From 3af18e6185c2f1e7c0a97167d682ab1bb997d3fe Mon Sep 17 00:00:00 2001 From: Christian Wiese Date: Mon, 27 May 2013 18:59:56 +0200 Subject: [PATCH] dovecot: update upstream fixes for version 2.2.2 Note: The patch now includes all fixes and improvements for dovecot 2.2.2 from the dovecot 2.2 branch up to http://hg.dovecot.org/dovecot-2.2/rev/4883a8e1db13. --- .../dovecot-2.2.2-0000-upstream-fixes.patch | 1050 +++++++++++++++++ 1 file changed, 1050 insertions(+) diff --git a/mail/dovecot/dovecot-2.2.2-0000-upstream-fixes.patch b/mail/dovecot/dovecot-2.2.2-0000-upstream-fixes.patch index 075ce073b..a094c33c3 100644 --- a/mail/dovecot/dovecot-2.2.2-0000-upstream-fixes.patch +++ b/mail/dovecot/dovecot-2.2.2-0000-upstream-fixes.patch @@ -1141,3 +1141,1053 @@ index 69cb448..9c8d131 100644 -- 1.7.10.2 + +From 7dc8d11c6315150feac47878c9122dc5812a7c1c Mon Sep 17 00:00:00 2001 +From: Timo Sirainen +Date: Sun, 26 May 2013 19:04:00 +0300 +Subject: [PATCH] lib-index: mail_cache_lookup*() can now return fields + recently added with mail_cache_add() Previously it was + returning them if they had already been written to + dovecot.index.cache, but not if they were still in the + in-memory buffer. This avoids caching/parsing the same + field multiple times when messages aren't accessed in + ascending order (e.g. when sorting messages). + + +diff --git a/src/lib-index/mail-cache-lookup.c b/src/lib-index/mail-cache-lookup.c +index c48dfc0..39f3eb0 100644 +--- a/src/lib-index/mail-cache-lookup.c ++++ b/src/lib-index/mail-cache-lookup.c +@@ -163,31 +163,58 @@ void mail_cache_lookup_iter_init(struct mail_cache_view *view, uint32_t seq, + memset(&view->loop_track, 0, sizeof(view->loop_track)); + } + ++static bool ++mail_cache_lookup_iter_transaction(struct mail_cache_lookup_iterate_ctx *ctx) ++{ ++ ctx->rec = mail_cache_transaction_lookup_rec(ctx->view->transaction, ++ ctx->seq, ++ &ctx->trans_next_idx); ++ if (ctx->rec == NULL) ++ return FALSE; ++ ++ ctx->remap_counter = ctx->view->cache->remap_counter; ++ ctx->pos = sizeof(*ctx->rec); ++ ctx->rec_size = ctx->rec->size; ++ return TRUE; ++} ++ + static int + mail_cache_lookup_iter_next_record(struct mail_cache_lookup_iterate_ctx *ctx) + { + struct mail_cache_view *view = ctx->view; + +- if (ctx->stop) +- return ctx->failed ? -1 : 0; ++ if (ctx->failed) ++ return -1; + + if (ctx->rec != NULL) + ctx->offset = ctx->rec->prev_offset; + if (ctx->offset == 0) { + /* end of this record list. check newly appended data. */ +- if (ctx->appends_checked || +- view->trans_seq1 > ctx->seq || ++ if (view->trans_seq1 > ctx->seq || + view->trans_seq2 < ctx->seq || +- MAIL_CACHE_IS_UNUSABLE(view->cache) || ++ MAIL_CACHE_IS_UNUSABLE(view->cache)) ++ return 0; ++ /* check data still in memory */ ++ if (!ctx->memory_appends_checked) { ++ if (mail_cache_lookup_iter_transaction(ctx)) ++ return 1; ++ ctx->memory_appends_checked = TRUE; ++ } ++ ++ /* check data already written to cache file */ ++ if (ctx->disk_appends_checked || + mail_cache_lookup_offset(view->cache, view->trans_view, + ctx->seq, &ctx->offset) <= 0) + return 0; + +- ctx->appends_checked = TRUE; ++ ctx->disk_appends_checked = TRUE; + ctx->remap_counter = view->cache->remap_counter; + memset(&view->loop_track, 0, sizeof(view->loop_track)); + } + ++ if (ctx->stop) ++ return 0; ++ + /* look up the next record */ + if (mail_cache_get_record(view->cache, ctx->offset, &ctx->rec) < 0) + return -1; +diff --git a/src/lib-index/mail-cache-private.h b/src/lib-index/mail-cache-private.h +index 7b6f33c..eb57387 100644 +--- a/src/lib-index/mail-cache-private.h ++++ b/src/lib-index/mail-cache-private.h +@@ -202,9 +202,12 @@ struct mail_cache_lookup_iterate_ctx { + unsigned int pos, rec_size; + uint32_t offset; + ++ unsigned int trans_next_idx; ++ + unsigned int stop:1; + unsigned int failed:1; +- unsigned int appends_checked:1; ++ unsigned int memory_appends_checked:1; ++ unsigned int disk_appends_checked:1; + }; + + /* Explicitly lock the cache file. Returns -1 if error / timed out, +@@ -243,6 +246,10 @@ void mail_cache_lookup_iter_init(struct mail_cache_view *view, uint32_t seq, + /* Returns 1 if field was returned, 0 if end of fields, or -1 if error */ + int mail_cache_lookup_iter_next(struct mail_cache_lookup_iterate_ctx *ctx, + struct mail_cache_iterate_field *field_r); ++const struct mail_cache_record * ++mail_cache_transaction_lookup_rec(struct mail_cache_transaction_ctx *ctx, ++ unsigned int seq, ++ unsigned int *trans_next_idx); + + int mail_cache_map(struct mail_cache *cache, size_t offset, size_t size, + const void **data_r); +diff --git a/src/lib-index/mail-cache-transaction.c b/src/lib-index/mail-cache-transaction.c +index 6049d33..b56aa94 100644 +--- a/src/lib-index/mail-cache-transaction.c ++++ b/src/lib-index/mail-cache-transaction.c +@@ -21,6 +21,11 @@ + #define CACHE_TRANS_CONTEXT(obj) \ + MODULE_CONTEXT(obj, cache_mail_index_transaction_module) + ++struct mail_cache_transaction_rec { ++ uint32_t seq; ++ uint32_t cache_data_pos; ++}; ++ + struct mail_cache_transaction_ctx { + union mail_index_transaction_module_context module_ctx; + struct mail_index_transaction_vfuncs super; +@@ -33,7 +38,7 @@ struct mail_cache_transaction_ctx { + uint32_t first_new_seq; + + buffer_t *cache_data; +- ARRAY(uint32_t) cache_data_seq; ++ ARRAY(struct mail_cache_transaction_rec) cache_data_seq; + uint32_t prev_seq, min_seq; + size_t last_rec_pos; + +@@ -272,13 +277,33 @@ static int mail_cache_transaction_lock(struct mail_cache_transaction_ctx *ctx) + return 1; + } + ++const struct mail_cache_record * ++mail_cache_transaction_lookup_rec(struct mail_cache_transaction_ctx *ctx, ++ unsigned int seq, ++ unsigned int *trans_next_idx) ++{ ++ const struct mail_cache_transaction_rec *recs; ++ unsigned int i, count; ++ ++ recs = array_get(&ctx->cache_data_seq, &count); ++ for (i = *trans_next_idx; i < count; i++) { ++ if (recs[i].seq == seq) { ++ *trans_next_idx = i + 1; ++ return CONST_PTR_OFFSET(ctx->cache_data->data, ++ recs[i].cache_data_pos); ++ } ++ } ++ *trans_next_idx = i; ++ return NULL; ++} ++ + static int + mail_cache_transaction_update_index(struct mail_cache_transaction_ctx *ctx, + uint32_t write_offset) + { + struct mail_cache *cache = ctx->cache; + const struct mail_cache_record *rec = ctx->cache_data->data; +- const uint32_t *seqs; ++ const struct mail_cache_transaction_rec *recs; + uint32_t i, seq_count; + + mail_index_ext_using_reset_id(ctx->trans, ctx->cache->ext_id, +@@ -287,9 +312,9 @@ mail_cache_transaction_update_index(struct mail_cache_transaction_ctx *ctx, + /* write the cache_offsets to index file. records' prev_offset + is updated to point to old cache record when index is being + synced. */ +- seqs = array_get(&ctx->cache_data_seq, &seq_count); ++ recs = array_get(&ctx->cache_data_seq, &seq_count); + for (i = 0; i < seq_count; i++) { +- mail_index_update_ext(ctx->trans, seqs[i], cache->ext_id, ++ mail_index_update_ext(ctx->trans, recs[i].seq, cache->ext_id, + &write_offset, NULL); + + write_offset += rec->size; +@@ -304,7 +329,8 @@ mail_cache_link_records(struct mail_cache_transaction_ctx *ctx, + { + struct mail_index_map *map; + struct mail_cache_record *rec; +- const uint32_t *seqs, *prev_offsetp; ++ const struct mail_cache_transaction_rec *recs; ++ const uint32_t *prev_offsetp; + ARRAY_TYPE(uint32_t) seq_offsets; + uint32_t i, seq_count, reset_id, prev_offset, *offsetp; + const void *data; +@@ -312,15 +338,15 @@ mail_cache_link_records(struct mail_cache_transaction_ctx *ctx, + i_assert(ctx->min_seq != 0); + + i_array_init(&seq_offsets, 64); +- seqs = array_get(&ctx->cache_data_seq, &seq_count); ++ recs = array_get(&ctx->cache_data_seq, &seq_count); + rec = buffer_get_modifiable_data(ctx->cache_data, NULL); + for (i = 0; i < seq_count; i++) { + offsetp = array_idx_modifiable(&seq_offsets, +- seqs[i] - ctx->min_seq); ++ recs[i].seq - ctx->min_seq); + if (*offsetp != 0) + prev_offset = *offsetp; + else { +- mail_index_lookup_ext_full(ctx->view->trans_view, seqs[i], ++ mail_index_lookup_ext_full(ctx->view->trans_view, recs[i].seq, + ctx->cache->ext_id, &map, + &data, NULL); + prev_offsetp = data; +@@ -423,6 +449,7 @@ mail_cache_transaction_flush(struct mail_cache_transaction_ctx *ctx) + static void + mail_cache_transaction_update_last_rec(struct mail_cache_transaction_ctx *ctx) + { ++ struct mail_cache_transaction_rec *trans_rec; + struct mail_cache_record *rec; + void *data; + size_t size; +@@ -439,7 +466,9 @@ mail_cache_transaction_update_last_rec(struct mail_cache_transaction_ctx *ctx) + + if (ctx->min_seq > ctx->prev_seq || ctx->min_seq == 0) + ctx->min_seq = ctx->prev_seq; +- array_append(&ctx->cache_data_seq, &ctx->prev_seq, 1); ++ trans_rec = array_append_space(&ctx->cache_data_seq); ++ trans_rec->seq = ctx->prev_seq; ++ trans_rec->cache_data_pos = ctx->last_rec_pos; + ctx->last_rec_pos = size; + } + +-- +1.7.10.2 + + +From 4b733318b4ff228f7e920adc19d5cb4a7d654a4c Mon Sep 17 00:00:00 2001 +From: Timo Sirainen +Date: Sun, 26 May 2013 19:14:21 +0300 +Subject: [PATCH] dbox: Added support for POP3 message order. + + +diff --git a/src/doveadm/doveadm-dump-dbox.c b/src/doveadm/doveadm-dump-dbox.c +index 35aaa8a..17f4c24 100644 +--- a/src/doveadm/doveadm-dump-dbox.c ++++ b/src/doveadm/doveadm-dump-dbox.c +@@ -148,6 +148,9 @@ static void dump_msg_metadata(struct istream *input) + case DBOX_METADATA_POP3_UIDL: + printf("msg.pop3-uidl = %s\n", line + 1); + break; ++ case DBOX_METADATA_POP3_ORDER: ++ printf("msg.pop3-order = %s\n", line + 1); ++ break; + case DBOX_METADATA_RECEIVED_TIME: + dump_timestamp(input, "msg.received", line + 1); + break; +diff --git a/src/lib-storage/index/dbox-common/dbox-file.h b/src/lib-storage/index/dbox-common/dbox-file.h +index 5b94535..f790a35 100644 +--- a/src/lib-storage/index/dbox-common/dbox-file.h ++++ b/src/lib-storage/index/dbox-common/dbox-file.h +@@ -45,6 +45,8 @@ enum dbox_metadata_key { + DBOX_METADATA_GUID = 'G', + /* POP3 UIDL overriding the default format */ + DBOX_METADATA_POP3_UIDL = 'P', ++ /* POP3 message ordering (for migrated mails) */ ++ DBOX_METADATA_POP3_ORDER = 'O', + /* Received UNIX timestamp in hex */ + DBOX_METADATA_RECEIVED_TIME = 'R', + /* Physical message size in hex. Necessary only if it differs from +diff --git a/src/lib-storage/index/dbox-common/dbox-mail.c b/src/lib-storage/index/dbox-common/dbox-mail.c +index 3ec1e1b..90bf176 100644 +--- a/src/lib-storage/index/dbox-common/dbox-mail.c ++++ b/src/lib-storage/index/dbox-common/dbox-mail.c +@@ -165,12 +165,19 @@ dbox_get_cached_metadata(struct dbox_mail *mail, enum dbox_metadata_key key, + INDEX_STORAGE_CONTEXT(imail->mail.mail.box); + const char *value; + string_t *str; ++ uint32_t order; + + str = str_new(imail->mail.data_pool, 64); + if (mail_cache_lookup_field(imail->mail.mail.transaction->cache_view, + str, imail->mail.mail.seq, + ibox->cache_fields[cache_field].idx) > 0) { +- *value_r = str_c(str); ++ if (cache_field != MAIL_CACHE_POP3_ORDER) ++ *value_r = str_c(str); ++ else { ++ i_assert(str_len(str) == sizeof(order)); ++ memcpy(&order, str_data(str), sizeof(order)); ++ *value_r = dec2str(order); ++ } + return 0; + } + +@@ -179,8 +186,15 @@ dbox_get_cached_metadata(struct dbox_mail *mail, enum dbox_metadata_key key, + + if (value == NULL) + value = ""; +- index_mail_cache_add_idx(imail, ibox->cache_fields[cache_field].idx, +- value, strlen(value)+1); ++ if (cache_field != MAIL_CACHE_POP3_ORDER) { ++ index_mail_cache_add_idx(imail, ibox->cache_fields[cache_field].idx, ++ value, strlen(value)+1); ++ } else { ++ if (str_to_uint(value, &order) < 0) ++ order = 0; ++ index_mail_cache_add_idx(imail, ibox->cache_fields[cache_field].idx, ++ &order, sizeof(order)); ++ } + + /* don't return pointer to dbox metadata directly, since it may + change unexpectedly */ +@@ -202,6 +216,9 @@ int dbox_mail_get_special(struct mail *_mail, enum mail_fetch_field field, + case MAIL_FETCH_UIDL_BACKEND: + return dbox_get_cached_metadata(mail, DBOX_METADATA_POP3_UIDL, + MAIL_CACHE_POP3_UIDL, value_r); ++ case MAIL_FETCH_POP3_ORDER: ++ return dbox_get_cached_metadata(mail, DBOX_METADATA_POP3_ORDER, ++ MAIL_CACHE_POP3_ORDER, value_r); + case MAIL_FETCH_GUID: + return dbox_get_cached_metadata(mail, DBOX_METADATA_GUID, + MAIL_CACHE_GUID, value_r); +diff --git a/src/lib-storage/index/dbox-common/dbox-save.c b/src/lib-storage/index/dbox-common/dbox-save.c +index e7d0e4c..1aaa676 100644 +--- a/src/lib-storage/index/dbox-common/dbox-save.c ++++ b/src/lib-storage/index/dbox-common/dbox-save.c +@@ -164,6 +164,10 @@ void dbox_save_write_metadata(struct mail_save_context *_ctx, + str_printfa(str, "%c%s\n", DBOX_METADATA_POP3_UIDL, + mdata->pop3_uidl); + } ++ if (mdata->pop3_order != 0) { ++ str_printfa(str, "%c%u\n", DBOX_METADATA_POP3_ORDER, ++ mdata->pop3_order); ++ } + + guid = mdata->guid; + if (guid != NULL) +diff --git a/src/lib-storage/index/index-mail.c b/src/lib-storage/index/index-mail.c +index bb6929d..dc3a25b 100644 +--- a/src/lib-storage/index/index-mail.c ++++ b/src/lib-storage/index/index-mail.c +@@ -46,6 +46,9 @@ struct mail_cache_field global_cache_fields[MAIL_INDEX_CACHE_FIELD_COUNT] = { + .type = MAIL_CACHE_FIELD_STRING }, + { .name = "pop3.uidl", + .type = MAIL_CACHE_FIELD_STRING }, ++ { .name = "pop3.order", ++ .type = MAIL_CACHE_FIELD_FIXED_SIZE, ++ .field_size = sizeof(uint32_t) }, + { .name = "guid", + .type = MAIL_CACHE_FIELD_STRING }, + { .name = "mime.parts", +@@ -1871,6 +1874,8 @@ void index_mail_precache(struct mail *mail) + (void)mail_get_physical_size(mail, &size); + if ((cache & MAIL_FETCH_UIDL_BACKEND) != 0) + (void)mail_get_special(mail, MAIL_FETCH_UIDL_BACKEND, &str); ++ if ((cache & MAIL_FETCH_POP3_ORDER) != 0) ++ (void)mail_get_special(mail, MAIL_FETCH_POP3_ORDER, &str); + if ((cache & MAIL_FETCH_GUID) != 0) + (void)mail_get_special(mail, MAIL_FETCH_GUID, &str); + } +diff --git a/src/lib-storage/index/index-mail.h b/src/lib-storage/index/index-mail.h +index 4acf146..bc6d8af 100644 +--- a/src/lib-storage/index/index-mail.h ++++ b/src/lib-storage/index/index-mail.h +@@ -19,6 +19,7 @@ enum index_cache_field { + MAIL_CACHE_IMAP_BODYSTRUCTURE, + MAIL_CACHE_IMAP_ENVELOPE, + MAIL_CACHE_POP3_UIDL, ++ MAIL_CACHE_POP3_ORDER, + MAIL_CACHE_GUID, + MAIL_CACHE_MESSAGE_PARTS, + MAIL_CACHE_BINARY_PARTS, +-- +1.7.10.2 + + +From 4a11e3d91412544649014b5edb6376eec1791b28 Mon Sep 17 00:00:00 2001 +From: Timo Sirainen +Date: Sun, 26 May 2013 21:07:09 +0300 +Subject: [PATCH] imapc: Pass through SPECIAL-USE LIST flags if imapc is in + INBOX namespace. + + +diff --git a/src/lib-storage/index/imapc/imapc-list.c b/src/lib-storage/index/imapc/imapc-list.c +index 4f31614..52fbd3a 100644 +--- a/src/lib-storage/index/imapc/imapc-list.c ++++ b/src/lib-storage/index/imapc/imapc-list.c +@@ -18,6 +18,26 @@ struct imapc_mailbox_list_iterate_context { + + struct mailbox_tree_iterate_context *iter; + struct mailbox_info info; ++ string_t *special_use; ++}; ++ ++static struct { ++ const char *str; ++ enum mailbox_info_flags flag; ++} imap_list_flags[] = { ++ { "\\NoSelect", MAILBOX_NOSELECT }, ++ { "\\NonExistent", MAILBOX_NONEXISTENT }, ++ { "\\NoInferiors", MAILBOX_NOINFERIORS }, ++ { "\\Subscribed", MAILBOX_SUBSCRIBED }, ++ { "\\Subscribed", MAILBOX_SUBSCRIBED }, ++ { "\\All", MAILBOX_SPECIALUSE_ALL }, ++ { "\\Archive", MAILBOX_SPECIALUSE_ARCHIVE }, ++ { "\\Drafts", MAILBOX_SPECIALUSE_DRAFTS }, ++ { "\\Flagged", MAILBOX_SPECIALUSE_FLAGGED }, ++ { "\\Junk", MAILBOX_SPECIALUSE_JUNK }, ++ { "\\Sent", MAILBOX_SPECIALUSE_SENT }, ++ { "\\Trash", MAILBOX_SPECIALUSE_TRASH }, ++ { "\\Important", MAILBOX_SPECIALUSE_IMPORTANT } + }; + + extern struct mailbox_list imapc_mailbox_list; +@@ -63,6 +83,20 @@ static void imapc_list_simple_callback(const struct imapc_command_reply *reply, + } + } + ++static bool ++imap_list_flag_parse(const char *str, enum mailbox_info_flags *flag_r) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < N_ELEMENTS(imap_list_flags); i++) { ++ if (strcasecmp(str, imap_list_flags[i].str) == 0) { ++ *flag_r = imap_list_flags[i].flag; ++ return TRUE; ++ } ++ } ++ return FALSE; ++} ++ + static struct mailbox_node * + imapc_list_update_tree(struct imapc_mailbox_list *list, + struct mailbox_tree_context *tree, +@@ -71,7 +105,7 @@ imapc_list_update_tree(struct imapc_mailbox_list *list, + struct mailbox_node *node; + const struct imap_arg *flags; + const char *name, *flag; +- enum mailbox_info_flags info_flags = 0; ++ enum mailbox_info_flags info_flag, info_flags = 0; + bool created; + + if (!imap_arg_get_list(&args[0], &flags) || +@@ -80,14 +114,8 @@ imapc_list_update_tree(struct imapc_mailbox_list *list, + return NULL; + + while (imap_arg_get_atom(flags, &flag)) { +- if (strcasecmp(flag, "\\NoSelect") == 0) +- info_flags |= MAILBOX_NOSELECT; +- else if (strcasecmp(flag, "\\NonExistent") == 0) +- info_flags |= MAILBOX_NONEXISTENT; +- else if (strcasecmp(flag, "\\NoInferiors") == 0) +- info_flags |= MAILBOX_NOINFERIORS; +- else if (strcasecmp(flag, "\\Subscribed") == 0) +- info_flags |= MAILBOX_SUBSCRIBED; ++ if (imap_list_flag_parse(flag, &info_flag)) ++ info_flags |= info_flag; + flags++; + } + +@@ -450,6 +478,31 @@ imapc_list_iter_init(struct mailbox_list *_list, const char *const *patterns, + return &ctx->ctx; + } + ++static void ++imapc_list_write_special_use(struct imapc_mailbox_list_iterate_context *ctx, ++ struct mailbox_node *node) ++{ ++ unsigned int i; ++ ++ if (ctx->special_use == NULL) ++ ctx->special_use = str_new(ctx->ctx.pool, 64); ++ str_truncate(ctx->special_use, 0); ++ ++ for (i = 0; i < N_ELEMENTS(imap_list_flags); i++) { ++ if ((node->flags & imap_list_flags[i].flag) != 0) { ++ str_append(ctx->special_use, imap_list_flags[i].str); ++ str_append_c(ctx->special_use, ' '); ++ } ++ } ++ ++ if (str_len(ctx->special_use) > 0) { ++ str_truncate(ctx->special_use, str_len(ctx->special_use) - 1); ++ ctx->info.special_use = str_c(ctx->special_use); ++ } else { ++ ctx->info.special_use = NULL; ++ } ++} ++ + static const struct mailbox_info * + imapc_list_iter_next(struct mailbox_list_iterate_context *_ctx) + { +@@ -472,6 +525,13 @@ imapc_list_iter_next(struct mailbox_list_iterate_context *_ctx) + + ctx->info.vname = vname; + ctx->info.flags = node->flags; ++ if ((_ctx->list->ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0) { ++ /* we're iterating the INBOX namespace. pass through the ++ SPECIAL-USE flags if they exist. */ ++ imapc_list_write_special_use(ctx, node); ++ } else { ++ ctx->info.special_use = NULL; ++ } + return &ctx->info; + } + +diff --git a/src/lib-storage/mailbox-list.h b/src/lib-storage/mailbox-list.h +index edd301c..fb4096f 100644 +--- a/src/lib-storage/mailbox-list.h ++++ b/src/lib-storage/mailbox-list.h +@@ -48,7 +48,18 @@ enum mailbox_info_flags { + MAILBOX_CHILD_SUBSCRIBED = 0x100, + MAILBOX_CHILD_SPECIALUSE = 0x200, + +- /* Internally used by lib-storage */ ++ /* Internally used by lib-storage, use mailbox_info.special_use ++ to actually access these: */ ++ MAILBOX_SPECIALUSE_ALL = 0x00010000, ++ MAILBOX_SPECIALUSE_ARCHIVE = 0x00020000, ++ MAILBOX_SPECIALUSE_DRAFTS = 0x00040000, ++ MAILBOX_SPECIALUSE_FLAGGED = 0x00080000, ++ MAILBOX_SPECIALUSE_JUNK = 0x00100000, ++ MAILBOX_SPECIALUSE_SENT = 0x00200000, ++ MAILBOX_SPECIALUSE_TRASH = 0x00400000, ++ MAILBOX_SPECIALUSE_IMPORTANT = 0x00800000, ++ ++ /* Internally used by lib-storage: */ + MAILBOX_SELECT = 0x20000000, + MAILBOX_MATCHED = 0x40000000 + }; +-- +1.7.10.2 + + +From 05508c41a5a10da2a2cffe645d0f661c9743b9de Mon Sep 17 00:00:00 2001 +From: Timo Sirainen +Date: Sun, 26 May 2013 21:20:47 +0300 +Subject: [PATCH] dsync: Small code cleanup. + + +diff --git a/src/doveadm/dsync/doveadm-dsync.c b/src/doveadm/dsync/doveadm-dsync.c +index 73cfe60..895ff46 100644 +--- a/src/doveadm/dsync/doveadm-dsync.c ++++ b/src/doveadm/dsync/doveadm-dsync.c +@@ -486,16 +486,22 @@ cmd_dsync_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user) + struct dsync_cmd_context *ctx = (struct dsync_cmd_context *)_ctx; + struct dsync_ibc *ibc, *ibc2 = NULL; + struct dsync_brain *brain; +- struct mail_namespace *sync_ns = NULL; ++ struct dsync_brain_settings set; + enum dsync_brain_flags brain_flags; + bool remote_errors_logged = FALSE; + int status = 0, ret = 0; + ++ memset(&set, 0, sizeof(set)); ++ set.sync_box = ctx->mailbox; ++ memcpy(set.sync_box_guid, ctx->mailbox_guid, sizeof(set.sync_box_guid)); ++ set.lock_timeout_secs = ctx->lock_timeout; ++ set.state = ctx->state_input; ++ + user->dsyncing = TRUE; + + if (ctx->namespace_prefix != NULL) { +- sync_ns = mail_namespace_find(user->namespaces, +- ctx->namespace_prefix); ++ set.sync_ns = mail_namespace_find(user->namespaces, ++ ctx->namespace_prefix); + } + + if (ctx->run_type == DSYNC_RUN_TYPE_LOCAL) +@@ -524,12 +530,9 @@ cmd_dsync_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user) + brain_flags |= DSYNC_BRAIN_FLAG_NO_MAIL_SYNC; + if (doveadm_debug) + brain_flags |= DSYNC_BRAIN_FLAG_DEBUG; +- brain = dsync_brain_master_init(user, ibc, sync_ns, ctx->mailbox, +- ctx->mailbox_guid, +- ctx->sync_type, brain_flags, +- ctx->lock_timeout, +- ctx->state_input == NULL ? "" : +- ctx->state_input); ++ ++ brain = dsync_brain_master_init(user, ibc, ctx->sync_type, ++ brain_flags, &set); + + if (ctx->run_type == DSYNC_RUN_TYPE_LOCAL) { + if (cmd_dsync_run_local(ctx, user, brain, ibc2) < 0) +diff --git a/src/doveadm/dsync/dsync-brain.c b/src/doveadm/dsync/dsync-brain.c +index f305520..ca48d22 100644 +--- a/src/doveadm/dsync/dsync-brain.c ++++ b/src/doveadm/dsync/dsync-brain.c +@@ -86,32 +86,32 @@ dsync_brain_set_flags(struct dsync_brain *brain, enum dsync_brain_flags flags) + + struct dsync_brain * + dsync_brain_master_init(struct mail_user *user, struct dsync_ibc *ibc, +- struct mail_namespace *sync_ns, const char *sync_box, +- const guid_128_t sync_box_guid, + enum dsync_brain_sync_type sync_type, +- enum dsync_brain_flags flags, unsigned int lock_timeout, +- const char *state) ++ enum dsync_brain_flags flags, ++ const struct dsync_brain_settings *set) + { + struct dsync_ibc_settings ibc_set; + struct dsync_brain *brain; + const char *error; + + i_assert(sync_type != DSYNC_BRAIN_SYNC_TYPE_UNKNOWN); +- i_assert(sync_type != DSYNC_BRAIN_SYNC_TYPE_STATE || *state != '\0'); ++ i_assert(sync_type != DSYNC_BRAIN_SYNC_TYPE_STATE || ++ (set->state != NULL && *set->state != '\0')); + + brain = dsync_brain_common_init(user, ibc); + brain->sync_type = sync_type; +- if (sync_ns != NULL) +- brain->sync_ns = sync_ns; +- brain->sync_box = p_strdup(brain->pool, sync_box); +- memcpy(brain->sync_box_guid, sync_box_guid, sizeof(brain->sync_box_guid)); +- brain->lock_timeout = lock_timeout; ++ if (set->sync_ns != NULL) ++ brain->sync_ns = set->sync_ns; ++ brain->sync_box = p_strdup(brain->pool, set->sync_box); ++ memcpy(brain->sync_box_guid, set->sync_box_guid, ++ sizeof(brain->sync_box_guid)); ++ brain->lock_timeout = set->lock_timeout_secs; + brain->master_brain = TRUE; + dsync_brain_set_flags(brain, flags); + + if (sync_type == DSYNC_BRAIN_SYNC_TYPE_STATE && + dsync_mailbox_states_import(brain->mailbox_states, +- brain->pool, state, &error) < 0) { ++ brain->pool, set->state, &error) < 0) { + hash_table_clear(brain->mailbox_states, FALSE); + i_error("Saved sync state is invalid, " + "falling back to full sync: %s", error); +@@ -121,12 +121,13 @@ dsync_brain_master_init(struct mail_user *user, struct dsync_ibc *ibc, + + memset(&ibc_set, 0, sizeof(ibc_set)); + ibc_set.hostname = my_hostdomain(); +- ibc_set.sync_ns_prefix = sync_ns == NULL ? NULL : sync_ns->prefix; +- ibc_set.sync_box = sync_box; +- memcpy(ibc_set.sync_box_guid, sync_box_guid, ++ ibc_set.sync_ns_prefix = set->sync_ns == NULL ? NULL : ++ set->sync_ns->prefix; ++ ibc_set.sync_box = set->sync_box; ++ memcpy(ibc_set.sync_box_guid, set->sync_box_guid, + sizeof(ibc_set.sync_box_guid)); + ibc_set.sync_type = sync_type; +- ibc_set.lock_timeout = lock_timeout; ++ ibc_set.lock_timeout = set->lock_timeout_secs; + /* reverse the backup direction for the slave */ + ibc_set.brain_flags = flags & ~(DSYNC_BRAIN_FLAG_BACKUP_SEND | + DSYNC_BRAIN_FLAG_BACKUP_RECV); +diff --git a/src/doveadm/dsync/dsync-brain.h b/src/doveadm/dsync/dsync-brain.h +index 29bf4d2..ff0af27 100644 +--- a/src/doveadm/dsync/dsync-brain.h ++++ b/src/doveadm/dsync/dsync-brain.h +@@ -30,13 +30,25 @@ enum dsync_brain_sync_type { + DSYNC_BRAIN_SYNC_TYPE_STATE + }; + ++struct dsync_brain_settings { ++ /* Sync only this namespace */ ++ struct mail_namespace *sync_ns; ++ /* Sync only this mailbox name */ ++ const char *sync_box; ++ /* Sync only this mailbox GUID */ ++ guid_128_t sync_box_guid; ++ ++ /* If non-zero, use dsync lock file for this user */ ++ unsigned int lock_timeout_secs; ++ /* Input state for DSYNC_BRAIN_SYNC_TYPE_STATE */ ++ const char *state; ++}; ++ + struct dsync_brain * + dsync_brain_master_init(struct mail_user *user, struct dsync_ibc *ibc, +- struct mail_namespace *sync_ns, const char *sync_box, +- const guid_128_t sync_box_guid, + enum dsync_brain_sync_type sync_type, +- enum dsync_brain_flags flags, unsigned int lock_timeout, +- const char *state); ++ enum dsync_brain_flags flags, ++ const struct dsync_brain_settings *set); + struct dsync_brain * + dsync_brain_slave_init(struct mail_user *user, struct dsync_ibc *ibc); + /* Returns 0 if everything was successful, -1 if syncing failed in some way */ +-- +1.7.10.2 + + +From 1aad34445081a0f35bc964b989b3983918bd6e52 Mon Sep 17 00:00:00 2001 +From: Timo Sirainen +Date: Sun, 26 May 2013 21:44:50 +0300 +Subject: [PATCH] imapc: Fixed assert-crash when copying messages. + + +diff --git a/src/lib-storage/index/imapc/imapc-save.c b/src/lib-storage/index/imapc/imapc-save.c +index 7e80c7c..0556b76 100644 +--- a/src/lib-storage/index/imapc/imapc-save.c ++++ b/src/lib-storage/index/imapc/imapc-save.c +@@ -422,6 +422,7 @@ int imapc_copy(struct mail_save_context *_ctx, struct mail *mail) + while (sctx.ret == -2) + imapc_storage_run(src_mbox->storage); + ctx->finished = TRUE; ++ index_save_context_free(_ctx); + return sctx.ret; + } + return mail_storage_copy(_ctx, mail); +-- +1.7.10.2 + + +From aea076fdc28d751590981cdb305086526dbb1671 Mon Sep 17 00:00:00 2001 +From: Timo Sirainen +Date: Sun, 26 May 2013 21:57:36 +0300 +Subject: [PATCH] dsync: Added -x parameter to exclude mailboxes from sync. + Multiple -x parameters can be added. Giving \flag as + parameter means that the mailbox with the given SPECIAL-USE + \flag is skipped. For example: + +doveadm sync -x '\All' -x '\Flagged' -x '\Important' mdbox:~/mdbox + +diff --git a/src/doveadm/dsync/doveadm-dsync.c b/src/doveadm/dsync/doveadm-dsync.c +index 895ff46..a1e6e9d 100644 +--- a/src/doveadm/dsync/doveadm-dsync.c ++++ b/src/doveadm/dsync/doveadm-dsync.c +@@ -36,7 +36,7 @@ + #include + #include + +-#define DSYNC_COMMON_GETOPT_ARGS "+dEfg:l:m:n:Nr:Rs:U" ++#define DSYNC_COMMON_GETOPT_ARGS "+dEfg:l:m:n:Nr:Rs:Ux:" + #define DSYNC_REMOTE_CMD_EXIT_WAIT_SECS 30 + + enum dsync_run_type { +@@ -51,6 +51,7 @@ struct dsync_cmd_context { + const char *mailbox, *namespace_prefix; + guid_128_t mailbox_guid; + const char *state_input, *rawlog_path; ++ ARRAY_TYPE(const_string) exclude_mailboxes; + + const char *remote_name; + const char *local_location; +@@ -496,6 +497,10 @@ cmd_dsync_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user) + memcpy(set.sync_box_guid, ctx->mailbox_guid, sizeof(set.sync_box_guid)); + set.lock_timeout_secs = ctx->lock_timeout; + set.state = ctx->state_input; ++ if (array_count(&ctx->exclude_mailboxes) > 0) { ++ /* array is NULL-terminated in init() */ ++ set.exclude_mailboxes = array_idx(&ctx->exclude_mailboxes, 0); ++ } + + user->dsyncing = TRUE; + +@@ -803,6 +808,8 @@ static void cmd_dsync_init(struct doveadm_mail_cmd_context *_ctx, + if (args[0] == NULL) + doveadm_mail_help_name(_ctx->cmd->name); + } ++ if (array_count(&ctx->exclude_mailboxes) > 0) ++ array_append_zero(&ctx->exclude_mailboxes); + + lib_signals_ignore(SIGHUP, TRUE); + } +@@ -817,6 +824,7 @@ static bool + cmd_mailbox_dsync_parse_arg(struct doveadm_mail_cmd_context *_ctx, int c) + { + struct dsync_cmd_context *ctx = (struct dsync_cmd_context *)_ctx; ++ const char *str; + + switch (c) { + case 'd': +@@ -847,6 +855,10 @@ cmd_mailbox_dsync_parse_arg(struct doveadm_mail_cmd_context *_ctx, int c) + else + ctx->mailbox = optarg; + break; ++ case 'x': ++ str = optarg; ++ array_append(&ctx->exclude_mailboxes, &str, 1); ++ break; + case 'n': + ctx->namespace_prefix = optarg; + break; +@@ -891,6 +903,7 @@ static struct doveadm_mail_cmd_context *cmd_dsync_alloc(void) + doveadm_print_init(DOVEADM_PRINT_TYPE_FLOW); + doveadm_print_header("state", "state", + DOVEADM_PRINT_HEADER_FLAG_HIDE_TITLE); ++ p_array_init(&ctx->exclude_mailboxes, ctx->ctx.pool, 4); + return &ctx->ctx; + } + +@@ -995,11 +1008,11 @@ static struct doveadm_mail_cmd_context *cmd_dsync_server_alloc(void) + + struct doveadm_mail_cmd cmd_dsync_mirror = { + cmd_dsync_alloc, "sync", +- "[-dfR] [-l ] [-m ] [-n ] [-s ] " ++ "[-dfR] [-l ] [-m ] [-n ] [-x ] [-s ] " + }; + struct doveadm_mail_cmd cmd_dsync_backup = { + cmd_dsync_backup_alloc, "backup", +- "[-dfR] [-l ] [-m ] [-n ] [-s ] " ++ "[-dfR] [-l ] [-m ] [-n ] [-x ] [-s ] " + }; + struct doveadm_mail_cmd cmd_dsync_server = { + cmd_dsync_server_alloc, "dsync-server", &doveadm_mail_cmd_hide +diff --git a/src/doveadm/dsync/dsync-brain-mailbox-tree.c b/src/doveadm/dsync/dsync-brain-mailbox-tree.c +index fb13444..fc9b79e 100644 +--- a/src/doveadm/dsync/dsync-brain-mailbox-tree.c ++++ b/src/doveadm/dsync/dsync-brain-mailbox-tree.c +@@ -83,20 +83,14 @@ void dsync_brain_mailbox_trees_init(struct dsync_brain *brain) + doveadm_settings->dsync_alt_char[0]); + + /* fill the local mailbox tree */ +- if (brain->sync_ns != NULL) { +- if (dsync_mailbox_tree_fill(brain->local_mailbox_tree, +- brain->sync_ns, brain->sync_box, +- brain->sync_box_guid) < 0) ++ for (ns = brain->user->namespaces; ns != NULL; ns = ns->next) { ++ if (!dsync_brain_want_namespace(brain, ns)) ++ continue; ++ if (dsync_mailbox_tree_fill(brain->local_mailbox_tree, ns, ++ brain->sync_box, ++ brain->sync_box_guid, ++ brain->exclude_mailboxes) < 0) + brain->failed = TRUE; +- } else { +- for (ns = brain->user->namespaces; ns != NULL; ns = ns->next) { +- if (!dsync_brain_want_namespace(brain, ns)) +- continue; +- if (dsync_mailbox_tree_fill(brain->local_mailbox_tree, +- ns, brain->sync_box, +- brain->sync_box_guid) < 0) +- brain->failed = TRUE; +- } + } + + brain->local_tree_iter = +diff --git a/src/doveadm/dsync/dsync-brain-private.h b/src/doveadm/dsync/dsync-brain-private.h +index 0021a03..63b8a75 100644 +--- a/src/doveadm/dsync/dsync-brain-private.h ++++ b/src/doveadm/dsync/dsync-brain-private.h +@@ -52,6 +52,7 @@ struct dsync_brain { + struct mail_namespace *sync_ns; + const char *sync_box; + guid_128_t sync_box_guid; ++ const char *const *exclude_mailboxes; + enum dsync_brain_sync_type sync_type; + + unsigned int lock_timeout; +diff --git a/src/doveadm/dsync/dsync-brain.c b/src/doveadm/dsync/dsync-brain.c +index ca48d22..803c447 100644 +--- a/src/doveadm/dsync/dsync-brain.c ++++ b/src/doveadm/dsync/dsync-brain.c +@@ -103,6 +103,8 @@ dsync_brain_master_init(struct mail_user *user, struct dsync_ibc *ibc, + if (set->sync_ns != NULL) + brain->sync_ns = set->sync_ns; + brain->sync_box = p_strdup(brain->pool, set->sync_box); ++ brain->exclude_mailboxes = set->exclude_mailboxes == NULL ? NULL : ++ p_strarray_dup(brain->pool, set->exclude_mailboxes); + memcpy(brain->sync_box_guid, set->sync_box_guid, + sizeof(brain->sync_box_guid)); + brain->lock_timeout = set->lock_timeout_secs; +@@ -124,6 +126,7 @@ dsync_brain_master_init(struct mail_user *user, struct dsync_ibc *ibc, + ibc_set.sync_ns_prefix = set->sync_ns == NULL ? NULL : + set->sync_ns->prefix; + ibc_set.sync_box = set->sync_box; ++ ibc_set.exclude_mailboxes = set->exclude_mailboxes; + memcpy(ibc_set.sync_box_guid, set->sync_box_guid, + sizeof(ibc_set.sync_box_guid)); + ibc_set.sync_type = sync_type; +@@ -312,6 +315,8 @@ static bool dsync_brain_slave_recv_handshake(struct dsync_brain *brain) + ibc_set->sync_ns_prefix); + } + brain->sync_box = p_strdup(brain->pool, ibc_set->sync_box); ++ brain->exclude_mailboxes = ibc_set->exclude_mailboxes == NULL ? NULL : ++ p_strarray_dup(brain->pool, ibc_set->exclude_mailboxes); + memcpy(brain->sync_box_guid, ibc_set->sync_box_guid, + sizeof(brain->sync_box_guid)); + i_assert(brain->sync_type == DSYNC_BRAIN_SYNC_TYPE_UNKNOWN); +diff --git a/src/doveadm/dsync/dsync-brain.h b/src/doveadm/dsync/dsync-brain.h +index ff0af27..6d7c218 100644 +--- a/src/doveadm/dsync/dsync-brain.h ++++ b/src/doveadm/dsync/dsync-brain.h +@@ -37,6 +37,9 @@ struct dsync_brain_settings { + const char *sync_box; + /* Sync only this mailbox GUID */ + guid_128_t sync_box_guid; ++ /* Exclude these mailboxes from the sync. They can contain '*' ++ wildcards and be \special-use flags. */ ++ const char *const *exclude_mailboxes; + + /* If non-zero, use dsync lock file for this user */ + unsigned int lock_timeout_secs; +diff --git a/src/doveadm/dsync/dsync-ibc-pipe.c b/src/doveadm/dsync/dsync-ibc-pipe.c +index 6bf962e..da81312 100644 +--- a/src/doveadm/dsync/dsync-ibc-pipe.c ++++ b/src/doveadm/dsync/dsync-ibc-pipe.c +@@ -161,6 +161,8 @@ dsync_ibc_pipe_send_handshake(struct dsync_ibc *ibc, + item->u.set = *set; + item->u.set.sync_ns_prefix = p_strdup(item->pool, set->sync_ns_prefix); + item->u.set.sync_box = p_strdup(item->pool, set->sync_box); ++ item->u.set.exclude_mailboxes = set->exclude_mailboxes == NULL ? NULL : ++ p_strarray_dup(item->pool, set->exclude_mailboxes); + memcpy(item->u.set.sync_box_guid, set->sync_box_guid, + sizeof(item->u.set.sync_box_guid)); + } +diff --git a/src/doveadm/dsync/dsync-ibc-stream.c b/src/doveadm/dsync/dsync-ibc-stream.c +index 3dab919..ef9a1af 100644 +--- a/src/doveadm/dsync/dsync-ibc-stream.c ++++ b/src/doveadm/dsync/dsync-ibc-stream.c +@@ -73,7 +73,7 @@ static const struct { + .chr = 'H', + .required_keys = "hostname", + .optional_keys = "sync_ns_prefix sync_box sync_box_guid sync_type " +- "debug sync_visible_namespaces " ++ "debug sync_visible_namespaces exclude_mailboxes" + "send_mail_requests backup_send backup_recv lock_timeout" + }, + { .name = "mailbox_state", +@@ -594,6 +594,18 @@ dsync_ibc_stream_send_handshake(struct dsync_ibc *_ibc, + } + if (set->sync_box != NULL) + dsync_serializer_encode_add(encoder, "sync_box", set->sync_box); ++ if (set->exclude_mailboxes != NULL) { ++ string_t *substr = t_str_new(64); ++ unsigned int i; ++ ++ for (i = 0; set->exclude_mailboxes[i] != NULL; i++) { ++ if (i != 0) ++ str_append_c(substr, '\t'); ++ str_append_tabescaped(substr, set->exclude_mailboxes[i]); ++ } ++ dsync_serializer_encode_add(encoder, "exclude_mailboxes", ++ str_c(substr)); ++ } + if (!guid_128_is_empty(set->sync_box_guid)) { + dsync_serializer_encode_add(encoder, "sync_box_guid", + guid_128_to_string(set->sync_box_guid)); +@@ -670,6 +682,11 @@ dsync_ibc_stream_recv_handshake(struct dsync_ibc *_ibc, + "Invalid sync_box_guid: %s", value); + return DSYNC_IBC_RECV_RET_TRYAGAIN; + } ++ if (dsync_deserializer_decode_try(decoder, "exclude_mailboxes", &value) && ++ *value != '\0') { ++ char **boxes = p_strsplit_tabescaped(pool, value); ++ set->exclude_mailboxes = (const void *)boxes; ++ } + if (dsync_deserializer_decode_try(decoder, "sync_type", &value)) { + switch (value[0]) { + case 'f': +diff --git a/src/doveadm/dsync/dsync-ibc.h b/src/doveadm/dsync/dsync-ibc.h +index b1d2a26..6700dfb 100644 +--- a/src/doveadm/dsync/dsync-ibc.h ++++ b/src/doveadm/dsync/dsync-ibc.h +@@ -49,6 +49,9 @@ struct dsync_ibc_settings { + const char *sync_box; + /* if non-empty, sync only this mailbox GUID */ + guid_128_t sync_box_guid; ++ /* Exclude these mailboxes from the sync. They can contain '*' ++ wildcards and be \special-use flags. */ ++ const char *const *exclude_mailboxes; + + enum dsync_brain_sync_type sync_type; + enum dsync_brain_flags brain_flags; +diff --git a/src/doveadm/dsync/dsync-mailbox-tree-fill.c b/src/doveadm/dsync/dsync-mailbox-tree-fill.c +index 9480ebb..8af9fad 100644 +--- a/src/doveadm/dsync/dsync-mailbox-tree-fill.c ++++ b/src/doveadm/dsync/dsync-mailbox-tree-fill.c +@@ -5,6 +5,7 @@ + #include "hash.h" + #include "guid.h" + #include "str.h" ++#include "wildcard-match.h" + #include "mailbox-log.h" + #include "mail-namespace.h" + #include "mail-storage.h" +@@ -265,9 +266,39 @@ dsync_mailbox_tree_fix_guid_duplicate(struct dsync_mailbox_tree *tree, + return ret; + } + ++static bool ++dsync_mailbox_info_is_excluded(const struct mailbox_info *info, ++ const char *const *exclude_mailboxes) ++{ ++ const char *const *info_specialuses; ++ unsigned int i; ++ ++ if (exclude_mailboxes == NULL) ++ return FALSE; ++ ++ info_specialuses = info->special_use == NULL ? NULL : ++ t_strsplit(info->special_use, " "); ++ for (i = 0; exclude_mailboxes[i] != NULL; i++) { ++ const char *exclude = exclude_mailboxes[i]; ++ ++ if (exclude[0] == '\\') { ++ /* special-use */ ++ if (info_specialuses != NULL && ++ str_array_icase_find(info_specialuses, exclude)) ++ return TRUE; ++ } else { ++ /* mailbox with wildcards */ ++ if (wildcard_match(info->vname, exclude)) ++ return TRUE; ++ } ++ } ++ return FALSE; ++} ++ + int dsync_mailbox_tree_fill(struct dsync_mailbox_tree *tree, + struct mail_namespace *ns, const char *box_name, +- const guid_128_t box_guid) ++ const guid_128_t box_guid, ++ const char *const *exclude_mailboxes) + { + const enum mailbox_list_iter_flags list_flags = + /* FIXME: we'll skip symlinks, because we can't handle them +@@ -298,10 +329,12 @@ int dsync_mailbox_tree_fill(struct dsync_mailbox_tree *tree, + + /* first add all of the existing mailboxes */ + iter = mailbox_list_iter_init(ns->list, list_pattern, list_flags); +- while ((info = mailbox_list_iter_next(iter)) != NULL) { +- if (dsync_mailbox_tree_add(tree, info, box_guid) < 0) +- ret = -1; +- } ++ while ((info = mailbox_list_iter_next(iter)) != NULL) T_BEGIN { ++ if (!dsync_mailbox_info_is_excluded(info, exclude_mailboxes)) { ++ if (dsync_mailbox_tree_add(tree, info, box_guid) < 0) ++ ret = -1; ++ } ++ } T_END; + if (mailbox_list_iter_deinit(&iter) < 0) { + i_error("Mailbox listing for namespace '%s' failed", ns->prefix); + ret = -1; +diff --git a/src/doveadm/dsync/dsync-mailbox-tree.h b/src/doveadm/dsync/dsync-mailbox-tree.h +index 5a84b0e..956a570 100644 +--- a/src/doveadm/dsync/dsync-mailbox-tree.h ++++ b/src/doveadm/dsync/dsync-mailbox-tree.h +@@ -132,7 +132,8 @@ void dsync_mailbox_node_copy_data(struct dsync_mailbox_node *dest, + non-NULL, add only that mailbox to the tree. */ + int dsync_mailbox_tree_fill(struct dsync_mailbox_tree *tree, + struct mail_namespace *ns, const char *box_name, +- const guid_128_t box_guid); ++ const guid_128_t box_guid, ++ const char *const *exclude_mailboxes); + + /* Return all known deleted mailboxes and directories. */ + const struct dsync_mailbox_delete * +-- +1.7.10.2 +