~ubuntu-branches/ubuntu/trusty/dovecot/trusty-updates

« back to all changes in this revision

Viewing changes to src/doveadm/dsync/dsync-transaction-log-scan.c

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-01-08 09:35:49 UTC
  • mfrom: (1.15.3) (96.1.1 trusty-proposed)
  • Revision ID: package-import@ubuntu.com-20140108093549-814nkqdcxfbvgktg
Tags: 1:2.2.9-1ubuntu1
* Merge from Debian unstable, remaining changes:
  + Add mail-stack-delivery package:
    - Update d/rules
    - d/control: convert existing dovecot-postfix package to a dummy
      package and add new mail-stack-delivery package.
    - Update maintainer scripts.
    - Rename d/dovecot-postfix.* to debian/mail-stack-delivery.*
    - d/mail-stack-delivery.preinst: Move previously installed backups and
      config files to a new package namespace.
    - d/mail-stack-delivery.prerm: Added to handle downgrades.
  + Use Snakeoil SSL certificates by default:
    - d/control: Depend on ssl-cert.
    - d/dovecot-core.postinst: Relax grep for SSL_* a bit.
  + Add autopkgtest to debian/tests/*.
  + Add ufw integration:
    - d/dovecot-core.ufw.profile: new ufw profile.
    - d/rules: install profile in dovecot-core.
    - d/control: dovecot-core - suggest ufw.
  + d/dovecot-core.dirs: Added usr/share/doc/dovecot-core
  + Add apport hook:
    - d/rules, d/source_dovecot.py
  + Add upstart job:
    - d/rules, d/dovecot-core.dovecot.upstart, d/control,
      d/dovecot-core.dirs, dovecot-imapd.{postrm, postinst, prerm},
      d/dovecot-pop3d.{postinst, postrm, prerm}.
      d/mail-stack-deliver.postinst: Convert init script to upstart.
  + Use the autotools-dev dh addon to update config.guess/config.sub for
    arm64.
* Dropped changes, included in Debian:
  - Update Dovecot name to reflect distribution in login greeting.
  - Update Drac plugin for >= 2.0.0 support.
* d/control: Drop dovecot-postfix package as its no longer required.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (c) 2013 Dovecot authors, see the included COPYING file */
 
2
 
 
3
#include "lib.h"
 
4
#include "hash.h"
 
5
#include "mail-index-modseq.h"
 
6
#include "mail-storage-private.h"
 
7
#include "dsync-mail.h"
 
8
#include "dsync-mailbox.h"
 
9
#include "dsync-transaction-log-scan.h"
 
10
 
 
11
struct dsync_transaction_log_scan {
 
12
        pool_t pool;
 
13
        HASH_TABLE_TYPE(dsync_uid_mail_change) changes;
 
14
        HASH_TABLE_TYPE(dsync_attr_change) attr_changes;
 
15
        struct mail_index_view *view;
 
16
        uint32_t highest_wanted_uid;
 
17
 
 
18
        uint32_t last_log_seq;
 
19
        uoff_t last_log_offset;
 
20
 
 
21
        bool returned_all_changes;
 
22
};
 
23
 
 
24
static bool ATTR_NOWARN_UNUSED_RESULT
 
25
export_change_get(struct dsync_transaction_log_scan *ctx, uint32_t uid,
 
26
                  enum dsync_mail_change_type type,
 
27
                  struct dsync_mail_change **change_r)
 
28
{
 
29
        struct dsync_mail_change *change;
 
30
        const char *orig_guid;
 
31
 
 
32
        i_assert(uid > 0);
 
33
        i_assert(type != DSYNC_MAIL_CHANGE_TYPE_SAVE);
 
34
 
 
35
        *change_r = NULL;
 
36
 
 
37
        if (uid > ctx->highest_wanted_uid)
 
38
                return FALSE;
 
39
 
 
40
        change = hash_table_lookup(ctx->changes, POINTER_CAST(uid));
 
41
        if (change == NULL) {
 
42
                /* first change for this UID */
 
43
                change = p_new(ctx->pool, struct dsync_mail_change, 1);
 
44
                change->uid = uid;
 
45
                change->type = type;
 
46
                hash_table_insert(ctx->changes, POINTER_CAST(uid), change);
 
47
        } else if (type == DSYNC_MAIL_CHANGE_TYPE_EXPUNGE) {
 
48
                /* expunge overrides flag changes */
 
49
                orig_guid = change->guid;
 
50
                memset(change, 0, sizeof(*change));
 
51
                change->type = type;
 
52
                change->uid = uid;
 
53
                change->guid = orig_guid;
 
54
        } else if (change->type == DSYNC_MAIL_CHANGE_TYPE_EXPUNGE) {
 
55
                /* already expunged, this change doesn't matter */
 
56
                return FALSE;
 
57
        } else {
 
58
                /* another flag update */
 
59
        }
 
60
        *change_r = change;
 
61
        return TRUE;
 
62
}
 
63
 
 
64
static void
 
65
log_add_expunge(struct dsync_transaction_log_scan *ctx, const void *data,
 
66
                const struct mail_transaction_header *hdr)
 
67
{
 
68
        const struct mail_transaction_expunge *rec = data, *end;
 
69
        struct dsync_mail_change *change;
 
70
        uint32_t uid;
 
71
 
 
72
        if ((hdr->type & MAIL_TRANSACTION_EXTERNAL) == 0) {
 
73
                /* this is simply a request for expunge */
 
74
                return;
 
75
        }
 
76
        end = CONST_PTR_OFFSET(data, hdr->size);
 
77
        for (; rec != end; rec++) {
 
78
                for (uid = rec->uid1; uid <= rec->uid2; uid++) {
 
79
                        export_change_get(ctx, uid,
 
80
                                          DSYNC_MAIL_CHANGE_TYPE_EXPUNGE,
 
81
                                          &change);
 
82
                }
 
83
        }
 
84
}
 
85
 
 
86
static bool
 
87
log_add_expunge_uid(struct dsync_transaction_log_scan *ctx, const void *data,
 
88
                    const struct mail_transaction_header *hdr, uint32_t uid)
 
89
{
 
90
        const struct mail_transaction_expunge *rec = data, *end;
 
91
        struct dsync_mail_change *change;
 
92
 
 
93
        if ((hdr->type & MAIL_TRANSACTION_EXTERNAL) == 0) {
 
94
                /* this is simply a request for expunge */
 
95
                return FALSE;
 
96
        }
 
97
        end = CONST_PTR_OFFSET(data, hdr->size);
 
98
        for (; rec != end; rec++) {
 
99
                if (uid >= rec->uid1 && uid <= rec->uid2) {
 
100
                        export_change_get(ctx, uid,
 
101
                                          DSYNC_MAIL_CHANGE_TYPE_EXPUNGE,
 
102
                                          &change);
 
103
                        return TRUE;
 
104
                }
 
105
        }
 
106
        return FALSE;
 
107
}
 
108
 
 
109
static void
 
110
log_add_expunge_guid(struct dsync_transaction_log_scan *ctx,
 
111
                     struct mail_index_view *view, const void *data,
 
112
                     const struct mail_transaction_header *hdr)
 
113
{
 
114
        const struct mail_transaction_expunge_guid *rec = data, *end;
 
115
        struct dsync_mail_change *change;
 
116
        uint32_t seq;
 
117
        bool external;
 
118
 
 
119
        external = (hdr->type & MAIL_TRANSACTION_EXTERNAL) != 0;
 
120
 
 
121
        end = CONST_PTR_OFFSET(data, hdr->size);
 
122
        for (; rec != end; rec++) {
 
123
                if (!external && mail_index_lookup_seq(view, rec->uid, &seq)) {
 
124
                        /* expunge request that hasn't been actually done yet.
 
125
                           we check non-external ones because they might have
 
126
                           the GUID while external ones don't. */
 
127
                        continue;
 
128
                }
 
129
                if (export_change_get(ctx, rec->uid,
 
130
                                      DSYNC_MAIL_CHANGE_TYPE_EXPUNGE,
 
131
                                      &change) &&
 
132
                    !guid_128_is_empty(rec->guid_128)) T_BEGIN {
 
133
                        change->guid = p_strdup(ctx->pool,
 
134
                                guid_128_to_string(rec->guid_128));
 
135
                } T_END;
 
136
        }
 
137
}
 
138
 
 
139
static bool
 
140
log_add_expunge_guid_uid(struct dsync_transaction_log_scan *ctx, const void *data,
 
141
                         const struct mail_transaction_header *hdr, uint32_t uid)
 
142
{
 
143
        const struct mail_transaction_expunge_guid *rec = data, *end;
 
144
        struct dsync_mail_change *change;
 
145
 
 
146
        /* we're assuming UID is already known to be expunged */
 
147
        end = CONST_PTR_OFFSET(data, hdr->size);
 
148
        for (; rec != end; rec++) {
 
149
                if (rec->uid != uid)
 
150
                        continue;
 
151
 
 
152
                if (!export_change_get(ctx, rec->uid,
 
153
                                       DSYNC_MAIL_CHANGE_TYPE_EXPUNGE,
 
154
                                       &change))
 
155
                        i_unreached();
 
156
                if (!guid_128_is_empty(rec->guid_128)) T_BEGIN {
 
157
                        change->guid = p_strdup(ctx->pool,
 
158
                                                guid_128_to_string(rec->guid_128));
 
159
                } T_END;
 
160
                return TRUE;
 
161
        }
 
162
        return FALSE;
 
163
}
 
164
 
 
165
static void
 
166
log_add_flag_update(struct dsync_transaction_log_scan *ctx, const void *data,
 
167
                    const struct mail_transaction_header *hdr)
 
168
{
 
169
        const struct mail_transaction_flag_update *rec = data, *end;
 
170
        struct dsync_mail_change *change;
 
171
        uint32_t uid;
 
172
 
 
173
        end = CONST_PTR_OFFSET(data, hdr->size);
 
174
        for (; rec != end; rec++) {
 
175
                for (uid = rec->uid1; uid <= rec->uid2; uid++) {
 
176
                        if (export_change_get(ctx, uid,
 
177
                                        DSYNC_MAIL_CHANGE_TYPE_FLAG_CHANGE,
 
178
                                        &change)) {
 
179
                                change->add_flags |= rec->add_flags;
 
180
                                change->remove_flags &= ~rec->add_flags;
 
181
                                change->remove_flags |= rec->remove_flags;
 
182
                                change->add_flags &= ~rec->remove_flags;
 
183
                        }
 
184
                }
 
185
        }
 
186
}
 
187
 
 
188
static void
 
189
log_add_keyword_reset(struct dsync_transaction_log_scan *ctx, const void *data,
 
190
                      const struct mail_transaction_header *hdr)
 
191
{
 
192
        const struct mail_transaction_keyword_reset *rec = data, *end;
 
193
        struct dsync_mail_change *change;
 
194
        uint32_t uid;
 
195
 
 
196
        end = CONST_PTR_OFFSET(data, hdr->size);
 
197
        for (; rec != end; rec++) {
 
198
                for (uid = rec->uid1; uid <= rec->uid2; uid++) {
 
199
                        if (!export_change_get(ctx, uid,
 
200
                                        DSYNC_MAIL_CHANGE_TYPE_FLAG_CHANGE,
 
201
                                        &change))
 
202
                                continue;
 
203
 
 
204
                        change->keywords_reset = TRUE;
 
205
                        if (array_is_created(&change->keyword_changes))
 
206
                                array_clear(&change->keyword_changes);
 
207
                }
 
208
        }
 
209
}
 
210
 
 
211
static void
 
212
keywords_change_remove(struct dsync_mail_change *change, const char *name)
 
213
{
 
214
        const char *const *changes;
 
215
        unsigned int i, count;
 
216
 
 
217
        changes = array_get(&change->keyword_changes, &count);
 
218
        for (i = 0; i < count; i++) {
 
219
                if (strcmp(changes[i]+1, name) == 0) {
 
220
                        array_delete(&change->keyword_changes, i, 1);
 
221
                        break;
 
222
                }
 
223
        }
 
224
}
 
225
 
 
226
static void
 
227
log_add_keyword_update(struct dsync_transaction_log_scan *ctx, const void *data,
 
228
                       const struct mail_transaction_header *hdr)
 
229
{
 
230
        const struct mail_transaction_keyword_update *rec = data;
 
231
        struct dsync_mail_change *change;
 
232
        const char *kw_name, *change_str;
 
233
        const uint32_t *uids, *end;
 
234
        unsigned int uids_offset;
 
235
        uint32_t uid;
 
236
 
 
237
        uids_offset = sizeof(*rec) + rec->name_size;
 
238
        if ((uids_offset % 4) != 0)
 
239
                uids_offset += 4 - (uids_offset % 4);
 
240
 
 
241
        kw_name = t_strndup((const void *)(rec+1), rec->name_size);
 
242
        switch (rec->modify_type) {
 
243
        case MODIFY_ADD:
 
244
                change_str = p_strdup_printf(ctx->pool, "%c%s",
 
245
                                             KEYWORD_CHANGE_ADD, kw_name);
 
246
                break;
 
247
        case MODIFY_REMOVE:
 
248
                change_str = p_strdup_printf(ctx->pool, "%c%s",
 
249
                                             KEYWORD_CHANGE_REMOVE, kw_name);
 
250
                break;
 
251
        default:
 
252
                i_unreached();
 
253
        }
 
254
 
 
255
        uids = CONST_PTR_OFFSET(rec, uids_offset);
 
256
        end = CONST_PTR_OFFSET(rec, hdr->size);
 
257
 
 
258
        for (; uids < end; uids += 2) {
 
259
                for (uid = uids[0]; uid <= uids[1]; uid++) {
 
260
                        if (!export_change_get(ctx, uid,
 
261
                                        DSYNC_MAIL_CHANGE_TYPE_FLAG_CHANGE,
 
262
                                        &change))
 
263
                                continue;
 
264
                        if (!array_is_created(&change->keyword_changes)) {
 
265
                                p_array_init(&change->keyword_changes,
 
266
                                             ctx->pool, 4);
 
267
                        } else {
 
268
                                keywords_change_remove(change, kw_name);
 
269
                        }
 
270
                        array_append(&change->keyword_changes, &change_str, 1);
 
271
                }
 
272
        }
 
273
}
 
274
 
 
275
static void
 
276
log_add_modseq_update(struct dsync_transaction_log_scan *ctx, const void *data,
 
277
                      const struct mail_transaction_header *hdr, bool pvt_scan)
 
278
{
 
279
        const struct mail_transaction_modseq_update *rec = data, *end;
 
280
        struct dsync_mail_change *change;
 
281
        uint64_t modseq;
 
282
 
 
283
        /* update message's modseq, possibly by creating an empty flag change */
 
284
        end = CONST_PTR_OFFSET(rec, hdr->size);
 
285
        for (; rec != end; rec++) {
 
286
                if (rec->uid == 0) {
 
287
                        /* highestmodseq update */
 
288
                        continue;
 
289
                }
 
290
 
 
291
                if (!export_change_get(ctx, rec->uid,
 
292
                                       DSYNC_MAIL_CHANGE_TYPE_FLAG_CHANGE,
 
293
                                       &change))
 
294
                        continue;
 
295
 
 
296
                modseq = rec->modseq_low32 |
 
297
                        ((uint64_t)rec->modseq_high32 << 32);
 
298
                if (!pvt_scan) {
 
299
                        if (change->modseq < modseq)
 
300
                                change->modseq = modseq;
 
301
                } else {
 
302
                        if (change->pvt_modseq < modseq)
 
303
                                change->pvt_modseq = modseq;
 
304
                }
 
305
        }
 
306
}
 
307
 
 
308
static void
 
309
log_add_attribute_update_key(struct dsync_transaction_log_scan *ctx,
 
310
                             const char *attr_change, uint64_t modseq)
 
311
{
 
312
        struct dsync_mailbox_attribute lookup_attr, *attr;
 
313
 
 
314
        i_assert(strlen(attr_change) > 2); /* checked by lib-index */
 
315
 
 
316
        lookup_attr.type = attr_change[1] == 'p' ?
 
317
                MAIL_ATTRIBUTE_TYPE_PRIVATE : MAIL_ATTRIBUTE_TYPE_SHARED;
 
318
        lookup_attr.key = attr_change+2;
 
319
 
 
320
        attr = hash_table_lookup(ctx->attr_changes, &lookup_attr);
 
321
        if (attr == NULL) {
 
322
                attr = p_new(ctx->pool, struct dsync_mailbox_attribute, 1);
 
323
                attr->type = lookup_attr.type;
 
324
                attr->key = p_strdup(ctx->pool, lookup_attr.key);
 
325
                hash_table_insert(ctx->attr_changes, attr, attr);
 
326
        }
 
327
        attr->deleted = attr_change[0] == '-';
 
328
        attr->modseq = modseq;
 
329
}
 
330
 
 
331
static void
 
332
log_add_attribute_update(struct dsync_transaction_log_scan *ctx,
 
333
                         const void *data,
 
334
                         const struct mail_transaction_header *hdr,
 
335
                         uint64_t modseq)
 
336
{
 
337
        const char *attr_changes = data;
 
338
        unsigned int i;
 
339
 
 
340
        for (i = 0; i < hdr->size && attr_changes[i] != '\0'; ) {
 
341
                log_add_attribute_update_key(ctx, attr_changes+i, modseq);
 
342
                i += strlen(attr_changes+i) + 1;
 
343
        }
 
344
}
 
345
 
 
346
static int
 
347
dsync_log_set(struct dsync_transaction_log_scan *ctx,
 
348
              struct mail_index_view *view, bool pvt_scan,
 
349
              struct mail_transaction_log_view *log_view, uint64_t modseq)
 
350
{
 
351
        uint32_t log_seq, end_seq;
 
352
        uoff_t log_offset, end_offset;
 
353
        bool reset;
 
354
        int ret;
 
355
 
 
356
        end_seq = view->log_file_head_seq;
 
357
        end_offset = view->log_file_head_offset;
 
358
 
 
359
        if (modseq != 0 &&
 
360
            mail_index_modseq_get_next_log_offset(view, modseq,
 
361
                                                  &log_seq, &log_offset)) {
 
362
                /* scan the view only up to end of the current view.
 
363
                   if there are more changes, we don't care about them until
 
364
                   the next sync. the modseq may however already point to
 
365
                   beyond the current view's end (FIXME: why?) */
 
366
                if (log_seq > end_seq ||
 
367
                    (log_seq == end_seq && log_offset > end_offset)) {
 
368
                        end_seq = log_seq;
 
369
                        end_offset = log_offset;
 
370
                }
 
371
                ret = mail_transaction_log_view_set(log_view,
 
372
                                                    log_seq, log_offset,
 
373
                                                    end_seq, end_offset,
 
374
                                                    &reset);
 
375
                if (ret != 0)
 
376
                        return ret;
 
377
        }
 
378
 
 
379
        /* return everything we've got (until the end of the view) */
 
380
        if (!pvt_scan)
 
381
                ctx->returned_all_changes = TRUE;
 
382
        if (mail_transaction_log_view_set_all(log_view) < 0)
 
383
                return -1;
 
384
 
 
385
        mail_transaction_log_view_get_prev_pos(log_view, &log_seq, &log_offset);
 
386
        if (log_seq > end_seq ||
 
387
            (log_seq == end_seq && log_offset > end_offset)) {
 
388
                end_seq = log_seq;
 
389
                end_offset = log_offset;
 
390
        }
 
391
        ret = mail_transaction_log_view_set(log_view,
 
392
                                            log_seq, log_offset,
 
393
                                            end_seq, end_offset, &reset);
 
394
        if (ret == 0) {
 
395
                /* we shouldn't get here. _view_set_all() already
 
396
                   reserved all the log files, the _view_set() only
 
397
                   removed unwanted ones. */
 
398
                i_error("%s: Couldn't set transaction log view (seq %u..%u)",
 
399
                        view->index->filepath, log_seq, end_seq);
 
400
                ret = -1;
 
401
        }
 
402
        return ret < 0 ? -1 : 0;
 
403
}
 
404
 
 
405
static int
 
406
dsync_log_scan(struct dsync_transaction_log_scan *ctx,
 
407
               struct mail_index_view *view, uint64_t modseq, bool pvt_scan)
 
408
{
 
409
        struct mail_transaction_log_view *log_view;
 
410
        const struct mail_transaction_header *hdr;
 
411
        const void *data;
 
412
        uint32_t file_seq, max_seq;
 
413
        uoff_t file_offset, max_offset;
 
414
        uint64_t cur_modseq;
 
415
 
 
416
        log_view = mail_transaction_log_view_open(view->index->log);
 
417
        if (dsync_log_set(ctx, view, pvt_scan, log_view, modseq) < 0) {
 
418
                mail_transaction_log_view_close(&log_view);
 
419
                return -1;
 
420
        }
 
421
 
 
422
        /* read the log only up to current position in view */
 
423
        max_seq = view->log_file_expunge_seq;
 
424
        max_offset = view->log_file_expunge_offset;
 
425
 
 
426
        mail_transaction_log_view_get_prev_pos(log_view, &file_seq,
 
427
                                               &file_offset);
 
428
 
 
429
        while (mail_transaction_log_view_next(log_view, &hdr, &data) > 0) {
 
430
                mail_transaction_log_view_get_prev_pos(log_view, &file_seq,
 
431
                                                       &file_offset);
 
432
                if (file_offset >= max_offset && file_seq == max_seq)
 
433
                        break;
 
434
 
 
435
                if ((hdr->type & MAIL_TRANSACTION_SYNC) != 0) {
 
436
                        /* ignore changes done by dsync, unless we can get
 
437
                           expunged message's GUID from it */
 
438
                        if ((hdr->type & MAIL_TRANSACTION_TYPE_MASK) !=
 
439
                            MAIL_TRANSACTION_EXPUNGE_GUID)
 
440
                                continue;
 
441
                }
 
442
 
 
443
                switch (hdr->type & MAIL_TRANSACTION_TYPE_MASK) {
 
444
                case MAIL_TRANSACTION_EXPUNGE:
 
445
                        if (!pvt_scan)
 
446
                                log_add_expunge(ctx, data, hdr);
 
447
                        break;
 
448
                case MAIL_TRANSACTION_EXPUNGE_GUID:
 
449
                        if (!pvt_scan)
 
450
                                log_add_expunge_guid(ctx, view, data, hdr);
 
451
                        break;
 
452
                case MAIL_TRANSACTION_FLAG_UPDATE:
 
453
                        log_add_flag_update(ctx, data, hdr);
 
454
                        break;
 
455
                case MAIL_TRANSACTION_KEYWORD_RESET:
 
456
                        log_add_keyword_reset(ctx, data, hdr);
 
457
                        break;
 
458
                case MAIL_TRANSACTION_KEYWORD_UPDATE:
 
459
                        T_BEGIN {
 
460
                                log_add_keyword_update(ctx, data, hdr);
 
461
                        } T_END;
 
462
                        break;
 
463
                case MAIL_TRANSACTION_MODSEQ_UPDATE:
 
464
                        log_add_modseq_update(ctx, data, hdr, pvt_scan);
 
465
                        break;
 
466
                case MAIL_TRANSACTION_ATTRIBUTE_UPDATE:
 
467
                        cur_modseq = mail_transaction_log_view_get_prev_modseq(log_view);
 
468
                        log_add_attribute_update(ctx, data, hdr, cur_modseq);
 
469
                        break;
 
470
                }
 
471
        }
 
472
 
 
473
        if (!pvt_scan) {
 
474
                ctx->last_log_seq = file_seq;
 
475
                ctx->last_log_offset = file_offset;
 
476
        }
 
477
        mail_transaction_log_view_close(&log_view);
 
478
        return 0;
 
479
}
 
480
 
 
481
static int
 
482
dsync_mailbox_attribute_cmp(const struct dsync_mailbox_attribute *attr1,
 
483
                            const struct dsync_mailbox_attribute *attr2)
 
484
{
 
485
        if (attr1->type < attr2->type)
 
486
                return -1;
 
487
        if (attr1->type > attr2->type)
 
488
                return 1;
 
489
        return strcmp(attr1->key, attr2->key);
 
490
}
 
491
 
 
492
static unsigned int
 
493
dsync_mailbox_attribute_hash(const struct dsync_mailbox_attribute *attr)
 
494
{
 
495
        return str_hash(attr->key) ^ attr->type;
 
496
}
 
497
 
 
498
int dsync_transaction_log_scan_init(struct mail_index_view *view,
 
499
                                    struct mail_index_view *pvt_view,
 
500
                                    uint32_t highest_wanted_uid,
 
501
                                    uint64_t modseq, uint64_t pvt_modseq,
 
502
                                    struct dsync_transaction_log_scan **scan_r)
 
503
{
 
504
        struct dsync_transaction_log_scan *ctx;
 
505
        pool_t pool;
 
506
 
 
507
        pool = pool_alloconly_create(MEMPOOL_GROWING"dsync transaction log scan",
 
508
                                     10240);
 
509
        ctx = p_new(pool, struct dsync_transaction_log_scan, 1);
 
510
        ctx->pool = pool;
 
511
        hash_table_create_direct(&ctx->changes, pool, 0);
 
512
        hash_table_create(&ctx->attr_changes, pool, 0,
 
513
                          dsync_mailbox_attribute_hash,
 
514
                          dsync_mailbox_attribute_cmp);
 
515
        ctx->view = view;
 
516
        ctx->highest_wanted_uid = highest_wanted_uid;
 
517
 
 
518
        if (dsync_log_scan(ctx, view, modseq, FALSE) < 0)
 
519
                return -1;
 
520
        if (pvt_view != NULL) {
 
521
                if (dsync_log_scan(ctx, pvt_view, pvt_modseq, TRUE) < 0)
 
522
                        return -1;
 
523
        }
 
524
 
 
525
        *scan_r = ctx;
 
526
        return 0;
 
527
}
 
528
 
 
529
HASH_TABLE_TYPE(dsync_uid_mail_change)
 
530
dsync_transaction_log_scan_get_hash(struct dsync_transaction_log_scan *scan)
 
531
{
 
532
        return scan->changes;
 
533
}
 
534
 
 
535
HASH_TABLE_TYPE(dsync_attr_change)
 
536
dsync_transaction_log_scan_get_attr_hash(struct dsync_transaction_log_scan *scan)
 
537
{
 
538
        return scan->attr_changes;
 
539
}
 
540
 
 
541
bool
 
542
dsync_transaction_log_scan_has_all_changes(struct dsync_transaction_log_scan *scan)
 
543
{
 
544
        return scan->returned_all_changes;
 
545
}
 
546
 
 
547
struct dsync_mail_change *
 
548
dsync_transaction_log_scan_find_new_expunge(struct dsync_transaction_log_scan *scan,
 
549
                                            uint32_t uid)
 
550
{
 
551
        struct mail_transaction_log_view *log_view;
 
552
        const struct mail_transaction_header *hdr;
 
553
        const void *data;
 
554
        bool reset, found = FALSE;
 
555
 
 
556
        i_assert(uid > 0);
 
557
 
 
558
        if (scan->highest_wanted_uid < uid)
 
559
                scan->highest_wanted_uid = uid;
 
560
 
 
561
        log_view = mail_transaction_log_view_open(scan->view->index->log);
 
562
        if (mail_transaction_log_view_set(log_view,
 
563
                                          scan->last_log_seq,
 
564
                                          scan->last_log_offset,
 
565
                                          (uint32_t)-1, (uoff_t)-1,
 
566
                                          &reset) > 0) {
 
567
                while (!found &&
 
568
                       mail_transaction_log_view_next(log_view, &hdr, &data) > 0) {
 
569
                        switch (hdr->type & MAIL_TRANSACTION_TYPE_MASK) {
 
570
                        case MAIL_TRANSACTION_EXPUNGE:
 
571
                                if (log_add_expunge_uid(scan, data, hdr, uid))
 
572
                                        found = TRUE;
 
573
                                break;
 
574
                        case MAIL_TRANSACTION_EXPUNGE_GUID:
 
575
                                if (log_add_expunge_guid_uid(scan, data, hdr, uid))
 
576
                                        found = TRUE;
 
577
                                break;
 
578
                        }
 
579
                }
 
580
        }
 
581
        mail_transaction_log_view_close(&log_view);
 
582
 
 
583
        return !found ? NULL :
 
584
                hash_table_lookup(scan->changes, POINTER_CAST(uid));
 
585
}
 
586
 
 
587
void dsync_transaction_log_scan_deinit(struct dsync_transaction_log_scan **_scan)
 
588
{
 
589
        struct dsync_transaction_log_scan *scan = *_scan;
 
590
 
 
591
        *_scan = NULL;
 
592
 
 
593
        hash_table_destroy(&scan->changes);
 
594
        hash_table_destroy(&scan->attr_changes);
 
595
        pool_unref(&scan->pool);
 
596
}