virtual-sync.c revision d22301419109ed4a38351715e6760011421dadec
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen/* Copyright (c) 2008-2010 Dovecot authors, see the included COPYING file */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const char *const *kw_all;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* messages expunged within this sync */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ARRAY_DEFINE(all_adds, struct virtual_add_record);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic void virtual_sync_set_uidvalidity(struct virtual_sync_context *ctx)
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen offsetof(struct mail_index_header, uid_validity),
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic void virtual_sync_external_flags(struct virtual_sync_context *ctx,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const char *const *kw_names;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (!mail_set_uid(bbox->sync_mail, real_uid)) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* copy flags */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen mail_index_update_flags(ctx->trans, vseq, MODIFY_REPLACE, flags);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* copy keywords */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen kw_names = mail_get_keywords(bbox->sync_mail);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen keywords = mail_index_keywords_create(ctx->index, kw_names);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen mail_index_update_keywords(ctx->trans, vseq, MODIFY_REPLACE, keywords);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic int virtual_sync_mail_cmp(const void *p1, const void *p2)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const struct virtual_sync_mail *m1 = p1, *m2 = p2;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (m1->vrec.mailbox_id < m2->vrec.mailbox_id)
3d370bb6763ac4af4a0d143ad7c93300d5ddff89Timo Sirainen if (m1->vrec.mailbox_id > m2->vrec.mailbox_id)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenvirtual_backend_box_sync_mail_set(struct virtual_backend_box *bbox)
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen trans = mailbox_transaction_begin(bbox->box, 0);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenvirtual_backend_box_sync_mail_unset(struct virtual_backend_box *bbox)
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainenstatic int bbox_mailbox_id_cmp(struct virtual_backend_box *const *b1,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenvirtual_sync_get_backend_box(struct virtual_sync_context *ctx, const char *name,
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen *bbox_r = virtual_backend_box_lookup_name(ctx->mbox, name);
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen if (*bbox_r != NULL || !ctx->mbox->sync_initialized)
bd354c19cb93c07ade79477674328a54146ea332Timo Sirainen /* another process just added a new mailbox.
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen we can't handle this currently. */
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen mail_storage_set_error(ctx->mbox->box.storage, MAIL_ERROR_TEMP,
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen "Backend mailbox added by another session. "
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen "Reopen the virtual mailbox.");
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainenstatic int virtual_sync_ext_header_read(struct virtual_sync_context *ctx)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const struct virtual_mail_index_header *ext_hdr;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const struct virtual_mail_index_mailbox_record *mailboxes;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen unsigned int i, count, ext_name_offset, ext_mailbox_count;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen mail_index_get_header_ext(ctx->sync_view, ctx->mbox->virtual_ext_id,
3d370bb6763ac4af4a0d143ad7c93300d5ddff89Timo Sirainen ctx->mbox->prev_uid_validity == hdr->uid_validity &&
0af3274706d337b2930bd34f0377f2cc2dbcd18aTimo Sirainen ctx->mbox->prev_change_counter == ext_hdr->change_counter) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* fully refreshed */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ctx->mbox->prev_uid_validity = hdr->uid_validity;
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen ctx->mbox->search_args_crc32 != ext_hdr->search_args_crc32) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ctx->mbox->prev_change_counter = ext_hdr->change_counter;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ext_hdr->mailbox_count > INT_MAX/sizeof(*mailboxes)) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_error("virtual index %s: Broken mailbox_count header",
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen /* update mailbox backends */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen for (i = 0; i < ext_mailbox_count; i++) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (mailboxes[i].id > ext_hdr->highest_mailbox_id ||
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_error("virtual index %s: Broken mailbox id",
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen i_error("virtual index %s: Broken mailbox name_len",
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen if (ext_name_offset + mailboxes[i].name_len > ext_size) {
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen i_error("virtual index %s: Broken mailbox list",
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen const unsigned char *nameptr;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen nameptr = CONST_PTR_OFFSET(ext_data, ext_name_offset);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen name = t_strndup(nameptr, mailboxes[i].name_len);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen if (virtual_sync_get_backend_box(ctx, name, &bbox) < 0)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* mailbox no longer exists. */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen bbox->sync_uid_validity = mailboxes[i].uid_validity;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen bbox->sync_highest_modseq = mailboxes[i].highest_modseq;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ctx->mbox->highest_mailbox_id = ext_hdr == NULL ? 0 :
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* assign new mailbox IDs if any are missing */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen bboxes = array_get_modifiable(&ctx->mbox->backend_boxes, &count);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen for (i = 0; i < count; i++) {
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen bboxes[i]->mailbox_id = ++ctx->mbox->highest_mailbox_id;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* sort the backend mailboxes by mailbox_id. */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen array_sort(&ctx->mbox->backend_boxes, bbox_mailbox_id_cmp);
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainenstatic void virtual_sync_ext_header_rewrite(struct virtual_sync_context *ctx)
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen struct virtual_mail_index_mailbox_record mailbox;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen bboxes = array_get_modifiable(&ctx->mbox->backend_boxes, &count);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen name_pos = mailbox_pos + sizeof(mailbox) * count;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ext_hdr.change_counter = ++ctx->mbox->prev_change_counter;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ext_hdr.highest_mailbox_id = ctx->mbox->highest_mailbox_id;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ext_hdr.search_args_crc32 = ctx->mbox->search_args_crc32;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen buf = buffer_create_dynamic(pool_datastack_create(), name_pos + 256);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen buffer_append(buf, &ext_hdr, sizeof(ext_hdr));
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen for (i = 0; i < count; i++) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen bboxes[i]->mailbox_id > bboxes[i-1]->mailbox_id);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen mailbox.uid_validity = bboxes[i]->sync_uid_validity;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen mailbox.highest_modseq = bboxes[i]->sync_highest_modseq;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen buffer_write(buf, mailbox_pos, &mailbox, sizeof(mailbox));
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen buffer_write(buf, name_pos, bboxes[i]->name, mailbox.name_len);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen mail_index_get_header_ext(ctx->sync_view, ctx->mbox->virtual_ext_id,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen mail_index_ext_resize(ctx->trans, ctx->mbox->virtual_ext_id,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen mail_index_update_header_ext(ctx->trans, ctx->mbox->virtual_ext_id,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic void virtual_sync_ext_header_update(struct virtual_sync_context *ctx)
c1ebcdad1b4d950eb22219704dd9d64a89d0568fTimo Sirainen /* we changed something - update the change counter in header */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ext_hdr.change_counter = ++ctx->mbox->prev_change_counter;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen mail_index_update_header_ext(ctx->trans, ctx->mbox->virtual_ext_id,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen offsetof(struct virtual_mail_index_header, change_counter),
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen &ext_hdr.change_counter, sizeof(ext_hdr.change_counter));
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic void virtual_sync_index_rec(struct virtual_sync_context *ctx,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen uint32_t virtual_ext_id = ctx->mbox->virtual_ext_id;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* don't care */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (!mail_index_lookup_seq_range(ctx->sync_view,
c1ebcdad1b4d950eb22219704dd9d64a89d0568fTimo Sirainen /* already expunged, nothing to do. */
c1ebcdad1b4d950eb22219704dd9d64a89d0568fTimo Sirainen mail_index_lookup_ext(ctx->sync_view, vseq, virtual_ext_id,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen bbox = virtual_backend_box_lookup(ctx->mbox, vrec->mailbox_id);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (!mail_set_uid(bbox->sync_mail, vrec->real_uid)) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen /* message is already expunged from backend mailbox. */
c1ebcdad1b4d950eb22219704dd9d64a89d0568fTimo Sirainen flags = sync_rec->add_flags & MAIL_FLAGS_NONRECENT;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen flags = sync_rec->remove_flags & MAIL_FLAGS_NONRECENT;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen kw_names[0] = ctx->kw_all[sync_rec->keyword_idx];
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen keywords = mailbox_keywords_create_valid(bbox->box,
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen keywords = mailbox_keywords_create_valid(bbox->box,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen mail_update_keywords(bbox->sync_mail, MODIFY_REPLACE,
int ret;
return ret;
if (uid_count == 0)
i_unreached();
for (i = 0; i < uid_count; i++) {
&vseq))
if (uid_count == 0)
if (rec_count == 0 ||
&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;
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;
} 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;