virtual-sync.c revision e8bff8f8293e741385bd96420010ee70f7f7c5d4
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2008 Dovecot authors, see the included COPYING file */
62ed3307fb8a4a038a32a5181c503f1b645bf946Stephan Bosch const char *const *kw_all;
62ed3307fb8a4a038a32a5181c503f1b645bf946Stephan Bosch /* messages expunged within this sync */
62ed3307fb8a4a038a32a5181c503f1b645bf946Stephan Bosch ARRAY_DEFINE(all_adds, struct virtual_add_record);
62ed3307fb8a4a038a32a5181c503f1b645bf946Stephan Boschstatic void virtual_sync_set_uidvalidity(struct virtual_sync_context *ctx)
62ed3307fb8a4a038a32a5181c503f1b645bf946Stephan Bosch offsetof(struct mail_index_header, uid_validity),
62ed3307fb8a4a038a32a5181c503f1b645bf946Stephan Boschstatic void virtual_sync_external_flags(struct virtual_sync_context *ctx,
62ed3307fb8a4a038a32a5181c503f1b645bf946Stephan Bosch const char *const *kw_names;
62ed3307fb8a4a038a32a5181c503f1b645bf946Stephan Bosch /* copy flags */
62ed3307fb8a4a038a32a5181c503f1b645bf946Stephan Bosch mail_index_update_flags(ctx->trans, vseq, MODIFY_REPLACE, flags);
62ed3307fb8a4a038a32a5181c503f1b645bf946Stephan Bosch /* copy keywords */
62ed3307fb8a4a038a32a5181c503f1b645bf946Stephan Bosch kw_names = mail_get_keywords(bbox->sync_mail);
62ed3307fb8a4a038a32a5181c503f1b645bf946Stephan Bosch keywords = mail_index_keywords_create(ctx->index, kw_names);
62ed3307fb8a4a038a32a5181c503f1b645bf946Stephan Bosch mail_index_update_keywords(ctx->trans, vseq, MODIFY_REPLACE, keywords);
62ed3307fb8a4a038a32a5181c503f1b645bf946Stephan Boschstatic int virtual_sync_mail_cmp(const void *p1, const void *p2)
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch const struct virtual_sync_mail *m1 = p1, *m2 = p2;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch if (m1->vrec.mailbox_id < m2->vrec.mailbox_id)
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch if (m1->vrec.mailbox_id > m2->vrec.mailbox_id)
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Boschvirtual_backend_box_sync_mail_set(struct virtual_backend_box *bbox)
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch trans = mailbox_transaction_begin(bbox->box, 0);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Boschvirtual_backend_box_sync_mail_unset(struct virtual_backend_box *bbox)
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Boschstatic int bbox_mailbox_id_cmp(const void *p1, const void *p2)
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch const struct virtual_backend_box *const *b1 = p1, *const *b2 = p2;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Boschstatic bool virtual_sync_ext_header_read(struct virtual_sync_context *ctx)
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch const struct virtual_mail_index_header *ext_hdr;
32f28ff765ef6983af0df78ebc5289b478abf3feStephan Bosch const struct virtual_mail_index_mailbox_record *mailboxes;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch unsigned int i, count, ext_name_offset, ext_mailbox_count;
32f28ff765ef6983af0df78ebc5289b478abf3feStephan Bosch mail_index_get_header_ext(ctx->sync_view, ctx->mbox->virtual_ext_id,
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch ctx->mbox->prev_uid_validity == hdr->uid_validity &&
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch ctx->mbox->prev_change_counter == ext_hdr->change_counter) {
72fc989c43a0dc94ec2f114b5e221beeab45519bTimo Sirainen /* fully refreshed */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch ctx->mbox->prev_uid_validity = hdr->uid_validity;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch ctx->mbox->search_args_crc32 != ext_hdr->search_args_crc32) {
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch ctx->mbox->prev_change_counter = ext_hdr->change_counter;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch ext_hdr->mailbox_count > INT_MAX/sizeof(*mailboxes)) {
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch i_error("virtual %s: Broken mailbox_count header",
32f28ff765ef6983af0df78ebc5289b478abf3feStephan Bosch /* update mailbox backends */
32f28ff765ef6983af0df78ebc5289b478abf3feStephan Bosch for (i = 0; i < ext_mailbox_count; i++) {
32f28ff765ef6983af0df78ebc5289b478abf3feStephan Bosch if (mailboxes[i].id > ext_hdr->highest_mailbox_id ||
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch i_error("virtual %s: Broken mailbox name_len",
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch if (ext_name_offset + mailboxes[i].name_len > ext_size) {
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch const unsigned char *nameptr;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch nameptr = CONST_PTR_OFFSET(ext_data, ext_name_offset);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch name = t_strndup(nameptr, mailboxes[i].name_len);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch bbox = virtual_backend_box_lookup_name(ctx->mbox, name);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* mailbox no longer exists */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch bbox->sync_uid_validity = mailboxes[i].uid_validity;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch bbox->sync_highest_modseq = mailboxes[i].highest_modseq;
b7e953d7eecd18f1d0de701cc181e8830d8167b1Stephan Bosch ctx->mbox->highest_mailbox_id = ext_hdr->highest_mailbox_id;
b7e953d7eecd18f1d0de701cc181e8830d8167b1Stephan Bosch /* assign new mailbox IDs if any are missing */
b7e953d7eecd18f1d0de701cc181e8830d8167b1Stephan Bosch bboxes = array_get_modifiable(&ctx->mbox->backend_boxes, &count);
b7e953d7eecd18f1d0de701cc181e8830d8167b1Stephan Bosch for (i = 0; i < count; i++) {
b7e953d7eecd18f1d0de701cc181e8830d8167b1Stephan Bosch bboxes[i]->mailbox_id = ++ctx->mbox->highest_mailbox_id;
b7e953d7eecd18f1d0de701cc181e8830d8167b1Stephan Bosch /* sort the backend mailboxes by mailbox_id. */
b7e953d7eecd18f1d0de701cc181e8830d8167b1Stephan Bosch qsort(bboxes, count, sizeof(*bboxes), bbox_mailbox_id_cmp);
b7e953d7eecd18f1d0de701cc181e8830d8167b1Stephan Boschstatic void virtual_sync_ext_header_rewrite(struct virtual_sync_context *ctx)
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch struct virtual_mail_index_mailbox_record mailbox;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch bboxes = array_get_modifiable(&ctx->mbox->backend_boxes, &count);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch name_pos = mailbox_pos + sizeof(mailbox) * count;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch ext_hdr.change_counter = ++ctx->mbox->prev_change_counter;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch ext_hdr.highest_mailbox_id = ctx->mbox->highest_mailbox_id;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch ext_hdr.search_args_crc32 = ctx->mbox->search_args_crc32;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch buf = buffer_create_dynamic(pool_datastack_create(), name_pos + 256);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch buffer_append(buf, &ext_hdr, sizeof(ext_hdr));
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch for (i = 0; i < count; i++) {
32f28ff765ef6983af0df78ebc5289b478abf3feStephan Bosch bboxes[i]->mailbox_id > bboxes[i-1]->mailbox_id);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch mailbox.uid_validity = bboxes[i]->sync_uid_validity;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch mailbox.highest_modseq = bboxes[i]->sync_highest_modseq;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch buffer_write(buf, mailbox_pos, &mailbox, sizeof(mailbox));
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch buffer_write(buf, name_pos, bboxes[i]->name, mailbox.name_len);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch mail_index_get_header_ext(ctx->sync_view, ctx->mbox->virtual_ext_id,
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch mail_index_ext_resize(ctx->trans, ctx->mbox->virtual_ext_id,
b4167b174b4eeebceaf80e240635e601f0a9860cStephan Bosch mail_index_update_header_ext(ctx->trans, ctx->mbox->virtual_ext_id,
b4167b174b4eeebceaf80e240635e601f0a9860cStephan Boschstatic void virtual_sync_ext_header_update(struct virtual_sync_context *ctx)
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* we changed something - update the change counter in header */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch ext_hdr.change_counter = ++ctx->mbox->prev_change_counter;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch mail_index_update_header_ext(ctx->trans, ctx->mbox->virtual_ext_id,
b4167b174b4eeebceaf80e240635e601f0a9860cStephan Bosch offsetof(struct virtual_mail_index_header, change_counter),
b4167b174b4eeebceaf80e240635e601f0a9860cStephan Bosch &ext_hdr.change_counter, sizeof(ext_hdr.change_counter));
7a545edbd1fca7a330bcb4a807002373ee18762aStephan Boschstatic void virtual_sync_index_rec(struct virtual_sync_context *ctx,
b4167b174b4eeebceaf80e240635e601f0a9860cStephan Bosch uint32_t virtual_ext_id = ctx->mbox->virtual_ext_id;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* don't care */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch if (!mail_index_lookup_seq_range(ctx->sync_view,
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* already expunged, nothing to do. */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch mail_index_lookup_ext(ctx->sync_view, vseq, virtual_ext_id,
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch bbox = virtual_backend_box_lookup(ctx->mbox, vrec->mailbox_id);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch if (!mail_set_uid(bbox->sync_mail, vrec->real_uid))
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch flags = sync_rec->add_flags & MAIL_FLAGS_NONRECENT;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch flags = sync_rec->remove_flags & MAIL_FLAGS_NONRECENT;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch kw_names[0] = ctx->kw_all[sync_rec->keyword_idx];
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch keywords = mailbox_keywords_create_valid(bbox->box,
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch keywords = mailbox_keywords_create_valid(bbox->box,
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch mail_update_keywords(bbox->sync_mail, MODIFY_REPLACE,
d3b0b5d2389acc43c75b63d2960daf82cf1f8aa7Stephan Boschstatic void virtual_sync_index_changes(struct virtual_sync_context *ctx)
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch keywords = mail_index_get_keywords(ctx->index);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch ctx->kw_all = array_count(keywords) == 0 ? NULL :
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch while (mail_index_sync_next(ctx->index_sync_ctx, &sync_rec))
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Boschstatic void virtual_sync_index_finish(struct virtual_sync_context *ctx)
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* mark the newly seen messages as recent */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch if (mail_index_lookup_seq_range(ctx->sync_view, hdr->first_recent_uid,
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch index_mailbox_set_recent_seq(&ctx->mbox->ibox, ctx->sync_view,
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* entire mailbox list needs to be rewritten */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* update only changed parts in the header */
d3b0b5d2389acc43c75b63d2960daf82cf1f8aa7Stephan Boschstatic int virtual_sync_backend_box_init(struct virtual_backend_box *bbox)
d3b0b5d2389acc43c75b63d2960daf82cf1f8aa7Stephan Bosch enum mailbox_search_result_flags result_flags;
d3b0b5d2389acc43c75b63d2960daf82cf1f8aa7Stephan Bosch trans = mailbox_transaction_begin(bbox->box, 0);
d3b0b5d2389acc43c75b63d2960daf82cf1f8aa7Stephan Bosch mail_search_args_init(bbox->search_args, bbox->box, FALSE, NULL);
d3b0b5d2389acc43c75b63d2960daf82cf1f8aa7Stephan Bosch search_ctx = mailbox_search_init(trans, bbox->search_args, NULL);
b0dfc8fc0dd5d08fe6a746e346dca6c737749d89Stephan Bosch /* save the result and keep it updated */
b0dfc8fc0dd5d08fe6a746e346dca6c737749d89Stephan Bosch result_flags = MAILBOX_SEARCH_RESULT_FLAG_UPDATE |
b0dfc8fc0dd5d08fe6a746e346dca6c737749d89Stephan Bosch mailbox_search_result_save(search_ctx, result_flags);
b0dfc8fc0dd5d08fe6a746e346dca6c737749d89Stephan Bosch /* add the found UIDs to uidmap. virtual_uid gets assigned later. */
b0dfc8fc0dd5d08fe6a746e346dca6c737749d89Stephan Bosch while (mailbox_search_next(search_ctx, mail) > 0) {
b0dfc8fc0dd5d08fe6a746e346dca6c737749d89Stephan Boschstatic int virtual_backend_uidmap_cmp(const void *p1, const void *p2)
b0dfc8fc0dd5d08fe6a746e346dca6c737749d89Stephan Bosch const struct virtual_backend_uidmap *u1 = p1, *u2 = p2;
b0dfc8fc0dd5d08fe6a746e346dca6c737749d89Stephan Boschvirtual_sync_backend_add_existing_uids(struct virtual_sync_context *ctx,
b0dfc8fc0dd5d08fe6a746e346dca6c737749d89Stephan Bosch /* add the currently existing UIDs to uidmap. */
b0dfc8fc0dd5d08fe6a746e346dca6c737749d89Stephan Bosch messages = mail_index_view_get_messages_count(ctx->sync_view);
b0dfc8fc0dd5d08fe6a746e346dca6c737749d89Stephan Bosch mail_index_lookup_uid(ctx->sync_view, vseq, &vuid);
b0dfc8fc0dd5d08fe6a746e346dca6c737749d89Stephan Bosch seq_range_array_add(&result->uids, 0, vrec->real_uid);
b0dfc8fc0dd5d08fe6a746e346dca6c737749d89Stephan Bosch /* the uidmap must be sorted by real_uids */
b0dfc8fc0dd5d08fe6a746e346dca6c737749d89Stephan Bosch uids = array_get_modifiable(&bbox->uids, &uid_count);
b0dfc8fc0dd5d08fe6a746e346dca6c737749d89Stephan Bosch qsort(uids, uid_count, sizeof(*uids), virtual_backend_uidmap_cmp);
b0dfc8fc0dd5d08fe6a746e346dca6c737749d89Stephan Boschvirtual_sync_backend_remove_expunged_uids(struct mail_search_result *result)
b0dfc8fc0dd5d08fe6a746e346dca6c737749d89Stephan Bosch struct index_mailbox *ibox = (struct index_mailbox *)result->box;
b0dfc8fc0dd5d08fe6a746e346dca6c737749d89Stephan Bosch unsigned int i, count;
b0dfc8fc0dd5d08fe6a746e346dca6c737749d89Stephan Bosch for (i = 0; i < count; i++) {
b0dfc8fc0dd5d08fe6a746e346dca6c737749d89Stephan Bosch for (uid = range[i].seq1; uid <= range[i].seq2; uid++) {
b0dfc8fc0dd5d08fe6a746e346dca6c737749d89Stephan Bosch if (!mail_index_lookup_seq(ibox->view, uid, &seq))
b0dfc8fc0dd5d08fe6a746e346dca6c737749d89Stephan Boschstatic int virtual_sync_backend_box_continue(struct virtual_sync_context *ctx,
b0dfc8fc0dd5d08fe6a746e346dca6c737749d89Stephan Bosch const enum mailbox_search_result_flags result_flags =
b0dfc8fc0dd5d08fe6a746e346dca6c737749d89Stephan Bosch struct index_mailbox *ibox = (struct index_mailbox *)bbox->box;
b0dfc8fc0dd5d08fe6a746e346dca6c737749d89Stephan Bosch /* build the initial search result from the existing UIDs */
b0dfc8fc0dd5d08fe6a746e346dca6c737749d89Stephan Bosch result = mailbox_search_result_alloc(bbox->box, bbox->search_args,
b0dfc8fc0dd5d08fe6a746e346dca6c737749d89Stephan Bosch virtual_sync_backend_add_existing_uids(ctx, bbox, result);
b0dfc8fc0dd5d08fe6a746e346dca6c737749d89Stephan Bosch /* changes done from now on must update the sync queue */
b0dfc8fc0dd5d08fe6a746e346dca6c737749d89Stephan Bosch virtual_sync_backend_remove_expunged_uids(result);
b0dfc8fc0dd5d08fe6a746e346dca6c737749d89Stephan Bosch /* get list of changed messages */
b0dfc8fc0dd5d08fe6a746e346dca6c737749d89Stephan Bosch !mail_index_lookup_seq_range(ibox->view, 1, bbox->sync_next_uid-1,
b0dfc8fc0dd5d08fe6a746e346dca6c737749d89Stephan Bosch t_array_init(&flag_updates, I_MIN(128, old_msg_count));
d3b0b5d2389acc43c75b63d2960daf82cf1f8aa7Stephan Bosch modseq = mail_index_modseq_lookup(ibox->view, seq);
8d2d2780c9e71581ff9c3e8bce527b492c295ec1Stephan Bosch if (index_search_result_update_flags(result, &flag_updates) < 0 ||
8d2d2780c9e71581ff9c3e8bce527b492c295ec1Stephan Bosch index_search_result_update_appends(result, old_msg_count) < 0) {
8d2d2780c9e71581ff9c3e8bce527b492c295ec1Stephan Boschstatic int virtual_backend_uidmap_bsearch_cmp(const void *key, const void *data)
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch const struct virtual_backend_uidmap *uidmap = data;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Boschvirtual_sync_mailbox_box_remove(struct virtual_sync_context *ctx,
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch unsigned int i, src, dest, uid_count, rec_count, left;
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* everything in removed_uids should exist in bbox->uids */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch uidmap = array_get_modifiable(&bbox->uids, &rec_count);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* find the first uidmap record to be removed */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch if (!bsearch_insert_pos(&uids[0].seq1, uidmap, rec_count,
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* remove the unwanted messages */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch for (i = src = dest = 0; i < uid_count; i++) {
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch array_delete(&bbox->uids, dest + left, src - dest);
d3b0b5d2389acc43c75b63d2960daf82cf1f8aa7Stephan Boschvirtual_sync_mailbox_box_add(struct virtual_sync_context *ctx,
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch unsigned int i, src, dest, uid_count, add_count, rec_count;
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch /* none of added_uids should exist in bbox->uids. find the position
8d2d2780c9e71581ff9c3e8bce527b492c295ec1Stephan Bosch of the first inserted index. */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch uidmap = array_get_modifiable(&bbox->uids, &rec_count);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch if (rec_count == 0 || uids[0].seq1 > uidmap[rec_count-1].real_uid) {
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* fast path: usually messages are appended */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch } else if (bsearch_insert_pos(&uids[0].seq1, uidmap, rec_count,
8d2d2780c9e71581ff9c3e8bce527b492c295ec1Stephan Bosch /* make space for all added UIDs. */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch uidmap = array_get_modifiable(&bbox->uids, &rec_count);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* add/move the UIDs to their correct positions */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch for (i = 0; i < uid_count; i++) {
8d2d2780c9e71581ff9c3e8bce527b492c295ec1Stephan Bosch while (src < rec_count && uidmap[src].real_uid < uid) {
f3cf2f02155c4bac23fd50f0de96c0cae9c46478Stephan Boschstatic void virtual_sync_mailbox_box_update(struct virtual_sync_context *ctx,
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch ARRAY_TYPE(seq_range) removed_uids, added_uids, temp_uids;
d3b0b5d2389acc43c75b63d2960daf82cf1f8aa7Stephan Bosch mailbox_search_result_sync(bbox->search_result,
7a545edbd1fca7a330bcb4a807002373ee18762aStephan Bosch /* if any of the pending removes came back, we don't want to expunge
7a545edbd1fca7a330bcb4a807002373ee18762aStephan Bosch them anymore. also since they already exist, remove them from
7a545edbd1fca7a330bcb4a807002373ee18762aStephan Bosch added_uids. */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch count1 = array_count(&bbox->sync_pending_removes);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch array_append_array(&temp_uids, &bbox->sync_pending_removes);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch &bbox->sync_pending_removes, &added_uids) > 0) {
009217abb57a24a4076092e8e4e165545747839eStephan Bosch /* delay removing messages that don't match the search
009217abb57a24a4076092e8e4e165545747839eStephan Bosch criteria, but don't delay removing expunged messages */
009217abb57a24a4076092e8e4e165545747839eStephan Bosch seq_range_array_remove_seq_range(&removed_uids,
009217abb57a24a4076092e8e4e165545747839eStephan Bosch seq_range_array_merge(&bbox->sync_pending_removes,
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch } else if (array_count(&bbox->sync_pending_removes) > 0) {
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* remove all current and old */
d3b0b5d2389acc43c75b63d2960daf82cf1f8aa7Stephan Bosch seq_range_array_merge(&bbox->sync_pending_removes,
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch virtual_sync_mailbox_box_remove(ctx, bbox, &removed_uids);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch virtual_sync_mailbox_box_add(ctx, bbox, &added_uids);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Boschstatic bool virtual_sync_find_seqs(struct virtual_backend_box *bbox,
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch unsigned int *idx1_r,
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch unsigned int *idx2_r)
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch struct index_mailbox *ibox = (struct index_mailbox *)bbox->box;
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch mail_index_lookup_uid(ibox->view, sync_rec->seq1, &uid1);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch mail_index_lookup_uid(ibox->view, sync_rec->seq2, &uid2);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch uidmap = array_get_modifiable(&bbox->uids, &count);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch (void)bsearch_insert_pos(&uid1, uidmap, count, sizeof(*uidmap),
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch if (idx == count || uidmap[idx].real_uid > uid2)
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch while (idx < count && uidmap[idx].real_uid <= uid2) idx++;
f3cf2f02155c4bac23fd50f0de96c0cae9c46478Stephan Boschstatic int virtual_sync_backend_box_sync(struct virtual_sync_context *ctx,
bcd6c13936df11167350ac86598a781dce9038c3Stephan Bosch sync_ctx = mailbox_sync_init(bbox->box, sync_flags);
bcd6c13936df11167350ac86598a781dce9038c3Stephan Bosch while (mailbox_sync_next(sync_ctx, &sync_rec)) {
bcd6c13936df11167350ac86598a781dce9038c3Stephan Bosch /* no need to keep track of expunges */
bcd6c13936df11167350ac86598a781dce9038c3Stephan Bosch seq_range_array_add_range(&ctx->sync_expunges,
df70bf8c997cd91452cdb3a5c2e20605d30446d2Stephan Bosch return mailbox_sync_deinit(&sync_ctx, 0, NULL);
d3b0b5d2389acc43c75b63d2960daf82cf1f8aa7Stephan Boschstatic void virtual_sync_backend_ext_header(struct virtual_sync_context *ctx,
d3b0b5d2389acc43c75b63d2960daf82cf1f8aa7Stephan Bosch const unsigned int uidval_pos =
d3b0b5d2389acc43c75b63d2960daf82cf1f8aa7Stephan Bosch offsetof(struct virtual_mail_index_mailbox_record,
d3b0b5d2389acc43c75b63d2960daf82cf1f8aa7Stephan Bosch struct virtual_mail_index_mailbox_record mailbox;
d3b0b5d2389acc43c75b63d2960daf82cf1f8aa7Stephan Bosch mailbox_get_status(bbox->box, STATUS_UIDVALIDITY |
d3b0b5d2389acc43c75b63d2960daf82cf1f8aa7Stephan Bosch if (bbox->sync_uid_validity == status.uidvalidity &&
d3b0b5d2389acc43c75b63d2960daf82cf1f8aa7Stephan Bosch bbox->sync_highest_modseq == status.highest_modseq)
d3b0b5d2389acc43c75b63d2960daf82cf1f8aa7Stephan Bosch /* mailbox changed - update extension header */
d3b0b5d2389acc43c75b63d2960daf82cf1f8aa7Stephan Bosch bbox->sync_highest_modseq = status.highest_modseq;
d3b0b5d2389acc43c75b63d2960daf82cf1f8aa7Stephan Bosch /* we'll rewrite the entire header later */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch mailbox.uid_validity = bbox->sync_uid_validity;
61f962e8f32a4870d08fb6f2189fdf6a10fd1abbStephan Bosch mailbox.highest_modseq = bbox->sync_highest_modseq;
61f962e8f32a4870d08fb6f2189fdf6a10fd1abbStephan Bosch mailbox_offset = sizeof(struct virtual_mail_index_header) +
61f962e8f32a4870d08fb6f2189fdf6a10fd1abbStephan Bosch mail_index_update_header_ext(ctx->trans, ctx->mbox->virtual_ext_id,
61f962e8f32a4870d08fb6f2189fdf6a10fd1abbStephan Boschstatic int virtual_sync_backend_box(struct virtual_sync_context *ctx,
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch struct index_mailbox *ibox = (struct index_mailbox *)bbox->box;
dbbdcc1224f81a40e746a09e6d44af7c4f24ff71Stephan Bosch /* if we already did some changes to index, commit them before
dbbdcc1224f81a40e746a09e6d44af7c4f24ff71Stephan Bosch syncing starts. */
61f962e8f32a4870d08fb6f2189fdf6a10fd1abbStephan Bosch /* we use modseqs for speeding up initial search result build.
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch make sure the backend has them enabled. */
61f962e8f32a4870d08fb6f2189fdf6a10fd1abbStephan Bosch sync_flags = ctx->flags & (MAILBOX_SYNC_FLAG_FULL_READ |
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* first sync in this process */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch if (mailbox_sync(bbox->box, sync_flags, STATUS_UIDVALIDITY,
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch if (status.uidvalidity != bbox->sync_uid_validity) {
7a545edbd1fca7a330bcb4a807002373ee18762aStephan Bosch /* UID validity changed since last sync (or this is
7a545edbd1fca7a330bcb4a807002373ee18762aStephan Bosch the first sync), do a full search */
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch /* build the initial search using the saved modseq.
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch we can't directly update the search result because
05262e3132642bbdc4a8087c17b0903cf2ff22d2Stephan Bosch uidmap isn't finished for all messages yet, so
05262e3132642bbdc4a8087c17b0903cf2ff22d2Stephan Bosch mark the sync to be retried. */
05262e3132642bbdc4a8087c17b0903cf2ff22d2Stephan Bosch ret = virtual_sync_backend_box_continue(ctx, bbox);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* sync using the existing search result */
05262e3132642bbdc4a8087c17b0903cf2ff22d2Stephan Bosch ret = virtual_sync_backend_box_sync(ctx, bbox, sync_flags);
05262e3132642bbdc4a8087c17b0903cf2ff22d2Stephan Boschstatic void virtual_sync_backend_map_uids(struct virtual_sync_context *ctx)
05262e3132642bbdc4a8087c17b0903cf2ff22d2Stephan Bosch uint32_t virtual_ext_id = ctx->mbox->virtual_ext_id;
7a545edbd1fca7a330bcb4a807002373ee18762aStephan Bosch struct virtual_backend_box *bbox, *const *bboxes;
05262e3132642bbdc4a8087c17b0903cf2ff22d2Stephan Bosch unsigned int j = 0, uidmap_count = 0;
05262e3132642bbdc4a8087c17b0903cf2ff22d2Stephan Bosch messages = mail_index_view_get_messages_count(ctx->sync_view);
05262e3132642bbdc4a8087c17b0903cf2ff22d2Stephan Bosch /* sort the messages in current view by their backend mailbox and
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch mail_index_lookup_ext(ctx->sync_view, vseq, virtual_ext_id,
7a545edbd1fca7a330bcb4a807002373ee18762aStephan Bosch qsort(vmails, messages, sizeof(*vmails), virtual_sync_mail_cmp);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* create real mailbox uid -> virtual uid mapping and expunge
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch messages no longer matching the search rule */
05262e3132642bbdc4a8087c17b0903cf2ff22d2Stephan Bosch for (i = 0; i < messages; i++) {
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch if (bbox == NULL || bbox->mailbox_id != vrec->mailbox_id) {
7a545edbd1fca7a330bcb4a807002373ee18762aStephan Bosch /* add the rest of the newly seen messages */
7a545edbd1fca7a330bcb4a807002373ee18762aStephan Bosch for (; j < uidmap_count; j++) {
05262e3132642bbdc4a8087c17b0903cf2ff22d2Stephan Bosch /* the entire mailbox is lost */
05262e3132642bbdc4a8087c17b0903cf2ff22d2Stephan Bosch mail_index_lookup_uid(ctx->sync_view, vseq, &vuid);
bcd6c13936df11167350ac86598a781dce9038c3Stephan Bosch /* if virtual record doesn't exist in uidmap, it's expunged */
bcd6c13936df11167350ac86598a781dce9038c3Stephan Bosch for (; j < uidmap_count; j++) {
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* newly seen message */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* exists - update uidmap and flags */
61f962e8f32a4870d08fb6f2189fdf6a10fd1abbStephan Bosch /* if there are any mailboxes we didn't yet sync, add new messages in
61f962e8f32a4870d08fb6f2189fdf6a10fd1abbStephan Bosch bboxes = array_get(&ctx->mbox->backend_boxes, &count);
61f962e8f32a4870d08fb6f2189fdf6a10fd1abbStephan Bosch for (i = 0; i < count; i++) {
61f962e8f32a4870d08fb6f2189fdf6a10fd1abbStephan Bosch add_rec.rec.mailbox_id = bboxes[i]->mailbox_id;
61f962e8f32a4870d08fb6f2189fdf6a10fd1abbStephan Bosch uidmap = array_get_modifiable(&bboxes[i]->uids, &uidmap_count);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch for (j = 0; j < uidmap_count; j++) {
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Boschstatic int virtual_add_record_cmp(const void *p1, const void *p2)
bcd6c13936df11167350ac86598a781dce9038c3Stephan Bosch const struct virtual_add_record *add1 = p1, *add2 = p2;
bcd6c13936df11167350ac86598a781dce9038c3Stephan Bosch if (add1->received_date < add2->received_date)
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch if (add1->received_date > add2->received_date)
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* if they're in same mailbox, we can order them correctly by the UID.
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch if they're in different mailboxes, ordering by UID doesn't really
639bb36b12b9f9bb54c8bb1be50eac623622f8a0Timo Sirainen help but it doesn't really harm either. */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* two messages in different mailboxes have the same received date
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Boschstatic void virtual_sync_backend_sort_new(struct virtual_sync_context *ctx)
61f962e8f32a4870d08fb6f2189fdf6a10fd1abbStephan Bosch unsigned int i, count;
61f962e8f32a4870d08fb6f2189fdf6a10fd1abbStephan Bosch /* get all messages' received dates */
61f962e8f32a4870d08fb6f2189fdf6a10fd1abbStephan Bosch adds = array_get_modifiable(&ctx->all_adds, &count);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch if (bbox == NULL || bbox->mailbox_id != vrec->mailbox_id) {
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch if (!mail_set_uid(bbox->sync_mail, vrec->real_uid))
61f962e8f32a4870d08fb6f2189fdf6a10fd1abbStephan Bosch /* probably expunged already, just add it somewhere */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch qsort(adds, count, sizeof(*adds), virtual_add_record_cmp);
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Boschstatic void virtual_sync_backend_add_new(struct virtual_sync_context *ctx)
a643e1e3e5d9d8a60eeff83601f86ee00c26332aStephan Bosch uint32_t virtual_ext_id = ctx->mbox->virtual_ext_id;
a643e1e3e5d9d8a60eeff83601f86ee00c26332aStephan Bosch adds = array_get_modifiable(&ctx->all_adds, &count);
a643e1e3e5d9d8a60eeff83601f86ee00c26332aStephan Bosch if (adds[0].rec.mailbox_id == adds[count-1].rec.mailbox_id) {
a643e1e3e5d9d8a60eeff83601f86ee00c26332aStephan Bosch /* all messages are from a single mailbox. add them in
a643e1e3e5d9d8a60eeff83601f86ee00c26332aStephan Bosch the same order. */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch /* sort new messages by received date to get the add order */
8fe8f97e688779add9cd042a9db4ddb7b117cce2Stephan Bosch if (bbox == NULL || bbox->mailbox_id != vrec->mailbox_id) {
458d877d84f62005e0ffc338f8591a8e2a36adadStephan Bosch mail_index_update_ext(ctx->trans, vseq, virtual_ext_id,
458d877d84f62005e0ffc338f8591a8e2a36adadStephan Bosch virtual_sync_external_flags(ctx, bbox, vseq, vrec->real_uid);
458d877d84f62005e0ffc338f8591a8e2a36adadStephan Bosch /* assign UIDs to new messages */
458d877d84f62005e0ffc338f8591a8e2a36adadStephan Bosch first_uid = mail_index_get_header(ctx->sync_view)->next_uid;
458d877d84f62005e0ffc338f8591a8e2a36adadStephan Bosch mail_index_append_assign_uids(ctx->trans, first_uid, &next_uid);
458d877d84f62005e0ffc338f8591a8e2a36adadStephan Bosch /* update virtual UIDs in uidmap */
458d877d84f62005e0ffc338f8591a8e2a36adadStephan Bosch if (bbox == NULL || bbox->mailbox_id != vrec->mailbox_id) {
458d877d84f62005e0ffc338f8591a8e2a36adadStephan Bosch uidmap = array_get_modifiable(&bbox->uids, &uid_count);
458d877d84f62005e0ffc338f8591a8e2a36adadStephan Bosch if (!bsearch_insert_pos(&vrec->real_uid, uidmap, uid_count,
458d877d84f62005e0ffc338f8591a8e2a36adadStephan Boschstatic int virtual_sync_backend_boxes(struct virtual_sync_context *ctx)
458d877d84f62005e0ffc338f8591a8e2a36adadStephan Bosch unsigned int i, count;
458d877d84f62005e0ffc338f8591a8e2a36adadStephan Bosch bboxes = array_get(&ctx->mbox->backend_boxes, &count);
458d877d84f62005e0ffc338f8591a8e2a36adadStephan Bosch for (i = 0; i < count; i++) {
458d877d84f62005e0ffc338f8591a8e2a36adadStephan Bosch if (virtual_sync_backend_box(ctx, bboxes[i]) < 0)
458d877d84f62005e0ffc338f8591a8e2a36adadStephan Bosch /* initial sync: assign virtual UIDs to existing messages and
458d877d84f62005e0ffc338f8591a8e2a36adadStephan Bosch sync all flags */
458d877d84f62005e0ffc338f8591a8e2a36adadStephan Boschstatic void virtual_sync_backend_boxes_finish(struct virtual_sync_context *ctx)
458d877d84f62005e0ffc338f8591a8e2a36adadStephan Bosch unsigned int i, count;
458d877d84f62005e0ffc338f8591a8e2a36adadStephan Bosch bboxes = array_get(&ctx->mbox->backend_boxes, &count);
458d877d84f62005e0ffc338f8591a8e2a36adadStephan Bosch for (i = 0; i < count; i++)
458d877d84f62005e0ffc338f8591a8e2a36adadStephan Bosch virtual_backend_box_sync_mail_unset(bboxes[i]);
8d2d2780c9e71581ff9c3e8bce527b492c295ec1Stephan Boschstatic int virtual_sync_finish(struct virtual_sync_context *ctx, bool success)
8d2d2780c9e71581ff9c3e8bce527b492c295ec1Stephan Bosch if (mail_index_sync_commit(&ctx->index_sync_ctx) < 0) {
8d2d2780c9e71581ff9c3e8bce527b492c295ec1Stephan Bosch mail_storage_set_index_error(&ctx->mbox->ibox);
8d2d2780c9e71581ff9c3e8bce527b492c295ec1Stephan Bosch mail_index_sync_rollback(&ctx->index_sync_ctx);
8d2d2780c9e71581ff9c3e8bce527b492c295ec1Stephan Boschstatic int virtual_sync(struct virtual_mailbox *mbox,
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch /* Removed messages are expunged when
458d877d84f62005e0ffc338f8591a8e2a36adadStephan Bosch a) EXPUNGE is used
458d877d84f62005e0ffc338f8591a8e2a36adadStephan Bosch b) Mailbox is being opened (FIX_INCONSISTENT is set) */
458d877d84f62005e0ffc338f8591a8e2a36adadStephan Bosch index_sync_flags = MAIL_INDEX_SYNC_FLAG_FLUSH_DIRTY |
458d877d84f62005e0ffc338f8591a8e2a36adadStephan Bosch index_sync_flags |= MAIL_INDEX_SYNC_FLAG_DROP_RECENT;
458d877d84f62005e0ffc338f8591a8e2a36adadStephan Bosch ret = mail_index_sync_begin(ctx->index, &ctx->index_sync_ctx,
e4e9ba5f43f9bf7e072d7d9fcc3259a42ecb15c8Stephan Bosch /* apply changes from virtual index to backend mailboxes */
af53c056cf1e3d133a78c201e72a678b5431d0fbStephan Bosch /* update list of UIDs in backend mailboxes */
af53c056cf1e3d133a78c201e72a678b5431d0fbStephan Boschvirtual_storage_sync_init(struct mailbox *box, enum mailbox_sync_flags flags)
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch struct virtual_mailbox *mbox = (struct virtual_mailbox *)box;
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch if (index_mailbox_want_full_sync(&mbox->ibox, flags))