Coverage Report

Created: 2026-08-31 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dovecot/src/lib-storage/index/index-sync-changes.c
Line
Count
Source
1
/* Copyright (c) Dovecot authors, see top-level COPYING file */
2
3
#include "lib.h"
4
#include "array.h"
5
#include "index-storage.h"
6
#include "index-sync-changes.h"
7
8
struct index_sync_changes_context {
9
  struct mail_index_sync_ctx *index_sync_ctx;
10
  struct mail_index_view *sync_view;
11
  struct mail_index_transaction *sync_trans;
12
13
  ARRAY(struct mail_index_sync_rec) syncs;
14
  struct mail_index_sync_rec sync_rec;
15
  bool dirty_flag_updates;
16
};
17
18
struct index_sync_changes_context *
19
index_sync_changes_init(struct mail_index_sync_ctx *index_sync_ctx,
20
      struct mail_index_view *sync_view,
21
      struct mail_index_transaction *sync_trans,
22
      bool dirty_flag_updates)
23
0
{
24
0
  struct index_sync_changes_context *ctx;
25
26
0
  ctx = i_new(struct index_sync_changes_context, 1);
27
0
  ctx->index_sync_ctx = index_sync_ctx;
28
0
  ctx->sync_view = sync_view;
29
0
  ctx->sync_trans = sync_trans;
30
0
  ctx->dirty_flag_updates = dirty_flag_updates;
31
0
  i_array_init(&ctx->syncs, 16);
32
0
  return ctx;
33
0
}
34
35
void index_sync_changes_deinit(struct index_sync_changes_context **_ctx)
36
0
{
37
0
  struct index_sync_changes_context *ctx = *_ctx;
38
39
0
  *_ctx = NULL;
40
0
  array_free(&ctx->syncs);
41
0
  i_free(ctx);
42
0
}
43
44
void index_sync_changes_reset(struct index_sync_changes_context *ctx)
45
0
{
46
0
  array_clear(&ctx->syncs);
47
0
  i_zero(&ctx->sync_rec);
48
0
}
49
50
void index_sync_changes_delete_to(struct index_sync_changes_context *ctx,
51
          uint32_t last_uid)
52
0
{
53
0
  struct mail_index_sync_rec *syncs;
54
0
  unsigned int src, dest, count;
55
56
0
  syncs = array_get_modifiable(&ctx->syncs, &count);
57
58
0
  for (src = dest = 0; src < count; src++) {
59
0
    i_assert(last_uid >= syncs[src].uid1);
60
0
    if (last_uid <= syncs[src].uid2) {
61
      /* keep it */
62
0
      if (src != dest)
63
0
        syncs[dest] = syncs[src];
64
0
      dest++;
65
0
    }
66
0
  }
67
68
0
  array_delete(&ctx->syncs, dest, count - dest);
69
0
}
70
71
static bool
72
index_sync_changes_have_expunges(struct index_sync_changes_context *ctx,
73
         unsigned int count,
74
         guid_128_t expunged_guid_128_r)
75
0
{
76
0
  const struct mail_index_sync_rec *syncs;
77
0
  unsigned int i;
78
79
0
  syncs = array_front(&ctx->syncs);
80
0
  for (i = 0; i < count; i++) {
81
0
    if (syncs[i].type == MAIL_INDEX_SYNC_TYPE_EXPUNGE) {
82
0
      memcpy(expunged_guid_128_r, syncs[i].guid_128,
83
0
             GUID_128_SIZE);
84
0
      return TRUE;
85
0
    }
86
0
  }
87
0
  return FALSE;
88
0
}
89
90
void index_sync_changes_read(struct index_sync_changes_context *ctx,
91
           uint32_t uid, bool *sync_expunge_r,
92
           guid_128_t expunged_guid_128_r)
93
0
{
94
0
  struct mail_index_sync_rec *sync_rec = &ctx->sync_rec;
95
0
  uint32_t seq1, seq2;
96
0
  unsigned int orig_count;
97
98
0
  *sync_expunge_r = FALSE;
99
100
0
  index_sync_changes_delete_to(ctx, uid);
101
0
  orig_count = array_count(&ctx->syncs);
102
103
0
  while (uid >= sync_rec->uid1) {
104
0
    if (uid <= sync_rec->uid2) {
105
0
      array_push_back(&ctx->syncs, sync_rec);
106
107
0
      if (sync_rec->type == MAIL_INDEX_SYNC_TYPE_EXPUNGE) {
108
0
        *sync_expunge_r = TRUE;
109
0
        memcpy(expunged_guid_128_r, sync_rec->guid_128,
110
0
               GUID_128_SIZE);
111
0
      }
112
0
    }
113
114
0
    if (!mail_index_sync_next(ctx->index_sync_ctx, sync_rec)) {
115
0
      i_zero(sync_rec);
116
0
      break;
117
0
    }
118
119
0
    switch (sync_rec->type) {
120
0
    case MAIL_INDEX_SYNC_TYPE_EXPUNGE:
121
0
      break;
122
0
    case MAIL_INDEX_SYNC_TYPE_FLAGS:
123
0
    case MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD:
124
0
    case MAIL_INDEX_SYNC_TYPE_KEYWORD_REMOVE:
125
0
      if (!ctx->dirty_flag_updates)
126
0
        break;
127
128
      /* mark the changes as dirty */
129
0
      (void)mail_index_lookup_seq_range(ctx->sync_view,
130
0
                sync_rec->uid1,
131
0
                sync_rec->uid2,
132
0
                &seq1, &seq2);
133
0
      i_zero(sync_rec);
134
135
0
      if (seq1 == 0)
136
0
        break;
137
138
0
      mail_index_update_flags_range(ctx->sync_trans,
139
0
        seq1, seq2, MODIFY_ADD,
140
0
        (enum mail_flags)MAIL_INDEX_MAIL_FLAG_DIRTY);
141
0
      break;
142
0
    }
143
0
  }
144
145
0
  if (!*sync_expunge_r && orig_count > 0) {
146
0
    *sync_expunge_r =
147
0
      index_sync_changes_have_expunges(ctx, orig_count,
148
0
               expunged_guid_128_r);
149
0
  }
150
0
}
151
152
bool index_sync_changes_have(struct index_sync_changes_context *ctx)
153
0
{
154
0
  return array_count(&ctx->syncs) > 0;
155
0
}
156
157
uint32_t
158
index_sync_changes_get_next_uid(struct index_sync_changes_context *ctx)
159
0
{
160
0
  return ctx->sync_rec.uid1;
161
0
}
162
163
void index_sync_changes_apply(struct index_sync_changes_context *ctx,
164
            pool_t pool, uint8_t *flags,
165
            ARRAY_TYPE(keyword_indexes) *keywords,
166
            enum mail_index_sync_type *sync_type_r)
167
0
{
168
0
  const struct mail_index_sync_rec *syncs;
169
0
  unsigned int i, count;
170
0
  enum mail_index_sync_type sync_type = 0;
171
172
0
  syncs = array_get(&ctx->syncs, &count);
173
0
  for (i = 0; i < count; i++) {
174
0
    switch (syncs[i].type) {
175
0
    case MAIL_INDEX_SYNC_TYPE_FLAGS:
176
0
      mail_index_sync_flags_apply(&syncs[i], flags);
177
0
      sync_type |= MAIL_INDEX_SYNC_TYPE_FLAGS;
178
0
      break;
179
0
    case MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD:
180
0
    case MAIL_INDEX_SYNC_TYPE_KEYWORD_REMOVE:
181
0
      if (!array_is_created(keywords)) {
182
        /* no existing keywords */
183
0
        if (syncs[i].type !=
184
0
            MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD)
185
0
          break;
186
187
        /* adding, create the array */
188
0
        p_array_init(keywords, pool,
189
0
               I_MIN(10, count - i));
190
0
      }
191
0
      if (mail_index_sync_keywords_apply(&syncs[i], keywords))
192
0
        sync_type |= syncs[i].type;
193
0
      break;
194
0
    default:
195
0
      break;
196
0
    }
197
0
  }
198
199
0
  *sync_type_r = sync_type;
200
0
}