virtual-sync.c revision e5601cd11edce275b4c423523bd00ee3e4eeae42
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2008-2009 Dovecot authors, see the included COPYING file */
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen const char *const *kw_all;
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen /* messages expunged within this sync */
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen ARRAY_DEFINE(all_adds, struct virtual_add_record);
942302b0247403645394d848b3c620ead262a2a5Timo Sirainenstatic void virtual_sync_set_uidvalidity(struct virtual_sync_context *ctx)
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen offsetof(struct mail_index_header, uid_validity),
942302b0247403645394d848b3c620ead262a2a5Timo Sirainenstatic void virtual_sync_external_flags(struct virtual_sync_context *ctx,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen const char *const *kw_names;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (!mail_set_uid(bbox->sync_mail, real_uid)) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* copy flags */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen mail_index_update_flags(ctx->trans, vseq, MODIFY_REPLACE, flags);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen /* copy keywords */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen kw_names = mail_get_keywords(bbox->sync_mail);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen keywords = mail_index_keywords_create(ctx->index, kw_names);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen mail_index_update_keywords(ctx->trans, vseq, MODIFY_REPLACE, keywords);
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenstatic int virtual_sync_mail_cmp(const void *p1, const void *p2)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen const struct virtual_sync_mail *m1 = p1, *m2 = p2;
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (m1->vrec.mailbox_id < m2->vrec.mailbox_id)
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen if (m1->vrec.mailbox_id > m2->vrec.mailbox_id)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvirtual_backend_box_sync_mail_set(struct virtual_backend_box *bbox)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen trans = mailbox_transaction_begin(bbox->box, 0);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvirtual_backend_box_sync_mail_unset(struct virtual_backend_box *bbox)
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainenstatic int bbox_mailbox_id_cmp(struct virtual_backend_box *const *b1,
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainenvirtual_sync_get_backend_box(struct virtual_sync_context *ctx, const char *name,
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen *bbox_r = virtual_backend_box_lookup_name(ctx->mbox, name);
755aea84bbe2b15ed7fe991f6462a93333ff571fTimo Sirainen if (*bbox_r != NULL || !ctx->mbox->sync_initialized)
755aea84bbe2b15ed7fe991f6462a93333ff571fTimo Sirainen /* another process just added a new mailbox.
755aea84bbe2b15ed7fe991f6462a93333ff571fTimo Sirainen we can't handle this currently. */
755aea84bbe2b15ed7fe991f6462a93333ff571fTimo Sirainen mail_storage_set_error(ctx->mbox->ibox.box.storage, MAIL_ERROR_TEMP,
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen "Backend mailbox added by another session. "
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen "Reopen the virtual mailbox.");
755aea84bbe2b15ed7fe991f6462a93333ff571fTimo Sirainenstatic int virtual_sync_ext_header_read(struct virtual_sync_context *ctx)
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen const struct virtual_mail_index_header *ext_hdr;
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen const struct virtual_mail_index_mailbox_record *mailboxes;
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen unsigned int i, count, ext_name_offset, ext_mailbox_count;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen mail_index_get_header_ext(ctx->sync_view, ctx->mbox->virtual_ext_id,
596433ccbca59ce2328dc1d029586154cd937155Timo Sirainen ctx->mbox->prev_uid_validity == hdr->uid_validity &&
4145cbac82bfc0c8bfeceeca0ef841700117930cTimo Sirainen ctx->mbox->prev_change_counter == ext_hdr->change_counter) {
4145cbac82bfc0c8bfeceeca0ef841700117930cTimo Sirainen /* fully refreshed */
e5fd6dfd0a492e4708d4dbb7971d7fc5d7b8fd85Timo Sirainen ctx->mbox->prev_uid_validity = hdr->uid_validity;
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainen ctx->mbox->search_args_crc32 != ext_hdr->search_args_crc32) {
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen ctx->mbox->prev_change_counter = ext_hdr->change_counter;
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen ext_hdr->mailbox_count > INT_MAX/sizeof(*mailboxes)) {
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen i_error("virtual index %s: Broken mailbox_count header",
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen /* update mailbox backends */
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen for (i = 0; i < ext_mailbox_count; i++) {
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen if (mailboxes[i].id > ext_hdr->highest_mailbox_id ||
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_error("virtual index %s: Broken mailbox id",
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_error("virtual index %s: Broken mailbox name_len",
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (ext_name_offset + mailboxes[i].name_len > ext_size) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen i_error("virtual index %s: Broken mailbox list",
c0a87e5f3316a57e6f915882fa1951d0fbb74a61Timo Sirainen const unsigned char *nameptr;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen nameptr = CONST_PTR_OFFSET(ext_data, ext_name_offset);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen name = t_strndup(nameptr, mailboxes[i].name_len);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen if (virtual_sync_get_backend_box(ctx, name, &bbox) < 0)
d22301419109ed4a38351715e6760011421dadecTimo Sirainen /* mailbox no longer exists. */
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen bbox->sync_uid_validity = mailboxes[i].uid_validity;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen bbox->sync_highest_modseq = mailboxes[i].highest_modseq;
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen ctx->mbox->highest_mailbox_id = ext_hdr == NULL ? 0 :
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen /* assign new mailbox IDs if any are missing */
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen bboxes = array_get_modifiable(&ctx->mbox->backend_boxes, &count);
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen for (i = 0; i < count; i++) {
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen bboxes[i]->mailbox_id = ++ctx->mbox->highest_mailbox_id;
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen /* sort the backend mailboxes by mailbox_id. */
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen array_sort(&ctx->mbox->backend_boxes, bbox_mailbox_id_cmp);
c4bb0320ab43ea35fa6df88fc745fdad906cee44Timo Sirainenstatic void virtual_sync_ext_header_rewrite(struct virtual_sync_context *ctx)
047e3bbb00e68a0d43355e11a67b2e912e06de19Timo Sirainen struct virtual_mail_index_mailbox_record mailbox;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen bboxes = array_get_modifiable(&ctx->mbox->backend_boxes, &count);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen name_pos = mailbox_pos + sizeof(mailbox) * count;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen ext_hdr.change_counter = ++ctx->mbox->prev_change_counter;
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen ext_hdr.highest_mailbox_id = ctx->mbox->highest_mailbox_id;
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen ext_hdr.search_args_crc32 = ctx->mbox->search_args_crc32;
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen buf = buffer_create_dynamic(pool_datastack_create(), name_pos + 256);
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen buffer_append(buf, &ext_hdr, sizeof(ext_hdr));
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen for (i = 0; i < count; i++) {
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen bboxes[i]->mailbox_id > bboxes[i-1]->mailbox_id);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen mailbox.uid_validity = bboxes[i]->sync_uid_validity;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen mailbox.highest_modseq = bboxes[i]->sync_highest_modseq;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen buffer_write(buf, mailbox_pos, &mailbox, sizeof(mailbox));
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen buffer_write(buf, name_pos, bboxes[i]->name, mailbox.name_len);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mail_index_get_header_ext(ctx->sync_view, ctx->mbox->virtual_ext_id,
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen mail_index_ext_resize(ctx->trans, ctx->mbox->virtual_ext_id,
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen mail_index_update_header_ext(ctx->trans, ctx->mbox->virtual_ext_id,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic void virtual_sync_ext_header_update(struct virtual_sync_context *ctx)
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen /* we changed something - update the change counter in header */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ext_hdr.change_counter = ++ctx->mbox->prev_change_counter;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen mail_index_update_header_ext(ctx->trans, ctx->mbox->virtual_ext_id,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen offsetof(struct virtual_mail_index_header, change_counter),
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen &ext_hdr.change_counter, sizeof(ext_hdr.change_counter));
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainenstatic void virtual_sync_index_rec(struct virtual_sync_context *ctx,
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen uint32_t virtual_ext_id = ctx->mbox->virtual_ext_id;
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen /* don't care */
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen if (!mail_index_lookup_seq_range(ctx->sync_view,
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen /* already expunged, nothing to do. */
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen mail_index_lookup_ext(ctx->sync_view, vseq, virtual_ext_id,
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen bbox = virtual_backend_box_lookup(ctx->mbox, vrec->mailbox_id);
206ed2f6fa3a6fb291498627b2da626581c07a18Timo Sirainen if (!mail_set_uid(bbox->sync_mail, vrec->real_uid))
77d8223da3da23b731257596abefa77e4485b77dTimo Sirainen flags = sync_rec->add_flags & MAIL_FLAGS_NONRECENT;
77d8223da3da23b731257596abefa77e4485b77dTimo Sirainen flags = sync_rec->remove_flags & MAIL_FLAGS_NONRECENT;
9438ecaf1caee1bb33c8d7f638742875ac42c4e5Timo Sirainen kw_names[0] = ctx->kw_all[sync_rec->keyword_idx];
77d8223da3da23b731257596abefa77e4485b77dTimo Sirainen keywords = mailbox_keywords_create_valid(bbox->box,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen keywords = mailbox_keywords_create_valid(bbox->box,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen mail_update_keywords(bbox->sync_mail, MODIFY_REPLACE,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenstatic void virtual_sync_index_changes(struct virtual_sync_context *ctx)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen keywords = mail_index_get_keywords(ctx->index);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen ctx->kw_all = array_count(keywords) == 0 ? NULL :
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen while (mail_index_sync_next(ctx->index_sync_ctx, &sync_rec))
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainenstatic void virtual_sync_index_finish(struct virtual_sync_context *ctx)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen /* mark the newly seen messages as recent */
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (mail_index_lookup_seq_range(ctx->sync_view, hdr->first_recent_uid,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen index_mailbox_set_recent_seq(&ctx->mbox->ibox, ctx->sync_view,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen /* entire mailbox list needs to be rewritten */
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen /* update only changed parts in the header */
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainenstatic int virtual_sync_backend_box_init(struct virtual_backend_box *bbox)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen enum mailbox_search_result_flags result_flags;
ecdce39e5ef4b62eefa9f5818f17d153fd5d710aTimo Sirainen trans = mailbox_transaction_begin(bbox->box, 0);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen search_ctx = mailbox_search_init(trans, bbox->search_args, NULL);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen /* save the result and keep it updated */
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen result_flags = MAILBOX_SEARCH_RESULT_FLAG_UPDATE |
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen mailbox_search_result_save(search_ctx, result_flags);
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen /* add the found UIDs to uidmap. virtual_uid gets assigned later. */
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainen while (mailbox_search_next(search_ctx, mail) > 0) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenvirtual_backend_uidmap_bsearch_cmp(const uint32_t *uidp,
c6afd726060aae56b6622c6c52aec10231c4bf1cTimo Sirainenvirtual_sync_mailbox_box_remove(struct virtual_sync_context *ctx,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen unsigned int i, src, dest, uid_count, rec_count;
047e3bbb00e68a0d43355e11a67b2e912e06de19Timo Sirainen /* everything in removed_uids should exist in bbox->uids */
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen uidmap = array_get_modifiable(&bbox->uids, &rec_count);
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen /* find the first uidmap record to be removed */
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen if (!array_bsearch_insert_pos(&bbox->uids, &uids[0].seq1,
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen /* remove the unwanted messages */
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen for (i = 0; i < uid_count; i++) {
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainenvirtual_sync_mailbox_box_add(struct virtual_sync_context *ctx,
1460ef7a18c53216ddb4a94bb62fba96076aae8eTimo Sirainen unsigned int i, src, dest, uid_count, add_count, rec_count;
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainen added_uids = array_get(added_uids_arr, &uid_count);
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen /* none of added_uids should exist in bbox->uids. find the position
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen of the first inserted index. */
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen uidmap = array_get_modifiable(&bbox->uids, &rec_count);
&dest))
i_unreached();
for (i = 0; i < uid_count; i++) {
unsigned int i, count;
for (i = 0; i < count; i++) {
const void *data;
bool expunged;
&seq)) {
old_msg_count = 0;
unsigned int i, n = 0, count;
if (i == count)
for (; i < count; ) {
unsigned int i, n = 0, count;
for (; i < count; ) {
if (!iter_done) {
&added_uids);
&temp_uids);
&removed_uids);
&removed_uids);
unsigned int *idx1_r,
unsigned int *idx2_r)
&idx);
return FALSE;
return TRUE;
&idx1);
case MAILBOX_SYNC_TYPE_FLAGS:
case MAILBOX_SYNC_TYPE_MODSEQ:
const unsigned int uidval_pos =
unsigned int mailbox_offset;
int ret;
&status) < 0)
} T_END;
return ret;
const void *data;
bool expunged;
unsigned int j = 0, uidmap_count = 0;
for (i = 0; i < messages; i++) {
for (; j < uidmap_count; j++) {
&uidmap_count);
for (; j < uidmap_count; j++) {
for (; j < uidmap_count; j++) {
for (i = 0; i < count; i++) {
for (j = 0; j < uidmap_count; j++) {
unsigned int i, count;
i_unreached();
if (count == 0) {
&idx))
i_unreached();
const void *data;
bool expunged;
const void *data;
bool expunged;
unsigned int i, count;
for (i = 0; i < count; i++) {
unsigned int i, count;
for (i = 0; i < count; i++)
if (success) {
return ret;
int ret;
if (ret <= 0) {
if (ret < 0)
return ret;
if (ret < 0)
if (ret == 0)
struct mailbox_sync_context *
int ret = 0;
return sync_ctx;