~ubuntu-dev/ubuntu/lucid/dovecot/lucid-201002110912

« back to all changes in this revision

Viewing changes to src/lib-index/mail-index-modseq.c

  • Committer: Bazaar Package Importer
  • Author(s): CHuck Short, Chuck Short
  • Date: 2009-11-06 00:47:29 UTC
  • mfrom: (4.1.9 squeeze)
  • Revision ID: james.westby@ubuntu.com-20091106004729-i39n7v9e7d4h51f6
Tags: 1:1.2.6-1ubuntu1
* Merge from debian testing, remaining changes:
  Add new binary pkg dovecot-postfix that integrates postfix and dovecot
  automatically: (LP: #164837)
  + debian/control:
    - add new binary with short description
    - set Architecture all for dovecot-postfix (LP: #329878)
  + debian/dovecot-postfix.postinst:
    - create initial certificate symlinks to snakeoil.
    - set up postfix with postconf to:
      - use Maildir/ as the default mailbox.
      - use dovecot as the sasl authentication server.
      - use dovecot LDA (deliver).
      - use tls for smtp{d} services.
    - fix certificates paths in postfix' main.cf
    - add reject_unauth_destination to postfix' recipient restrictions
    - add reject_unknown_sender_domain to postfix' sender restrictions
    - rename configuration name on remove, delete on purge
    - restart dovecot after linking certificates
    - handle use case when postfix is unconfigurated
   + debian/dovecot-postfix.dirs: create backup directory for postfix's configuration
   + restart postfix and dovecot.
   + debian/dovecot-postfix.postrm:
     - remove all dovecot related configuration from postfix.
     - restart postfix and dovecot.
   + debian/dovecot-common.init:
     - check if /etc/dovecot/dovecot-postfix.conf exists and use it
       as the configuration file if so.
   + debian/patches/warning-ubuntu-postfix.dpatch
     - add warning about dovecot-postfix.conf in dovecot default 
       configuration file
   + debian/patches/dovecot-postfix.conf.diff:
     - Ubuntu server custom changes to the default dovecot configuration for
       better interfation with postfix
     - enable sieve plugin
   + debian/patches/dovecot-postfix.conf.diff:
     + Ubuntu server custom changes to the default dovecot configuration for
       better integration with postfix:
       - enable imap, pop3, imaps, pop3s and managesieve by default.
       - enable dovecot LDA (deliver).
       - enable SASL auth socket in postfix private directory.
   + debian/rules:
     - copy, patch and install dovecot-postfix.conf in /etc/dovecot/.
     - build architecure independent packages too
   + Use Snakeoil SSL certificates by default.
     - debian/control: Depend on ssl-cert.
     - debian/patches/ssl-cert-snakeoil.dpatch: Change default SSL cert
       paths to snakeoil.
     - debian/dovecot-common.postinst: Relax grep for SSL_* a bit.
   + Add autopkgtest to debian/tests/*.
   + Fast TearDown: Update the lsb init header to not stop in level 6.
   + Add ufw integration:
     - Created debian/dovecot-common.ufw.profile.
     - debian/rules:
       + install profile
     - debian/control:
       + Suggest ufw
   + debian/{control,rules}: enable PIE hardening.
   + dovecot-imapd, dovecot-pop3: Replaces dovecot-common (<< 1:1.1). LP: #254721
   + debian/control:
     - Update Vcs-* headers.
   + debian/rules:
     - Create emtpy stamp.h.in files in dovecot-sieve/ and dovecot-managesieve/
       if they're not there since empty files are not included in the diff.gz 
       file.
   + Add SMTP-AUTH support for Outlook (login auth mechanism)
   + Dropped:
     - debian/patches/security-CVE-2009-3235: Applied upstream.
     - debian/patches/fix-pop3-assertion.dpatch: Applied upstream.
     - dovecot-sieve and dovecot-managesieve: Use the debian patches instead.

  [Chuck Short]
  - Updated dovecot-sieve to 0.1.13.
  - Updated dovecot-managesieve to 0.11.9.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (c) 2008-2009 Dovecot authors, see the included COPYING file */
 
2
 
 
3
#include "lib.h"
 
4
#include "array.h"
 
5
#include "mail-transaction-log-private.h"
 
6
#include "mail-index-private.h"
 
7
#include "mail-index-sync-private.h"
 
8
#include "mail-index-modseq.h"
 
9
 
 
10
ARRAY_DEFINE_TYPE(modseqs, uint64_t);
 
11
 
 
12
enum modseq_metadata_idx {
 
13
        /* must be in the same order as enum mail_flags */
 
14
        METADATA_MODSEQ_IDX_ANSWERED = 0,
 
15
        METADATA_MODSEQ_IDX_FLAGGED,
 
16
        METADATA_MODSEQ_IDX_DELETED,
 
17
        METADATA_MODSEQ_IDX_SEEN,
 
18
        METADATA_MODSEQ_IDX_DRAFT,
 
19
 
 
20
        METADATA_MODSEQ_IDX_KEYWORD_START
 
21
};
 
22
 
 
23
struct metadata_modseqs {
 
24
        ARRAY_TYPE(modseqs) modseqs;
 
25
};
 
26
 
 
27
struct mail_index_map_modseq {
 
28
        /* indexes use enum modseq_metadata_idx */
 
29
        ARRAY_DEFINE(metadata_modseqs, struct metadata_modseqs);
 
30
};
 
31
 
 
32
struct mail_index_modseq_sync {
 
33
        struct mail_index_sync_map_ctx *sync_map_ctx;
 
34
        struct mail_index_view *view;
 
35
        struct mail_transaction_log_view *log_view;
 
36
        struct mail_index_map_modseq *mmap;
 
37
 
 
38
        uint64_t highest_modseq;
 
39
};
 
40
 
 
41
void mail_index_modseq_init(struct mail_index *index)
 
42
{
 
43
        index->modseq_ext_id =
 
44
                mail_index_ext_register(index, MAIL_INDEX_MODSEQ_EXT_NAME,
 
45
                                        sizeof(struct mail_index_modseq_header),
 
46
                                        sizeof(uint64_t), sizeof(uint64_t));
 
47
}
 
48
 
 
49
static uint64_t mail_index_modseq_get_head(struct mail_index *index)
 
50
{
 
51
        return index->log->head == NULL ? 1 :
 
52
                I_MAX(index->log->head->sync_highest_modseq, 1);
 
53
}
 
54
 
 
55
void mail_index_modseq_enable(struct mail_index *index)
 
56
{
 
57
        struct mail_index_transaction *trans;
 
58
        struct mail_index_view *view;
 
59
        struct mail_index_modseq_header hdr;
 
60
        uint32_t ext_map_idx, log_seq;
 
61
        uoff_t log_offset;
 
62
 
 
63
        if (index->modseqs_enabled)
 
64
                return;
 
65
 
 
66
        if (!mail_index_map_get_ext_idx(index->map, index->modseq_ext_id,
 
67
                                        &ext_map_idx)) {
 
68
                /* modseqs not enabled to the index yet, add them. */
 
69
                view = mail_index_view_open(index);
 
70
                trans = mail_index_transaction_begin(view, 0);
 
71
 
 
72
                memset(&hdr, 0, sizeof(hdr));
 
73
                hdr.highest_modseq = mail_index_modseq_get_head(index);
 
74
                mail_index_update_header_ext(trans, index->modseq_ext_id,
 
75
                                             0, &hdr, sizeof(hdr));
 
76
 
 
77
                /* commit also refreshes the index, which syncs the modseqs */
 
78
                (void)mail_index_transaction_commit(&trans,
 
79
                                                    &log_seq, &log_offset);
 
80
                mail_index_view_close(&view);
 
81
 
 
82
                /* get the modseq extension to index map */
 
83
                if (!mail_index_map_get_ext_idx(index->map,
 
84
                                                index->modseq_ext_id,
 
85
                                                &ext_map_idx)) {
 
86
                        /* didn't work for some reason */
 
87
                        return;
 
88
                }
 
89
        }
 
90
        index->modseqs_enabled = TRUE;
 
91
}
 
92
 
 
93
const struct mail_index_modseq_header *
 
94
mail_index_map_get_modseq_header(struct mail_index_map *map)
 
95
{
 
96
        const struct mail_index_ext *ext;
 
97
        uint32_t idx;
 
98
 
 
99
        if (!mail_index_map_get_ext_idx(map, map->index->modseq_ext_id, &idx))
 
100
                return NULL;
 
101
 
 
102
        ext = array_idx(&map->extensions, idx);
 
103
        if (ext->hdr_size != sizeof(struct mail_index_modseq_header))
 
104
                return NULL;
 
105
 
 
106
        return CONST_PTR_OFFSET(map->hdr_base, ext->hdr_offset);
 
107
}
 
108
 
 
109
uint64_t mail_index_map_modseq_get_highest(struct mail_index_map *map)
 
110
{
 
111
        const struct mail_index_modseq_header *modseq_hdr;
 
112
 
 
113
        modseq_hdr = mail_index_map_get_modseq_header(map);
 
114
        if (modseq_hdr != NULL && modseq_hdr->highest_modseq != 0)
 
115
                return modseq_hdr->highest_modseq;
 
116
        else {
 
117
                /* fallback to returning the log head. if modseqs aren't
 
118
                   enabled, we return 0. */
 
119
                return map->index->log->head == NULL ? 0 :
 
120
                        map->index->log->head->sync_highest_modseq;
 
121
        }
 
122
}
 
123
 
 
124
uint64_t mail_index_modseq_get_highest(struct mail_index_view *view)
 
125
{
 
126
        return mail_index_map_modseq_get_highest(view->map);
 
127
}
 
128
 
 
129
static struct mail_index_map_modseq *
 
130
mail_index_map_modseq(struct mail_index_view *view)
 
131
{
 
132
        struct mail_index_map_modseq *mmap = view->map->rec_map->modseq;
 
133
        uint32_t ext_map_idx;
 
134
 
 
135
        if (mmap != NULL)
 
136
                return mmap;
 
137
 
 
138
        /* don't start tracking until we've seen modseq extension intro */
 
139
        if (!mail_index_map_get_ext_idx(view->map, view->index->modseq_ext_id,
 
140
                                        &ext_map_idx))
 
141
                return NULL;
 
142
 
 
143
        mmap = i_new(struct mail_index_map_modseq, 1);
 
144
        i_array_init(&mmap->metadata_modseqs,
 
145
                     METADATA_MODSEQ_IDX_KEYWORD_START +
 
146
                     array_count(&view->index->keywords));
 
147
        view->map->rec_map->modseq = mmap;
 
148
        return mmap;
 
149
}
 
150
 
 
151
uint64_t mail_index_modseq_lookup(struct mail_index_view *view, uint32_t seq)
 
152
{
 
153
        struct mail_index_map_modseq *mmap = mail_index_map_modseq(view);
 
154
        struct mail_index_map *map;
 
155
        const struct mail_index_ext *ext;
 
156
        const struct mail_index_record *rec;
 
157
        const uint64_t *modseqp;
 
158
        uint32_t ext_map_idx;
 
159
 
 
160
        if (mmap == NULL)
 
161
                return mail_index_modseq_get_head(view->index);
 
162
 
 
163
        rec = mail_index_lookup_full(view, seq, &map);
 
164
        if (!mail_index_map_get_ext_idx(map, view->index->modseq_ext_id,
 
165
                                        &ext_map_idx)) {
 
166
                /* not enabled yet */
 
167
                return mail_index_modseq_get_head(view->index);
 
168
        }
 
169
 
 
170
        ext = array_idx(&map->extensions, ext_map_idx);
 
171
        modseqp = CONST_PTR_OFFSET(rec, ext->record_offset);
 
172
        if (*modseqp == 0) {
 
173
                /* If we're here because we just enabled modseqs, we'll return
 
174
                   the same modseq (initial highestmodseq) for all messages.
 
175
                   The next sync will change these zeros to initial
 
176
                   highestmodseq or higher.
 
177
 
 
178
                   If we're here because a message got appended but modseq
 
179
                   wasn't set (older Dovecot?), we'll again use the current
 
180
                   highest modseq. This isn't exactly correct, but it gets
 
181
                   fixed after the next sync and this situation shouldn't
 
182
                   normally happen anyway. */
 
183
                return mail_index_modseq_get_highest(view);
 
184
        }
 
185
        return *modseqp;
 
186
}
 
187
 
 
188
static uint64_t
 
189
modseq_idx_lookup(struct mail_index_map_modseq *mmap,
 
190
                  unsigned int idx, uint32_t seq)
 
191
{
 
192
        const struct metadata_modseqs *metadata;
 
193
        const uint64_t *modseqs;
 
194
        unsigned int count;
 
195
 
 
196
        metadata = array_get(&mmap->metadata_modseqs, &count);
 
197
        if (idx >= count || !array_is_created(&metadata[idx].modseqs))
 
198
                return 0;
 
199
 
 
200
        modseqs = array_get(&metadata[idx].modseqs, &count);
 
201
        return seq > count ? 0 : modseqs[seq-1];
 
202
}
 
203
 
 
204
uint64_t mail_index_modseq_lookup_flags(struct mail_index_view *view,
 
205
                                        enum mail_flags flags_mask,
 
206
                                        uint32_t seq)
 
207
{
 
208
        struct mail_index_map_modseq *mmap = mail_index_map_modseq(view);
 
209
        unsigned int i;
 
210
        uint64_t modseq, highest_modseq = 0;
 
211
 
 
212
        if (mmap != NULL) {
 
213
                /* first try to find a specific match */
 
214
                for (i = 0; i < METADATA_MODSEQ_IDX_KEYWORD_START; i++) {
 
215
                        if ((flags_mask & (1 << i)) != 0) {
 
216
                                modseq = modseq_idx_lookup(mmap, i, seq);
 
217
                                if (highest_modseq < modseq)
 
218
                                        highest_modseq = modseq;
 
219
                        }
 
220
                }
 
221
        }
 
222
 
 
223
        if (highest_modseq == 0) {
 
224
                /* no specific matches, fallback to using the highest */
 
225
                highest_modseq = mail_index_modseq_lookup(view, seq);
 
226
        }
 
227
        return highest_modseq;
 
228
}
 
229
 
 
230
uint64_t mail_index_modseq_lookup_keywords(struct mail_index_view *view,
 
231
                                           const struct mail_keywords *keywords,
 
232
                                           uint32_t seq)
 
233
{
 
234
        struct mail_index_map_modseq *mmap = mail_index_map_modseq(view);
 
235
        unsigned int i, metadata_idx;
 
236
        uint64_t modseq, highest_modseq = 0;
 
237
 
 
238
        if (mmap != NULL) {
 
239
                /* first try to find a specific match */
 
240
                for (i = 0; i < keywords->count; i++) {
 
241
                        metadata_idx = METADATA_MODSEQ_IDX_KEYWORD_START +
 
242
                                keywords->idx[i];
 
243
 
 
244
                        modseq = modseq_idx_lookup(mmap, metadata_idx, seq);
 
245
                        if (highest_modseq < modseq)
 
246
                                highest_modseq = modseq;
 
247
                }
 
248
        }
 
249
 
 
250
        if (highest_modseq == 0) {
 
251
                /* no specific matches, fallback to using the highest */
 
252
                highest_modseq = mail_index_modseq_lookup(view, seq);
 
253
        }
 
254
        return highest_modseq;
 
255
}
 
256
 
 
257
static void
 
258
mail_index_modseq_update(struct mail_index_modseq_sync *ctx,
 
259
                         uint64_t modseq, bool nonzeros,
 
260
                         uint32_t seq1, uint32_t seq2)
 
261
{
 
262
        const struct mail_index_ext *ext;
 
263
        const struct mail_index_record *rec;
 
264
        uint32_t ext_map_idx;
 
265
        uint64_t *modseqp;
 
266
 
 
267
        if (!mail_index_map_get_ext_idx(ctx->view->map,
 
268
                                        ctx->view->index->modseq_ext_id,
 
269
                                        &ext_map_idx))
 
270
                return;
 
271
 
 
272
        if (modseq > ctx->highest_modseq)
 
273
                ctx->highest_modseq = modseq;
 
274
 
 
275
        ext = array_idx(&ctx->view->map->extensions, ext_map_idx);
 
276
        for (; seq1 <= seq2; seq1++) {
 
277
                rec = MAIL_INDEX_MAP_IDX(ctx->view->map, seq1-1);
 
278
                modseqp = PTR_OFFSET(rec, ext->record_offset);
 
279
                if (*modseqp == 0 || (nonzeros && *modseqp < modseq))
 
280
                        *modseqp = modseq;
 
281
        }
 
282
}
 
283
 
 
284
static bool
 
285
mail_index_modseq_update_highest(struct mail_index_modseq_sync *ctx,
 
286
                                 uint32_t seq1, uint32_t seq2)
 
287
{
 
288
        uint64_t modseq;
 
289
 
 
290
        if (ctx->mmap == NULL)
 
291
                return FALSE;
 
292
 
 
293
        modseq = mail_transaction_log_view_get_prev_modseq(ctx->log_view);
 
294
        mail_index_modseq_update(ctx, modseq, TRUE, seq1, seq2);
 
295
        return TRUE;
 
296
}
 
297
 
 
298
static void
 
299
mail_index_modseq_update_old_rec(struct mail_index_modseq_sync *ctx,
 
300
                                 const struct mail_transaction_header *thdr,
 
301
                                 const void *tdata)
 
302
{
 
303
        ARRAY_TYPE(seq_range) uids = ARRAY_INIT;
 
304
        const struct seq_range *rec;
 
305
        buffer_t *uid_buf;
 
306
        unsigned int i, count;
 
307
        uint32_t seq1, seq2;
 
308
 
 
309
        switch (thdr->type & MAIL_TRANSACTION_TYPE_MASK) {
 
310
        case MAIL_TRANSACTION_APPEND: {
 
311
                const struct mail_index_record *appends = tdata;
 
312
 
 
313
                count = thdr->size / sizeof(*appends);
 
314
                for (i = 0; i < count; i++) {
 
315
                        if (mail_index_lookup_seq(ctx->view,
 
316
                                                  appends[i].uid, &seq1)) {
 
317
                                mail_index_modseq_update_highest(ctx, seq1,
 
318
                                                                 seq1);
 
319
                        }
 
320
                }
 
321
                return;
 
322
        }
 
323
        case MAIL_TRANSACTION_FLAG_UPDATE: {
 
324
                uid_buf = buffer_create_const_data(pool_datastack_create(),
 
325
                                                   tdata, thdr->size);
 
326
                array_create_from_buffer(&uids, uid_buf,
 
327
                        sizeof(struct mail_transaction_flag_update));
 
328
                break;
 
329
        }
 
330
        case MAIL_TRANSACTION_KEYWORD_UPDATE: {
 
331
                const struct mail_transaction_keyword_update *rec = tdata;
 
332
                unsigned int seqset_offset;
 
333
 
 
334
                seqset_offset = sizeof(*rec) + rec->name_size;
 
335
                if ((seqset_offset % 4) != 0)
 
336
                        seqset_offset += 4 - (seqset_offset % 4);
 
337
 
 
338
                uid_buf = buffer_create_const_data(pool_datastack_create(),
 
339
                                        CONST_PTR_OFFSET(tdata, seqset_offset),
 
340
                                        thdr->size - seqset_offset);
 
341
                array_create_from_buffer(&uids, uid_buf, sizeof(uint32_t)*2);
 
342
                break;
 
343
        }
 
344
        case MAIL_TRANSACTION_KEYWORD_RESET:
 
345
                uid_buf = buffer_create_const_data(pool_datastack_create(),
 
346
                                                   tdata, thdr->size);
 
347
                array_create_from_buffer(&uids, uid_buf,
 
348
                        sizeof(struct mail_transaction_keyword_reset));
 
349
                break;
 
350
        default:
 
351
                return;
 
352
        }
 
353
 
 
354
        /* update modseqs */
 
355
        count = array_count(&uids);
 
356
        for (i = 0; i < count; i++) {
 
357
                rec = array_idx(&uids, i);
 
358
                if (mail_index_lookup_seq_range(ctx->view, rec->seq1, rec->seq2,
 
359
                                                &seq1, &seq2))
 
360
                        mail_index_modseq_update_highest(ctx, seq1, seq2);
 
361
        }
 
362
}
 
363
 
 
364
static void mail_index_modseq_sync_init(struct mail_index_modseq_sync *ctx)
 
365
{
 
366
        struct mail_index_map *map = ctx->view->map;
 
367
        const struct mail_index_ext *ext;
 
368
        const struct mail_index_modseq_header *hdr;
 
369
        const struct mail_transaction_header *thdr;
 
370
        const void *tdata;
 
371
        uint32_t ext_map_idx;
 
372
        uint32_t end_seq;
 
373
        uoff_t end_offset;
 
374
        uint64_t cur_modseq;
 
375
        bool reset;
 
376
        int ret;
 
377
 
 
378
        if (!mail_index_map_get_ext_idx(map, ctx->view->index->modseq_ext_id,
 
379
                                        &ext_map_idx))
 
380
                i_unreached();
 
381
        ext = array_idx(&map->extensions, ext_map_idx);
 
382
 
 
383
        /* get the current highest_modseq. don't change any modseq below it. */
 
384
        hdr = CONST_PTR_OFFSET(map->hdr_base, ext->hdr_offset);
 
385
        ctx->highest_modseq = hdr->highest_modseq;
 
386
 
 
387
        /* Scan logs for updates between ext_hdr.log_* .. view position.
 
388
           There are two reasons why there could be any:
 
389
 
 
390
           1) We just enabled modseqs and we're filling the initial values.
 
391
           2) A non-modseq-aware Dovecot version added new messages and wrote
 
392
              dovecot.index file. */
 
393
        mail_transaction_log_view_get_prev_pos(ctx->view->log_view,
 
394
                                               &end_seq, &end_offset);
 
395
        if (end_seq <= hdr->log_seq ||
 
396
            (end_seq == hdr->log_seq && end_offset <= hdr->log_offset)) {
 
397
                /* modseqs are up to date */
 
398
                return;
 
399
        }
 
400
 
 
401
        ctx->log_view = mail_transaction_log_view_open(ctx->view->index->log);
 
402
        ret = mail_transaction_log_view_set(ctx->log_view,
 
403
                                            I_MAX(1, hdr->log_seq),
 
404
                                            hdr->log_offset,
 
405
                                            end_seq, end_offset, &reset);
 
406
        if (ret == 0) {
 
407
                /* missing files - try with only the last file */
 
408
                ret = mail_transaction_log_view_set(ctx->log_view, end_seq, 0,
 
409
                                                    end_seq, end_offset,
 
410
                                                    &reset);
 
411
                /* since we don't know if we skipped some changes, set all
 
412
                   modseqs to beginning of the latest file. */
 
413
                cur_modseq = mail_transaction_log_view_get_prev_modseq(
 
414
                                                                ctx->log_view);
 
415
                if (cur_modseq < hdr->highest_modseq) {
 
416
                        /* should happen only when setting initial modseqs.
 
417
                           we may already have returned highest_modseq as
 
418
                           some messages' modseq value. don't shrink it. */
 
419
                        cur_modseq = hdr->highest_modseq;
 
420
                }
 
421
                mail_index_modseq_update(ctx, cur_modseq, TRUE, 1,
 
422
                                         map->hdr.messages_count);
 
423
        } else {
 
424
                /* we have all the logs. replace zero modseqs with the current
 
425
                   highest modseq (we may have already returned it for them). */
 
426
                mail_index_modseq_update(ctx, hdr->highest_modseq, FALSE, 1,
 
427
                                         map->hdr.messages_count);
 
428
        }
 
429
        if (ret > 0) {
 
430
                while (mail_transaction_log_view_next(ctx->log_view,
 
431
                                                      &thdr, &tdata) > 0) {
 
432
                        T_BEGIN {
 
433
                                mail_index_modseq_update_old_rec(ctx, thdr,
 
434
                                                                 tdata);
 
435
                        } T_END;
 
436
                }
 
437
        }
 
438
        mail_index_sync_write_seq_update(ctx->sync_map_ctx, 1,
 
439
                                         map->hdr.messages_count);
 
440
        mail_transaction_log_view_close(&ctx->log_view);
 
441
}
 
442
 
 
443
struct mail_index_modseq_sync *
 
444
mail_index_modseq_sync_begin(struct mail_index_sync_map_ctx *sync_map_ctx)
 
445
{
 
446
        struct mail_index_modseq_sync *ctx;
 
447
 
 
448
        ctx = i_new(struct mail_index_modseq_sync, 1);
 
449
        ctx->sync_map_ctx = sync_map_ctx;
 
450
        ctx->view = sync_map_ctx->view;
 
451
        ctx->mmap = mail_index_map_modseq(ctx->view);
 
452
        if (ctx->mmap != NULL) {
 
453
                mail_index_modseq_sync_init(ctx);
 
454
                ctx->log_view = ctx->view->log_view;
 
455
        }
 
456
        return ctx;
 
457
}
 
458
 
 
459
static void mail_index_modseq_update_header(struct mail_index_modseq_sync *ctx)
 
460
{
 
461
        struct mail_index_map *map = ctx->view->map;
 
462
        const struct mail_index_ext *ext;
 
463
        const struct mail_index_modseq_header *old_modseq_hdr;
 
464
        struct mail_index_modseq_header new_modseq_hdr;
 
465
        uint32_t ext_map_idx, log_seq;
 
466
        uoff_t log_offset;
 
467
 
 
468
        if (!mail_index_map_get_ext_idx(map, ctx->view->index->modseq_ext_id,
 
469
                                        &ext_map_idx))
 
470
                return;
 
471
 
 
472
        mail_transaction_log_view_get_prev_pos(ctx->view->log_view,
 
473
                                               &log_seq, &log_offset);
 
474
 
 
475
        ext = array_idx(&map->extensions, ext_map_idx);
 
476
        old_modseq_hdr = CONST_PTR_OFFSET(map->hdr_base, ext->hdr_offset);
 
477
 
 
478
        if (old_modseq_hdr->log_seq < log_seq ||
 
479
            (old_modseq_hdr->log_seq == log_seq &&
 
480
             old_modseq_hdr->log_offset < log_offset)) {
 
481
                new_modseq_hdr.highest_modseq = ctx->highest_modseq;
 
482
                new_modseq_hdr.log_seq = log_seq;
 
483
                new_modseq_hdr.log_offset = log_offset;
 
484
 
 
485
                buffer_write(map->hdr_copy_buf, ext->hdr_offset,
 
486
                             &new_modseq_hdr, sizeof(new_modseq_hdr));
 
487
                map->hdr_base = map->hdr_copy_buf->data;
 
488
                map->write_ext_header = TRUE;
 
489
        }
 
490
}
 
491
 
 
492
void mail_index_modseq_sync_end(struct mail_index_modseq_sync **_ctx)
 
493
{
 
494
        struct mail_index_modseq_sync *ctx = *_ctx;
 
495
 
 
496
        *_ctx = NULL;
 
497
        if (ctx->mmap != NULL) {
 
498
                i_assert(ctx->mmap == ctx->view->map->rec_map->modseq);
 
499
                mail_index_modseq_update_header(ctx);
 
500
        }
 
501
        i_free(ctx);
 
502
}
 
503
 
 
504
void mail_index_modseq_sync_map_replaced(struct mail_index_modseq_sync *ctx)
 
505
{
 
506
        ctx->mmap = mail_index_map_modseq(ctx->view);
 
507
}
 
508
 
 
509
void mail_index_modseq_hdr_update(struct mail_index_modseq_sync *ctx)
 
510
{
 
511
        if (ctx->mmap == NULL) {
 
512
                ctx->mmap = mail_index_map_modseq(ctx->view);
 
513
                i_assert(ctx->mmap != NULL);
 
514
                mail_index_modseq_sync_init(ctx);
 
515
                ctx->log_view = ctx->view->log_view;
 
516
        }
 
517
}
 
518
 
 
519
void mail_index_modseq_append(struct mail_index_modseq_sync *ctx, uint32_t seq)
 
520
{
 
521
        mail_index_modseq_update_highest(ctx, seq, seq);
 
522
}
 
523
 
 
524
void mail_index_modseq_expunge(struct mail_index_modseq_sync *ctx,
 
525
                               uint32_t seq1, uint32_t seq2)
 
526
{
 
527
        struct metadata_modseqs *metadata;
 
528
        unsigned int i, count;
 
529
        uint64_t modseq;
 
530
 
 
531
        if (ctx->mmap == NULL)
 
532
                return;
 
533
 
 
534
        seq1--;
 
535
        metadata = array_get_modifiable(&ctx->mmap->metadata_modseqs, &count);
 
536
        for (i = 0; i < count; i++) {
 
537
                if (array_is_created(&metadata->modseqs))
 
538
                        array_delete(&metadata->modseqs, seq1, seq2-seq1);
 
539
        }
 
540
 
 
541
        modseq = mail_transaction_log_view_get_prev_modseq(ctx->log_view);
 
542
        if (ctx->highest_modseq < modseq)
 
543
                ctx->highest_modseq = modseq;
 
544
}
 
545
 
 
546
static void
 
547
modseqs_update(ARRAY_TYPE(modseqs) *array, uint32_t seq1, uint32_t seq2,
 
548
               uint64_t value)
 
549
{
 
550
        for (; seq1 <= seq2; seq1++)
 
551
                array_idx_set(array, seq1-1, &value);
 
552
}
 
553
 
 
554
static void
 
555
modseqs_idx_update(struct mail_index_modseq_sync *ctx, unsigned int idx,
 
556
                   uint32_t seq1, uint32_t seq2)
 
557
{
 
558
        struct metadata_modseqs *metadata;
 
559
 
 
560
        if (!ctx->view->index->modseqs_enabled) {
 
561
                /* we want to keep permanent modseqs updated, but don't bother
 
562
                   updating in-memory per-flag updates */
 
563
                return;
 
564
        }
 
565
 
 
566
        metadata = array_idx_modifiable(&ctx->mmap->metadata_modseqs, idx);
 
567
        if (!array_is_created(&metadata->modseqs))
 
568
                i_array_init(&metadata->modseqs, seq2 + 16);
 
569
        modseqs_update(&metadata->modseqs, seq1, seq2, ctx->highest_modseq);
 
570
}
 
571
 
 
572
void mail_index_modseq_update_flags(struct mail_index_modseq_sync *ctx,
 
573
                                    enum mail_flags flags_mask,
 
574
                                    uint32_t seq1, uint32_t seq2)
 
575
{
 
576
        unsigned int i;
 
577
 
 
578
        if (!mail_index_modseq_update_highest(ctx, seq1, seq2))
 
579
                return;
 
580
 
 
581
        for (i = 0; i < METADATA_MODSEQ_IDX_KEYWORD_START; i++) {
 
582
                if ((flags_mask & (1 << i)) != 0)
 
583
                        modseqs_idx_update(ctx, i, seq1, seq2);
 
584
        }
 
585
}
 
586
 
 
587
void mail_index_modseq_update_keyword(struct mail_index_modseq_sync *ctx,
 
588
                                      unsigned int keyword_idx,
 
589
                                      uint32_t seq1, uint32_t seq2)
 
590
{
 
591
        if (!mail_index_modseq_update_highest(ctx, seq1, seq2))
 
592
                return;
 
593
 
 
594
        modseqs_idx_update(ctx, METADATA_MODSEQ_IDX_KEYWORD_START + keyword_idx,
 
595
                           seq1, seq2);
 
596
}
 
597
 
 
598
void mail_index_modseq_reset_keywords(struct mail_index_modseq_sync *ctx,
 
599
                                      uint32_t seq1, uint32_t seq2)
 
600
{
 
601
        unsigned int i, count;
 
602
 
 
603
        if (!mail_index_modseq_update_highest(ctx, seq1, seq2))
 
604
                return;
 
605
 
 
606
        count = array_count(&ctx->mmap->metadata_modseqs);
 
607
        for (i = METADATA_MODSEQ_IDX_KEYWORD_START; i < count; i++)
 
608
                modseqs_idx_update(ctx, i, seq1, seq2);
 
609
}
 
610
 
 
611
struct mail_index_map_modseq *
 
612
mail_index_map_modseq_clone(const struct mail_index_map_modseq *mmap)
 
613
{
 
614
        struct mail_index_map_modseq *new_mmap;
 
615
        const struct metadata_modseqs *src_metadata;
 
616
        struct metadata_modseqs *dest_metadata;
 
617
        unsigned int i, count;
 
618
 
 
619
        src_metadata = array_get(&mmap->metadata_modseqs, &count);
 
620
 
 
621
        new_mmap = i_new(struct mail_index_map_modseq, 1);
 
622
        i_array_init(&new_mmap->metadata_modseqs, count + 16);
 
623
 
 
624
        for (i = 0; i < count; i++) {
 
625
                dest_metadata = array_append_space(&new_mmap->metadata_modseqs);
 
626
                if (array_is_created(&src_metadata[i].modseqs)) {
 
627
                        i_array_init(&dest_metadata->modseqs,
 
628
                                     array_count(&src_metadata[i].modseqs));
 
629
                        array_append_array(&dest_metadata->modseqs,
 
630
                                           &src_metadata[i].modseqs);
 
631
                }
 
632
        }
 
633
        return new_mmap;
 
634
}
 
635
 
 
636
void mail_index_map_modseq_free(struct mail_index_map_modseq **_mmap)
 
637
{
 
638
        struct mail_index_map_modseq *mmap = *_mmap;
 
639
        struct metadata_modseqs *metadata;
 
640
        unsigned int i, count;
 
641
 
 
642
        *_mmap = NULL;
 
643
 
 
644
        metadata = array_get_modifiable(&mmap->metadata_modseqs, &count);
 
645
        for (i = 0; i < count; i++) {
 
646
                if (array_is_created(&metadata[i].modseqs))
 
647
                        array_free(&metadata[i].modseqs);
 
648
        }
 
649
        array_free(&mmap->metadata_modseqs);
 
650
        i_free(mmap);
 
651
}
 
652
 
 
653
bool mail_index_modseq_get_next_log_offset(struct mail_index_view *view,
 
654
                                           uint64_t modseq, uint32_t *log_seq_r,
 
655
                                           uoff_t *log_offset_r)
 
656
{
 
657
        struct mail_transaction_log_file *file, *prev_file = NULL;
 
658
 
 
659
        for (file = view->index->log->files; file != NULL; file = file->next) {
 
660
                if (modseq < file->hdr.initial_modseq)
 
661
                        break;
 
662
                prev_file = file;
 
663
        }
 
664
 
 
665
        if (prev_file == NULL) {
 
666
                /* the log file has been deleted already */
 
667
                return FALSE;
 
668
        }
 
669
 
 
670
        *log_seq_r = prev_file->hdr.file_seq;
 
671
        return mail_transaction_log_file_get_modseq_next_offset(
 
672
                                        prev_file, modseq, log_offset_r) == 0;
 
673
}