virtual-sync.c revision ce930f99c6a78f2c74b00df1ad2337095978a9db
bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2008-2014 Dovecot authors, see the included COPYING file */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "lib.h"
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen#include "array.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "bsearch-insert-pos.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "ioloop.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "str.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "mail-index-modseq.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "mail-search-build.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "mailbox-search-result-private.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "index-sync-private.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "index-search-result.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include "virtual-storage.h"
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch#include <stdlib.h>
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
e9c433c5b8ef9a1b4246ebe10beb90fa01e05cafPhil Carmodystruct virtual_add_record {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct virtual_mail_index_record rec;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch time_t received_date;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch};
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstruct virtual_sync_mail {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uint32_t vseq;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct virtual_mail_index_record vrec;
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch};
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstruct virtual_sync_context {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct virtual_mailbox *mbox;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct mail_index_sync_ctx *index_sync_ctx;
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch struct mail_index *index;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct mail_index_view *sync_view;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct mail_index_transaction *trans;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const char *const *kw_all;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* messages expunged within this sync */
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch ARRAY_TYPE(seq_range) sync_expunges;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ARRAY(struct virtual_add_record) all_adds;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* all messages in this sync, sorted by mailbox_id
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch (but unsorted inside it for now, since it doesn't matter) */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ARRAY(struct virtual_sync_mail) all_mails;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uint32_t all_mails_idx, all_mails_prev_mailbox_id;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch enum mailbox_sync_flags flags;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uint32_t uid_validity;
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch unsigned int ext_header_changed:1;
f883bf3eff62f5d27df5ee9ee664edc38a77937fStephan Bosch unsigned int ext_header_rewrite:1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch unsigned int expunge_removed:1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch unsigned int index_broken:1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch};
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Boschstatic void virtual_sync_set_uidvalidity(struct virtual_sync_context *ctx)
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch{
f883bf3eff62f5d27df5ee9ee664edc38a77937fStephan Bosch uint32_t uid_validity = ioloop_time;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch mail_index_update_header(ctx->trans,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch offsetof(struct mail_index_header, uid_validity),
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch &uid_validity, sizeof(uid_validity), TRUE);
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch ctx->uid_validity = uid_validity;
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch}
f883bf3eff62f5d27df5ee9ee664edc38a77937fStephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic void virtual_sync_external_flags(struct virtual_sync_context *ctx,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct virtual_backend_box *bbox,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uint32_t vseq, uint32_t real_uid)
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch enum mail_flags flags;
f883bf3eff62f5d27df5ee9ee664edc38a77937fStephan Bosch const char *const *kw_names;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct mail_keywords *keywords;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (!mail_set_uid(bbox->sync_mail, real_uid)) {
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch /* we may have reopened the mailbox, which could have
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch caused the mail to be expunged already. */
f883bf3eff62f5d27df5ee9ee664edc38a77937fStephan Bosch return;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* copy flags */
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch flags = mail_get_flags(bbox->sync_mail);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch mail_index_update_flags(ctx->trans, vseq, MODIFY_REPLACE, flags);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* copy keywords */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch kw_names = mail_get_keywords(bbox->sync_mail);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch keywords = mail_index_keywords_create(ctx->index, kw_names);
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch mail_index_update_keywords(ctx->trans, vseq, MODIFY_REPLACE, keywords);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch mail_index_keywords_unref(&keywords);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic int virtual_sync_mail_uid_cmp(const void *p1, const void *p2)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch const struct virtual_sync_mail *m1 = p1, *m2 = p2;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (m1->vrec.mailbox_id < m2->vrec.mailbox_id)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (m1->vrec.mailbox_id > m2->vrec.mailbox_id)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return 1;
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (m1->vrec.real_uid < m2->vrec.real_uid)
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (m1->vrec.real_uid > m2->vrec.real_uid)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return 1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* broken */
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch return 0;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic void
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschvirtual_backend_box_sync_mail_set(struct virtual_backend_box *bbox)
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct mailbox_transaction_context *trans;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (bbox->sync_mail == NULL) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch trans = mailbox_transaction_begin(bbox->box, 0);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch bbox->sync_mail = mail_alloc(trans, 0, NULL);
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic int bbox_mailbox_id_cmp(struct virtual_backend_box *const *b1,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct virtual_backend_box *const *b2)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch if ((*b1)->mailbox_id < (*b2)->mailbox_id)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if ((*b1)->mailbox_id > (*b2)->mailbox_id)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return 1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return 0;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic int
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschvirtual_sync_get_backend_box(struct virtual_sync_context *ctx, const char *name,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct virtual_backend_box **bbox_r)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch *bbox_r = virtual_backend_box_lookup_name(ctx->mbox, name);
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch if (*bbox_r != NULL || !ctx->mbox->sync_initialized)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return 0;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* another process just added a new mailbox.
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch we can't handle this currently. */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ctx->mbox->inconsistent = TRUE;
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch mail_storage_set_error(ctx->mbox->box.storage, MAIL_ERROR_TEMP,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch "Backend mailbox added by another session. "
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch "Reopen the virtual mailbox.");
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Boschstatic int virtual_sync_ext_header_read(struct virtual_sync_context *ctx)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const char *box_path = mailbox_get_path(&ctx->mbox->box);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const struct virtual_mail_index_header *ext_hdr;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const struct mail_index_header *hdr;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const struct virtual_mail_index_mailbox_record *mailboxes;
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch struct virtual_backend_box *bbox, **bboxes;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const void *ext_data;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch size_t ext_size;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch unsigned int i, count, ext_name_offset, ext_mailbox_count;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uint32_t prev_mailbox_id;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch int ret = 1;
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch hdr = mail_index_get_header(ctx->sync_view);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch mail_index_get_header_ext(ctx->sync_view, ctx->mbox->virtual_ext_id,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch &ext_data, &ext_size);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ext_hdr = ext_data;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (ctx->mbox->sync_initialized &&
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch ctx->mbox->prev_uid_validity == hdr->uid_validity &&
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ext_size >= sizeof(*ext_hdr) &&
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ctx->mbox->prev_change_counter == ext_hdr->change_counter) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* fully refreshed */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return 1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch ctx->mbox->prev_uid_validity = hdr->uid_validity;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (ext_hdr == NULL ||
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ctx->mbox->search_args_crc32 != ext_hdr->search_args_crc32) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch mailboxes = NULL;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ext_name_offset = 0;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ext_mailbox_count = 0;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch } else {
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch ctx->mbox->prev_change_counter = ext_hdr->change_counter;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch mailboxes = (const void *)(ext_hdr + 1);
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch ext_name_offset = sizeof(*ext_hdr) +
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ext_hdr->mailbox_count * sizeof(*mailboxes);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (ext_name_offset >= ext_size ||
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ext_hdr->mailbox_count > INT_MAX/sizeof(*mailboxes)) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch i_error("virtual index %s: Broken mailbox_count header",
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch box_path);
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch ctx->index_broken = TRUE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ext_mailbox_count = 0;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ret = 0;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch } else {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ext_mailbox_count = ext_hdr->mailbox_count;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch /* update mailbox backends */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch prev_mailbox_id = 0;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch for (i = 0; i < ext_mailbox_count; i++) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (mailboxes[i].id > ext_hdr->highest_mailbox_id ||
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch mailboxes[i].id <= prev_mailbox_id) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch i_error("virtual index %s: Broken mailbox id",
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch box_path);
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch break;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (mailboxes[i].name_len == 0 ||
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch mailboxes[i].name_len > ext_size) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch i_error("virtual index %s: Broken mailbox name_len",
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch box_path);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch break;
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (ext_name_offset + mailboxes[i].name_len > ext_size) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch i_error("virtual index %s: Broken mailbox list",
17c29e3e2246972c3d988e05d91b9286398a624fStephan Bosch box_path);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch break;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch T_BEGIN {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const unsigned char *nameptr;
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch const char *name;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch nameptr = CONST_PTR_OFFSET(ext_data, ext_name_offset);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch name = t_strndup(nameptr, mailboxes[i].name_len);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (virtual_sync_get_backend_box(ctx, name, &bbox) < 0)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ret = -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch } T_END;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch if (bbox == NULL) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (ret < 0)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* mailbox no longer exists. */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ret = 0;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch } else {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch bbox->mailbox_id = mailboxes[i].id;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch bbox->sync_uid_validity = mailboxes[i].uid_validity;
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch bbox->ondisk_highest_modseq =
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch bbox->sync_highest_modseq =
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch mailboxes[i].highest_modseq;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch bbox->sync_next_uid = mailboxes[i].next_uid;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch bbox->sync_mailbox_idx = i;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ext_name_offset += mailboxes[i].name_len;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch prev_mailbox_id = mailboxes[i].id;
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (i < ext_mailbox_count) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ctx->index_broken = TRUE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ret = 0;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ctx->mbox->highest_mailbox_id = ext_hdr == NULL ? 0 :
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ext_hdr->highest_mailbox_id;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ctx->mbox->sync_initialized = TRUE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch /* assign new mailbox IDs if any are missing */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch bboxes = array_get_modifiable(&ctx->mbox->backend_boxes, &count);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch for (i = 0; i < count; i++) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (bboxes[i]->mailbox_id == 0) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch bboxes[i]->mailbox_id = ++ctx->mbox->highest_mailbox_id;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ret = 0;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* sort the backend mailboxes by mailbox_id. */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch array_sort(&ctx->mbox->backend_boxes, bbox_mailbox_id_cmp);
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch return ret;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic void virtual_sync_ext_header_rewrite(struct virtual_sync_context *ctx)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct virtual_mail_index_header ext_hdr;
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch struct virtual_mail_index_mailbox_record mailbox;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct virtual_backend_box **bboxes;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch buffer_t *buf;
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch const void *ext_data;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch size_t ext_size;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch unsigned int i, mailbox_pos, name_pos, count;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch bboxes = array_get_modifiable(&ctx->mbox->backend_boxes, &count);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch mailbox_pos = sizeof(ext_hdr);
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch name_pos = mailbox_pos + sizeof(mailbox) * count;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch memset(&ext_hdr, 0, sizeof(ext_hdr));
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch memset(&mailbox, 0, sizeof(mailbox));
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ext_hdr.change_counter = ++ctx->mbox->prev_change_counter;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ext_hdr.mailbox_count = count;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ext_hdr.highest_mailbox_id = ctx->mbox->highest_mailbox_id;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ext_hdr.search_args_crc32 = ctx->mbox->search_args_crc32;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch buf = buffer_create_dynamic(pool_datastack_create(), name_pos + 256);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch buffer_append(buf, &ext_hdr, sizeof(ext_hdr));
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch for (i = 0; i < count; i++) {
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch i_assert(i == 0 ||
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch bboxes[i]->mailbox_id > bboxes[i-1]->mailbox_id);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch bboxes[i]->sync_mailbox_idx = i;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch mailbox.id = bboxes[i]->mailbox_id;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch mailbox.name_len = strlen(bboxes[i]->name);
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch mailbox.uid_validity = bboxes[i]->sync_uid_validity;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch mailbox.highest_modseq = bboxes[i]->ondisk_highest_modseq;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch mailbox.next_uid = bboxes[i]->sync_next_uid;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch buffer_write(buf, mailbox_pos, &mailbox, sizeof(mailbox));
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch buffer_write(buf, name_pos, bboxes[i]->name, mailbox.name_len);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch mailbox_pos += sizeof(mailbox);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch name_pos += mailbox.name_len;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch i_assert(buf->used == name_pos);
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch mail_index_get_header_ext(ctx->sync_view, ctx->mbox->virtual_ext_id,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch &ext_data, &ext_size);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (ext_size < name_pos) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch mail_index_ext_resize(ctx->trans, ctx->mbox->virtual_ext_id,
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch name_pos,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch sizeof(struct virtual_mail_index_record),
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch sizeof(uint32_t));
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch mail_index_update_header_ext(ctx->trans, ctx->mbox->virtual_ext_id,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch 0, buf->data, name_pos);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic void virtual_sync_ext_header_update(struct virtual_sync_context *ctx)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct virtual_mail_index_header ext_hdr;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch if (!ctx->ext_header_changed)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* we changed something - update the change counter in header */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ext_hdr.change_counter = ++ctx->mbox->prev_change_counter;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch mail_index_update_header_ext(ctx->trans, ctx->mbox->virtual_ext_id,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch offsetof(struct virtual_mail_index_header, change_counter),
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch &ext_hdr.change_counter, sizeof(ext_hdr.change_counter));
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic int virtual_sync_index_rec(struct virtual_sync_context *ctx,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const struct mail_index_sync_rec *sync_rec)
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uint32_t virtual_ext_id = ctx->mbox->virtual_ext_id;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct virtual_backend_box *bbox;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const struct virtual_mail_index_record *vrec;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const void *data;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch enum mail_flags flags;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct mail_keywords *keywords;
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch enum modify_type modify_type;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const char *kw_names[2];
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uint32_t vseq, seq1, seq2;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch switch (sync_rec->type) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch case MAIL_INDEX_SYNC_TYPE_EXPUNGE:
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch case MAIL_INDEX_SYNC_TYPE_FLAGS:
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch case MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD:
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch case MAIL_INDEX_SYNC_TYPE_KEYWORD_REMOVE:
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch break;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (!mail_index_lookup_seq_range(ctx->sync_view,
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch sync_rec->uid1, sync_rec->uid2,
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch &seq1, &seq2)) {
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch /* already expunged, nothing to do. */
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch return 0;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch }
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch for (vseq = seq1; vseq <= seq2; vseq++) {
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch mail_index_lookup_ext(ctx->sync_view, vseq, virtual_ext_id,
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch &data, NULL);
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch vrec = data;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch bbox = virtual_backend_box_lookup(ctx->mbox, vrec->mailbox_id);
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (bbox == NULL)
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch continue;
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch if (!bbox->box->opened) {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (virtual_backend_box_open(ctx->mbox, bbox) < 0) {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch virtual_box_copy_error(&ctx->mbox->box,
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch bbox->box);
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch return -1;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch }
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch } else {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch virtual_backend_box_accessed(ctx->mbox, bbox);
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch }
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch virtual_backend_box_sync_mail_set(bbox);
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (!mail_set_uid(bbox->sync_mail, vrec->real_uid)) {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch /* message is already expunged from backend mailbox. */
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch continue;
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch }
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch switch (sync_rec->type) {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch case MAIL_INDEX_SYNC_TYPE_EXPUNGE:
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch mail_expunge(bbox->sync_mail);
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch break;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch case MAIL_INDEX_SYNC_TYPE_FLAGS:
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch flags = sync_rec->add_flags & MAIL_FLAGS_NONRECENT;
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch if (flags != 0) {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch mail_update_flags(bbox->sync_mail,
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch MODIFY_ADD, flags);
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch }
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch flags = sync_rec->remove_flags & MAIL_FLAGS_NONRECENT;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch if (flags != 0) {
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch mail_update_flags(bbox->sync_mail,
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch MODIFY_REMOVE, flags);
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch }
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch break;
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch case MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD:
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch case MAIL_INDEX_SYNC_TYPE_KEYWORD_REMOVE:
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch kw_names[0] = ctx->kw_all[sync_rec->keyword_idx];
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch kw_names[1] = NULL;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch keywords = mailbox_keywords_create_valid(bbox->box,
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch kw_names);
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch modify_type = sync_rec->type ==
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD ?
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch MODIFY_ADD : MODIFY_REMOVE;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch mail_update_keywords(bbox->sync_mail,
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch modify_type, keywords);
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch mailbox_keywords_unref(&keywords);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch break;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch return 0;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic int virtual_sync_index_changes(struct virtual_sync_context *ctx)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const ARRAY_TYPE(keywords) *keywords;
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch struct mail_index_sync_rec sync_rec;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch keywords = mail_index_get_keywords(ctx->index);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ctx->kw_all = array_count(keywords) == 0 ? NULL :
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch array_idx(keywords, 0);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch while (mail_index_sync_next(ctx->index_sync_ctx, &sync_rec)) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (virtual_sync_index_rec(ctx, &sync_rec) < 0)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return 0;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic void virtual_sync_index_finish(struct virtual_sync_context *ctx)
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct mailbox *box = &ctx->mbox->box;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const struct mail_index_header *hdr;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uint32_t seq1, seq2;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch hdr = mail_index_get_header(ctx->sync_view);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (hdr->uid_validity != 0)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ctx->uid_validity = hdr->uid_validity;
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch else
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch virtual_sync_set_uidvalidity(ctx);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* mark the newly seen messages as recent */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (mail_index_lookup_seq_range(ctx->sync_view, hdr->first_recent_uid,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch hdr->next_uid, &seq1, &seq2)) {
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch index_mailbox_set_recent_seq(&ctx->mbox->box, ctx->sync_view,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch seq1, seq2);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (ctx->ext_header_rewrite) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* entire mailbox list needs to be rewritten */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch virtual_sync_ext_header_rewrite(ctx);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch } else {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* update only changed parts in the header */
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch virtual_sync_ext_header_update(ctx);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (box->v.sync_notify != NULL)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch box->v.sync_notify(box, 0, 0);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Boschstatic int virtual_sync_backend_box_init(struct virtual_backend_box *bbox)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct mailbox_transaction_context *trans;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct mail_search_context *search_ctx;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct mail *mail;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct virtual_backend_uidmap uidmap;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch enum mailbox_search_result_flags result_flags;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch int ret;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch trans = mailbox_transaction_begin(bbox->box, 0);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (!bbox->search_args_initialized) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch mail_search_args_init(bbox->search_args, bbox->box, FALSE, NULL);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch bbox->search_args_initialized = TRUE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch search_ctx = mailbox_search_init(trans, bbox->search_args, NULL,
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch 0, NULL);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* save the result and keep it updated */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch result_flags = MAILBOX_SEARCH_RESULT_FLAG_UPDATE |
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch MAILBOX_SEARCH_RESULT_FLAG_QUEUE_SYNC;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch bbox->search_result =
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch mailbox_search_result_save(search_ctx, result_flags);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* add the found UIDs to uidmap. virtual_uid gets assigned later. */
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch memset(&uidmap, 0, sizeof(uidmap));
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch array_clear(&bbox->uids);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch while (mailbox_search_next(search_ctx, &mail)) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uidmap.real_uid = mail->uid;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch array_append(&bbox->uids, &uidmap, 1);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ret = mailbox_search_deinit(&search_ctx);
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch (void)mailbox_transaction_commit(&trans);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return ret;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic int
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschvirtual_backend_uidmap_bsearch_cmp(const uint32_t *uidp,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const struct virtual_backend_uidmap *uidmap)
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return *uidp < uidmap->real_uid ? -1 :
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch (*uidp > uidmap->real_uid ? 1 : 0);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic void
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschvirtual_sync_mailbox_box_remove(struct virtual_sync_context *ctx,
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch struct virtual_backend_box *bbox,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const ARRAY_TYPE(seq_range) *removed_uids)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const struct seq_range *uids;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct virtual_backend_uidmap *uidmap;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch unsigned int i, src, dest, uid_count, rec_count;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uint32_t uid, vseq;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uids = array_get(removed_uids, &uid_count);
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch if (uid_count == 0)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* everything in removed_uids should exist in bbox->uids */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uidmap = array_get_modifiable(&bbox->uids, &rec_count);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch i_assert(rec_count >= uid_count);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch /* find the first uidmap record to be removed */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (!array_bsearch_insert_pos(&bbox->uids, &uids[0].seq1,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch virtual_backend_uidmap_bsearch_cmp, &src))
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch i_unreached();
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* remove the unwanted messages */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch dest = src;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch for (i = 0; i < uid_count; i++) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uid = uids[i].seq1;
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch while (uidmap[src].real_uid != uid) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uidmap[dest++] = uidmap[src++];
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch i_assert(src < rec_count);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch for (; uid <= uids[i].seq2; uid++, src++) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch i_assert(src < rec_count);
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch i_assert(uidmap[src].real_uid == uid);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (mail_index_lookup_seq(ctx->sync_view,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uidmap[src].virtual_uid,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch &vseq))
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch mail_index_expunge(ctx->trans, vseq);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch array_delete(&bbox->uids, dest, src - dest);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic void
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschvirtual_sync_mailbox_box_add(struct virtual_sync_context *ctx,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct virtual_backend_box *bbox,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const ARRAY_TYPE(seq_range) *added_uids_arr)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const struct seq_range *added_uids;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct virtual_backend_uidmap *uidmap;
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch struct virtual_add_record rec;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch unsigned int i, src, dest, uid_count, add_count, rec_count;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uint32_t add_uid;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch added_uids = array_get(added_uids_arr, &uid_count);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (uid_count == 0)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch add_count = seq_range_count(added_uids_arr);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* none of added_uids should exist in bbox->uids. find the position
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch of the first inserted index. */
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch uidmap = array_get_modifiable(&bbox->uids, &rec_count);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (rec_count == 0 ||
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch added_uids[0].seq1 > uidmap[rec_count-1].real_uid) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* fast path: usually messages are appended */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch dest = rec_count;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch } else if (array_bsearch_insert_pos(&bbox->uids, &added_uids[0].seq1,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch virtual_backend_uidmap_bsearch_cmp,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch &dest))
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch i_unreached();
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* make space for all added UIDs. */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (rec_count == dest)
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch array_idx_clear(&bbox->uids, dest + add_count-1);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch else {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch array_copy(&bbox->uids.arr, dest + add_count,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch &bbox->uids.arr, dest, rec_count - dest);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uidmap = array_get_modifiable(&bbox->uids, &rec_count);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch src = dest + add_count;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* add/move the UIDs to their correct positions */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch memset(&rec, 0, sizeof(rec));
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch rec.rec.mailbox_id = bbox->mailbox_id;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch for (i = 0; i < uid_count; i++) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch add_uid = added_uids[i].seq1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch while (src < rec_count && uidmap[src].real_uid < add_uid)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uidmap[dest++] = uidmap[src++];
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch for (; add_uid <= added_uids[i].seq2; add_uid++, dest++) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch i_assert(dest < rec_count);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uidmap[dest].real_uid = add_uid;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uidmap[dest].virtual_uid = 0;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (ctx->mbox->uids_mapped) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch rec.rec.real_uid = add_uid;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch array_append(&ctx->all_adds, &rec, 1);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
e9c433c5b8ef9a1b4246ebe10beb90fa01e05cafPhil Carmodystatic int virtual_backend_uidmap_cmp(const struct virtual_backend_uidmap *u1,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const struct virtual_backend_uidmap *u2)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (u1->real_uid < u2->real_uid)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (u1->real_uid > u2->real_uid)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return 1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return 0;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
e9c433c5b8ef9a1b4246ebe10beb90fa01e05cafPhil Carmody
e9c433c5b8ef9a1b4246ebe10beb90fa01e05cafPhil Carmodystatic void virtual_sync_bbox_uids_sort(struct virtual_backend_box *bbox)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* the uidmap must be sorted by real_uids */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch array_sort(&bbox->uids, virtual_backend_uidmap_cmp);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch bbox->uids_nonsorted = FALSE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch
639bb36b12b9f9bb54c8bb1be50eac623622f8a0Timo Sirainenstatic void virtual_sync_backend_boxes_sort_uids(struct virtual_mailbox *mbox)
639bb36b12b9f9bb54c8bb1be50eac623622f8a0Timo Sirainen{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct virtual_backend_box *const *bboxes;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch unsigned int i, count;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch bboxes = array_get(&mbox->backend_boxes, &count);
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch for (i = 0; i < count; i++) {
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch if (bboxes[i]->uids_nonsorted)
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch virtual_sync_bbox_uids_sort(bboxes[i]);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch}
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic void
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschvirtual_sync_backend_add_vmsgs_results(struct virtual_sync_context *ctx,
e87b25495e78a6f61f236b188bfd68070eff3295Phil Carmody struct virtual_backend_box *bbox,
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody uint32_t real_uid,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct mail_search_result *result,
e87b25495e78a6f61f236b188bfd68070eff3295Phil Carmody const uint32_t vseq)
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct virtual_backend_uidmap uidmap;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uint32_t vuid, seq;
e87b25495e78a6f61f236b188bfd68070eff3295Phil Carmody
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody mail_index_lookup_uid(ctx->sync_view, vseq, &vuid);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
e87b25495e78a6f61f236b188bfd68070eff3295Phil Carmody memset(&uidmap, 0, sizeof(uidmap));
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody uidmap.real_uid = real_uid;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uidmap.virtual_uid = vuid;
f883bf3eff62f5d27df5ee9ee664edc38a77937fStephan Bosch array_append(&bbox->uids, &uidmap, 1);
e87b25495e78a6f61f236b188bfd68070eff3295Phil Carmody
f883bf3eff62f5d27df5ee9ee664edc38a77937fStephan Bosch if (result == NULL)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ;
e87b25495e78a6f61f236b188bfd68070eff3295Phil Carmody else if (mail_index_lookup_seq(bbox->box->view, real_uid, &seq))
f883bf3eff62f5d27df5ee9ee664edc38a77937fStephan Bosch seq_range_array_add(&result->uids, real_uid);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch else
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch seq_range_array_add(&result->removed_uids, real_uid);
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch}
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic void
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Boschvirtual_sync_backend_handle_old_vmsgs(struct virtual_sync_context *ctx,
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch struct virtual_backend_box *bbox,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct mail_search_result *result)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
e87b25495e78a6f61f236b188bfd68070eff3295Phil Carmody const struct virtual_mail_index_record *vrec;
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody const struct virtual_sync_mail *sync_mail, *sync_mails;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const void *data;
e87b25495e78a6f61f236b188bfd68070eff3295Phil Carmody uint32_t i, vseq, messages;
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* find the messages that currently exist in virtual index and add them
e87b25495e78a6f61f236b188bfd68070eff3295Phil Carmody to the backend mailbox's list of uids. */
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody array_clear(&bbox->uids);
e87b25495e78a6f61f236b188bfd68070eff3295Phil Carmody
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody if (array_is_created(&ctx->all_mails)) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch i_assert(ctx->all_mails_prev_mailbox_id < bbox->mailbox_id);
e87b25495e78a6f61f236b188bfd68070eff3295Phil Carmody sync_mails = array_get(&ctx->all_mails, &messages);
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody for (i = ctx->all_mails_idx; i < messages; i++) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch sync_mail = &sync_mails[i];
e87b25495e78a6f61f236b188bfd68070eff3295Phil Carmody if (sync_mail->vrec.mailbox_id != bbox->mailbox_id) {
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody if (sync_mail->vrec.mailbox_id < bbox->mailbox_id) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* stale mailbox_id, ignore */
e87b25495e78a6f61f236b188bfd68070eff3295Phil Carmody continue;
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody }
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody /* Should be in mailbox_id order,
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody so skip to next box */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch break;
e87b25495e78a6f61f236b188bfd68070eff3295Phil Carmody }
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody virtual_sync_backend_add_vmsgs_results(ctx, bbox,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch sync_mail->vrec.real_uid, result, sync_mail->vseq);
e87b25495e78a6f61f236b188bfd68070eff3295Phil Carmody }
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody ctx->all_mails_idx = i;
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody ctx->all_mails_prev_mailbox_id = bbox->mailbox_id;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch } else {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* there should be only a single backend mailbox, but in the
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch existing index there may be stale mailbox_ids that we'll
e87b25495e78a6f61f236b188bfd68070eff3295Phil Carmody just skip over. */
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody messages = mail_index_view_get_messages_count(ctx->sync_view);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch for (vseq = 1; vseq <= messages; vseq++) {
e87b25495e78a6f61f236b188bfd68070eff3295Phil Carmody mail_index_lookup_ext(ctx->sync_view, vseq,
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody ctx->mbox->virtual_ext_id, &data, NULL);
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody vrec = data;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (vrec->mailbox_id == bbox->mailbox_id) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch virtual_sync_backend_add_vmsgs_results(ctx,
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody bbox, vrec->real_uid, result, vseq);
e87b25495e78a6f61f236b188bfd68070eff3295Phil Carmody }
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody }
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch virtual_sync_bbox_uids_sort(bbox);
e87b25495e78a6f61f236b188bfd68070eff3295Phil Carmody}
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmodystatic int virtual_sync_backend_box_continue(struct virtual_sync_context *ctx,
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody struct virtual_backend_box *bbox)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const enum mailbox_search_result_flags result_flags =
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody MAILBOX_SEARCH_RESULT_FLAG_UPDATE |
e87b25495e78a6f61f236b188bfd68070eff3295Phil Carmody MAILBOX_SEARCH_RESULT_FLAG_QUEUE_SYNC;
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody struct mail_index_view *view = bbox->box->view;
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody struct mail_search_result *result;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ARRAY_TYPE(seq_range) expunged_uids = ARRAY_INIT, removed_uids;
e87b25495e78a6f61f236b188bfd68070eff3295Phil Carmody ARRAY_TYPE(seq_range) added_uids, flag_update_uids;
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody uint64_t modseq, old_highest_modseq;
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody uint32_t seq, uid, old_msg_count;
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* initialize the search result from all the existing messages in
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch virtual index. */
e87b25495e78a6f61f236b188bfd68070eff3295Phil Carmody if (!bbox->search_args_initialized) {
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody mail_search_args_init(bbox->search_args, bbox->box, FALSE, NULL);
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody bbox->search_args_initialized = TRUE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
e87b25495e78a6f61f236b188bfd68070eff3295Phil Carmody result = mailbox_search_result_alloc(bbox->box, bbox->search_args,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch result_flags);
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody mailbox_search_result_initial_done(result);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch i_assert(array_count(&result->removed_uids) == 0);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch virtual_sync_backend_handle_old_vmsgs(ctx, bbox, result);
e87b25495e78a6f61f236b188bfd68070eff3295Phil Carmody if (array_count(&result->removed_uids) > 0) {
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody /* these are all expunged messages. treat them separately from
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody "no longer matching messages" (=removed_uids) */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch t_array_init(&expunged_uids, array_count(&result->removed_uids));
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch array_append_array(&expunged_uids, &result->removed_uids);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch array_clear(&result->removed_uids);
e87b25495e78a6f61f236b188bfd68070eff3295Phil Carmody }
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody /* get list of changed old messages (messages already once seen by
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch virtual index), based on modseq changes. (we'll assume all modseq
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch changes are due to flag changes, which may not be true in future) */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (bbox->sync_next_uid <= 1 ||
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch !mail_index_lookup_seq_range(view, 1, bbox->sync_next_uid-1,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch &seq, &old_msg_count))
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch old_msg_count = 0;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch old_highest_modseq = mail_index_modseq_get_highest(view);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
e87b25495e78a6f61f236b188bfd68070eff3295Phil Carmody t_array_init(&flag_update_uids, I_MIN(128, old_msg_count));
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody if (bbox->sync_highest_modseq < old_highest_modseq) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch for (seq = 1; seq <= old_msg_count; seq++) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch modseq = mail_index_modseq_lookup(view, seq);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (modseq > bbox->sync_highest_modseq) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch mail_index_lookup_uid(view, seq, &uid);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch seq_range_array_add(&flag_update_uids, uid);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* update the search result based on the flag changes and
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch new messages */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (index_search_result_update_flags(result, &flag_update_uids) < 0 ||
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch index_search_result_update_appends(result, old_msg_count) < 0) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch mailbox_search_result_free(&result);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return -1;
e9c433c5b8ef9a1b4246ebe10beb90fa01e05cafPhil Carmody }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch t_array_init(&removed_uids, 128);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch t_array_init(&added_uids, 128);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch mailbox_search_result_sync(result, &removed_uids, &added_uids);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (array_is_created(&expunged_uids)) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch seq_range_array_remove_seq_range(&removed_uids, &expunged_uids);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch virtual_sync_mailbox_box_remove(ctx, bbox, &expunged_uids);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch if (ctx->expunge_removed)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch virtual_sync_mailbox_box_remove(ctx, bbox, &removed_uids);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch else {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* delayed remove */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch seq_range_array_merge(&bbox->sync_pending_removes,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch &removed_uids);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch virtual_sync_mailbox_box_add(ctx, bbox, &added_uids);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch bbox->search_result = result;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return 0;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic void virtual_sync_drop_existing(struct virtual_backend_box *bbox,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ARRAY_TYPE(seq_range) *added_uids)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ARRAY_TYPE(seq_range) drop_uids;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const struct virtual_backend_uidmap *uidmap;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct seq_range_iter iter;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch unsigned int i, n = 0, count;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uint32_t add_uid;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch seq_range_array_iter_init(&iter, added_uids);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (!seq_range_array_iter_nth(&iter, n++, &add_uid))
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch (void)array_bsearch_insert_pos(&bbox->uids, &add_uid,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch virtual_backend_uidmap_bsearch_cmp, &i);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uidmap = array_get_modifiable(&bbox->uids, &count);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (i == count)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch t_array_init(&drop_uids, array_count(added_uids));
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch for (; i < count; ) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (uidmap[i].real_uid < add_uid) {
4c8646ca7a1bfe3e5a43f1f3e329f8ff8c24d851Stephan Bosch i++;
4c8646ca7a1bfe3e5a43f1f3e329f8ff8c24d851Stephan Bosch continue;
4c8646ca7a1bfe3e5a43f1f3e329f8ff8c24d851Stephan Bosch }
4c8646ca7a1bfe3e5a43f1f3e329f8ff8c24d851Stephan Bosch if (uidmap[i].real_uid == add_uid) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch seq_range_array_add(&drop_uids, add_uid);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch i++;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (!seq_range_array_iter_nth(&iter, n++, &add_uid))
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch break;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch seq_range_array_remove_seq_range(added_uids, &drop_uids);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic void virtual_sync_drop_nonexistent(struct virtual_backend_box *bbox,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ARRAY_TYPE(seq_range) *removed_uids)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ARRAY_TYPE(seq_range) drop_uids;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const struct virtual_backend_uidmap *uidmap;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct seq_range_iter iter;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch unsigned int i, n = 0, count;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uint32_t remove_uid;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch bool iter_done = FALSE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch seq_range_array_iter_init(&iter, removed_uids);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (!seq_range_array_iter_nth(&iter, n++, &remove_uid))
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch (void)array_bsearch_insert_pos(&bbox->uids, &remove_uid,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch virtual_backend_uidmap_bsearch_cmp, &i);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch t_array_init(&drop_uids, array_count(removed_uids)); iter_done = FALSE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uidmap = array_get_modifiable(&bbox->uids, &count);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch for (; i < count; ) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (uidmap[i].real_uid < remove_uid) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch i++;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch continue;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (uidmap[i].real_uid != remove_uid)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch seq_range_array_add(&drop_uids, remove_uid);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch else
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch i++;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (!seq_range_array_iter_nth(&iter, n++, &remove_uid)) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch iter_done = TRUE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch break;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (!iter_done) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch do {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch seq_range_array_add(&drop_uids, remove_uid);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch } while (seq_range_array_iter_nth(&iter, n++, &remove_uid));
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch seq_range_array_remove_seq_range(removed_uids, &drop_uids);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic void virtual_sync_mailbox_box_update(struct virtual_sync_context *ctx,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch struct virtual_backend_box *bbox)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch ARRAY_TYPE(seq_range) removed_uids, added_uids, temp_uids;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch unsigned int count1, count2;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch t_array_init(&removed_uids, 128);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch t_array_init(&added_uids, 128);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch mailbox_search_result_sync(bbox->search_result,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch &removed_uids, &added_uids);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (array_is_created(&bbox->sync_outside_expunges)) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch seq_range_array_remove_seq_range(&bbox->sync_outside_expunges,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch &added_uids);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch seq_range_array_merge(&removed_uids,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch &bbox->sync_outside_expunges);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch array_clear(&bbox->sync_outside_expunges);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch virtual_sync_drop_existing(bbox, &added_uids);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch virtual_sync_drop_nonexistent(bbox, &removed_uids);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* if any of the pending removes came back, we don't want to expunge
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch them anymore. also since they already exist, remove them from
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch added_uids. */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch count1 = array_count(&bbox->sync_pending_removes);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch count2 = array_count(&added_uids);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (count1 > 0 && count2 > 0) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch t_array_init(&temp_uids, count1);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch array_append_array(&temp_uids, &bbox->sync_pending_removes);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (seq_range_array_remove_seq_range(
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch &bbox->sync_pending_removes, &added_uids) > 0) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch seq_range_array_remove_seq_range(&added_uids,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch &temp_uids);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (!ctx->expunge_removed) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* delay removing messages that don't match the search
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch criteria, but don't delay removing expunged messages */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch if (array_count(&ctx->sync_expunges) > 0) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch seq_range_array_remove_seq_range(&bbox->sync_pending_removes,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch &ctx->sync_expunges);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch seq_range_array_remove_seq_range(&removed_uids,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch &ctx->sync_expunges);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch virtual_sync_mailbox_box_remove(ctx, bbox,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch &ctx->sync_expunges);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch seq_range_array_merge(&bbox->sync_pending_removes,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch &removed_uids);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch } else if (array_count(&bbox->sync_pending_removes) > 0) {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch /* remove all current and old */
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch seq_range_array_merge(&bbox->sync_pending_removes,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch &removed_uids);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch virtual_sync_mailbox_box_remove(ctx, bbox,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch &bbox->sync_pending_removes);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch array_clear(&bbox->sync_pending_removes);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch } else {
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch virtual_sync_mailbox_box_remove(ctx, bbox, &removed_uids);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
e9c433c5b8ef9a1b4246ebe10beb90fa01e05cafPhil Carmody virtual_sync_mailbox_box_add(ctx, bbox, &added_uids);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Boschstatic bool virtual_sync_find_seqs(struct virtual_backend_box *bbox,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const struct mailbox_sync_rec *sync_rec,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch unsigned int *idx1_r,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch unsigned int *idx2_r)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch{
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch const struct virtual_backend_uidmap *uidmap;
e9c433c5b8ef9a1b4246ebe10beb90fa01e05cafPhil Carmody unsigned int idx, count;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uint32_t uid1, uid2;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch mail_index_lookup_uid(bbox->box->view, sync_rec->seq1, &uid1);
66134fbce11778241ca9f8458ee2a0488a05bde0Stephan Bosch mail_index_lookup_uid(bbox->box->view, sync_rec->seq2, &uid2);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch (void)array_bsearch_insert_pos(&bbox->uids, &uid1,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch virtual_backend_uidmap_bsearch_cmp,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch &idx);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
639bb36b12b9f9bb54c8bb1be50eac623622f8a0Timo Sirainen uidmap = array_get_modifiable(&bbox->uids, &count);
639bb36b12b9f9bb54c8bb1be50eac623622f8a0Timo Sirainen if (idx == count || uidmap[idx].real_uid > uid2)
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return FALSE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch *idx1_r = idx;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch while (idx < count && uidmap[idx].real_uid <= uid2) idx++;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch *idx2_r = idx - 1;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return TRUE;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
e9c433c5b8ef9a1b4246ebe10beb90fa01e05cafPhil Carmody
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Boschstatic void virtual_sync_expunge_add(struct virtual_sync_context *ctx,
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch struct virtual_backend_box *bbox,
17c29e3e2246972c3d988e05d91b9286398a624fStephan Bosch const struct mailbox_sync_rec *sync_rec)
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch{
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch struct virtual_backend_uidmap *uidmap;
4c8646ca7a1bfe3e5a43f1f3e329f8ff8c24d851Stephan Bosch uint32_t uid1, uid2;
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch unsigned int i, idx1, count;
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch mail_index_lookup_uid(bbox->box->view, sync_rec->seq1, &uid1);
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch mail_index_lookup_uid(bbox->box->view, sync_rec->seq2, &uid2);
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch /* remember only the expunges for messages that
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch already exist for this mailbox */
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch (void)array_bsearch_insert_pos(&bbox->uids, &uid1,
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch virtual_backend_uidmap_bsearch_cmp,
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch &idx1);
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch uidmap = array_get_modifiable(&bbox->uids, &count);
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch for (i = idx1; i < count; i++) {
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch if (uidmap[i].real_uid > uid2)
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch break;
62aa68310d6f42467ca26880f678173bf1d26a83Stephan Bosch seq_range_array_add(&ctx->sync_expunges, uidmap[i].real_uid);
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch }
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch}
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Boschstatic int virtual_sync_backend_box_sync(struct virtual_sync_context *ctx,
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch struct virtual_backend_box *bbox,
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch enum mailbox_sync_flags sync_flags)
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch{
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch struct mailbox_sync_context *sync_ctx;
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch const struct virtual_backend_uidmap *uidmap;
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch struct mailbox_sync_rec sync_rec;
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch struct mailbox_sync_status sync_status;
e9c433c5b8ef9a1b4246ebe10beb90fa01e05cafPhil Carmody unsigned int idx1, idx2;
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch uint32_t vseq, vuid;
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch sync_ctx = mailbox_sync_init(bbox->box, sync_flags);
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch virtual_backend_box_sync_mail_set(bbox);
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch while (mailbox_sync_next(sync_ctx, &sync_rec)) {
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch switch (sync_rec.type) {
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch case MAILBOX_SYNC_TYPE_EXPUNGE:
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch if (ctx->expunge_removed) {
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch /* no need to keep track of expunges */
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch break;
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch }
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch virtual_sync_expunge_add(ctx, bbox, &sync_rec);
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch break;
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch case MAILBOX_SYNC_TYPE_FLAGS:
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch if (!virtual_sync_find_seqs(bbox, &sync_rec,
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch &idx1, &idx2))
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch break;
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch uidmap = array_idx(&bbox->uids, 0);
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch for (; idx1 <= idx2; idx1++) {
289ce1246b1c7511f8ceec02344316064ffbe546Phil Carmody vuid = uidmap[idx1].virtual_uid;
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch if (!mail_index_lookup_seq(ctx->sync_view,
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch vuid, &vseq)) {
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch /* expunged by another session,
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch but we haven't yet updated
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch bbox->uids. */
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch continue;
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch }
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch virtual_sync_external_flags(ctx, bbox, vseq,
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch uidmap[idx1].real_uid);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
baf3e87e186453fda13bd21f7cbcb2efc8492e8bTimo Sirainen break;
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch case MAILBOX_SYNC_TYPE_MODSEQ:
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch break;
4d955db590c3d76a631dfc5d37bcdf578a43e55aStephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch }
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch return mailbox_sync_deinit(&sync_ctx, &sync_status);
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch}
6ae6496c225238a2c55a8cd96744ad976c44a726Stephan Bosch
static void virtual_sync_backend_ext_header(struct virtual_sync_context *ctx,
struct virtual_backend_box *bbox)
{
const unsigned int uidval_pos =
offsetof(struct virtual_mail_index_mailbox_record,
uid_validity);
struct mailbox_status status;
struct virtual_mail_index_mailbox_record mailbox;
unsigned int mailbox_offset;
uint64_t wanted_ondisk_highest_modseq;
mailbox_get_open_status(bbox->box, STATUS_UIDVALIDITY |
STATUS_HIGHESTMODSEQ, &status);
wanted_ondisk_highest_modseq =
array_count(&bbox->sync_pending_removes) > 0 ? 0 :
status.highest_modseq;
if (bbox->sync_uid_validity == status.uidvalidity &&
bbox->sync_next_uid == status.uidnext &&
bbox->sync_highest_modseq == status.highest_modseq &&
bbox->ondisk_highest_modseq == wanted_ondisk_highest_modseq)
return;
/* mailbox changed - update extension header */
bbox->sync_uid_validity = status.uidvalidity;
bbox->sync_highest_modseq = status.highest_modseq;
bbox->ondisk_highest_modseq = wanted_ondisk_highest_modseq;
bbox->sync_next_uid = status.uidnext;
if (ctx->ext_header_rewrite) {
/* we'll rewrite the entire header later */
return;
}
memset(&mailbox, 0, sizeof(mailbox));
mailbox.uid_validity = bbox->sync_uid_validity;
mailbox.highest_modseq = bbox->ondisk_highest_modseq;
mailbox.next_uid = bbox->sync_next_uid;
mailbox_offset = sizeof(struct virtual_mail_index_header) +
bbox->sync_mailbox_idx * sizeof(mailbox);
mail_index_update_header_ext(ctx->trans, ctx->mbox->virtual_ext_id,
mailbox_offset + uidval_pos,
CONST_PTR_OFFSET(&mailbox, uidval_pos),
sizeof(mailbox) - uidval_pos);
ctx->ext_header_changed = TRUE;
}
static void virtual_sync_backend_box_deleted(struct virtual_sync_context *ctx,
struct virtual_backend_box *bbox)
{
ARRAY_TYPE(seq_range) removed_uids;
const struct virtual_backend_uidmap *uidmap;
/* delay its full removal until the next time we open the virtual
mailbox. for now just treat it as if it was empty. */
t_array_init(&removed_uids, 128);
array_foreach(&bbox->uids, uidmap)
seq_range_array_add(&removed_uids, uidmap->real_uid);
virtual_sync_mailbox_box_remove(ctx, bbox, &removed_uids);
}
static int virtual_sync_backend_box(struct virtual_sync_context *ctx,
struct virtual_backend_box *bbox)
{
enum mailbox_sync_flags sync_flags;
struct mailbox_status status;
bool bbox_index_opened = bbox->box->opened;
int ret;
/* if we already did some changes to index, commit them before
syncing starts. */
virtual_backend_box_sync_mail_unset(bbox);
sync_flags = ctx->flags & (MAILBOX_SYNC_FLAG_FULL_READ |
MAILBOX_SYNC_FLAG_FULL_WRITE |
MAILBOX_SYNC_FLAG_FAST);
if (bbox->search_result == NULL) {
/* a) first sync in this process.
b) we had auto-closed this backend mailbox.
first try to quickly check if the mailbox has changed.
if we can do that check from mailbox list index, we don't
even need to open the mailbox. */
i_assert(array_count(&bbox->sync_pending_removes) == 0);
if (bbox_index_opened || bbox->open_failed) {
/* a) index already opened, refresh it
b) delayed error handling for mailbox_open()
that failed in virtual_notify_changes() */
if (!bbox_index_opened) {
if (virtual_backend_box_open(ctx->mbox, bbox) < 0)
return -1;
}
if (mailbox_sync(bbox->box, sync_flags) < 0)
return -1;
bbox->open_failed = FALSE;
}
ret = mailbox_get_status(bbox->box, STATUS_UIDVALIDITY |
STATUS_UIDNEXT | STATUS_HIGHESTMODSEQ,
&status);
if (!bbox_index_opened && bbox->box->opened)
virtual_backend_box_opened(ctx->mbox, bbox);
if (ret < 0) {
if (mailbox_get_last_mail_error(bbox->box) != MAIL_ERROR_NOTFOUND)
return -1;
/* mailbox was deleted */
virtual_sync_backend_box_deleted(ctx, bbox);
return 0;
}
if (status.uidvalidity == bbox->sync_uid_validity &&
status.uidnext == bbox->sync_next_uid &&
status.highest_modseq == bbox->sync_highest_modseq) {
/* mailbox hasn't changed since we last opened it,
skip it for now.
we'll still need to create the bbox->uids mapping
using the current index. */
if (array_count(&bbox->uids) == 0)
virtual_sync_backend_handle_old_vmsgs(ctx, bbox, NULL);
return 0;
}
if (!bbox_index_opened) {
/* first time we're opening the index */
if (!bbox->box->opened) {
if (virtual_backend_box_open(ctx->mbox, bbox) < 0)
return -1;
}
if (mailbox_sync(bbox->box, sync_flags) < 0)
return -1;
}
virtual_backend_box_sync_mail_set(bbox);
if (status.uidvalidity != bbox->sync_uid_validity) {
/* UID validity changed since last sync (or this is
the first sync), do a full search */
i_assert(ctx->expunge_removed);
ret = virtual_sync_backend_box_init(bbox);
} else {
/* build the initial search using the saved modseq. */
ret = virtual_sync_backend_box_continue(ctx, bbox);
}
i_assert(bbox->search_result != NULL || ret < 0);
} else {
/* sync using the existing search result */
i_assert(bbox_index_opened);
i_array_init(&ctx->sync_expunges, 32);
ret = virtual_sync_backend_box_sync(ctx, bbox, sync_flags);
if (ret == 0) T_BEGIN {
virtual_sync_mailbox_box_update(ctx, bbox);
} T_END;
array_free(&ctx->sync_expunges);
}
virtual_sync_backend_ext_header(ctx, bbox);
return ret;
}
static void virtual_sync_backend_map_uids(struct virtual_sync_context *ctx)
{
uint32_t virtual_ext_id = ctx->mbox->virtual_ext_id;
struct virtual_sync_mail *vmails;
struct virtual_backend_box *bbox;
struct virtual_backend_uidmap *uidmap = NULL;
struct virtual_add_record add_rec;
const struct virtual_mail_index_record *vrec;
const void *data;
uint32_t i, vseq, vuid, messages;
unsigned int j = 0, uidmap_count = 0;
messages = mail_index_view_get_messages_count(ctx->sync_view);
if (messages == 0)
return;
/* sort the messages in current view by their backend mailbox and
real UID */
vmails = i_new(struct virtual_sync_mail, messages);
for (vseq = 1; vseq <= messages; vseq++) {
mail_index_lookup_ext(ctx->sync_view, vseq, virtual_ext_id,
&data, NULL);
vrec = data;
vmails[vseq-1].vseq = vseq;
vmails[vseq-1].vrec = *vrec;
}
qsort(vmails, messages, sizeof(*vmails), virtual_sync_mail_uid_cmp);
/* create real mailbox uid -> virtual uid mapping and expunge
messages no longer matching the search rule */
memset(&add_rec, 0, sizeof(add_rec));
bbox = NULL;
for (i = 0; i < messages; i++) {
vseq = vmails[i].vseq;
vrec = &vmails[i].vrec;
if (bbox == NULL || bbox->mailbox_id != vrec->mailbox_id) {
/* add the rest of the newly seen messages */
i_assert(j == uidmap_count ||
bbox->search_result != NULL);
for (; j < uidmap_count; j++) {
add_rec.rec.real_uid = uidmap[j].real_uid;
array_append(&ctx->all_adds, &add_rec, 1);
}
bbox = virtual_backend_box_lookup(ctx->mbox,
vrec->mailbox_id);
if (bbox == NULL) {
/* the entire mailbox is lost */
mail_index_expunge(ctx->trans, vseq);
continue;
}
uidmap = array_get_modifiable(&bbox->uids,
&uidmap_count);
j = 0;
add_rec.rec.mailbox_id = bbox->mailbox_id;
bbox->sync_seen = TRUE;
}
if (bbox->search_result == NULL) {
/* mailbox is completely unchanged since last sync */
j = uidmap_count;
continue;
}
mail_index_lookup_uid(ctx->sync_view, vseq, &vuid);
/* if virtual record doesn't exist in uidmap, it's expunged */
for (; j < uidmap_count; j++) {
if (uidmap[j].real_uid >= vrec->real_uid)
break;
/* newly seen message */
add_rec.rec.real_uid = uidmap[j].real_uid;
array_append(&ctx->all_adds, &add_rec, 1);
}
if (j == uidmap_count || uidmap[j].real_uid != vrec->real_uid)
mail_index_expunge(ctx->trans, vseq);
else {
/* exists - update uidmap and flags */
uidmap[j++].virtual_uid = vuid;
virtual_sync_external_flags(ctx, bbox, vseq,
vrec->real_uid);
}
}
i_free(vmails);
/* finish adding messages to the last mailbox */
for (; j < uidmap_count; j++) {
add_rec.rec.real_uid = uidmap[j].real_uid;
array_append(&ctx->all_adds, &add_rec, 1);
}
}
static void virtual_sync_new_backend_boxes(struct virtual_sync_context *ctx)
{
struct virtual_backend_box *const *bboxes;
struct virtual_add_record add_rec;
struct virtual_backend_uidmap *uidmap;
unsigned int i, j, count, uidmap_count;
/* if there are any mailboxes we didn't yet sync, add new messages in
them */
memset(&add_rec, 0, sizeof(add_rec));
bboxes = array_get(&ctx->mbox->backend_boxes, &count);
for (i = 0; i < count; i++) {
if (bboxes[i]->sync_seen)
continue;
add_rec.rec.mailbox_id = bboxes[i]->mailbox_id;
uidmap = array_get_modifiable(&bboxes[i]->uids, &uidmap_count);
for (j = 0; j < uidmap_count; j++) {
add_rec.rec.real_uid = uidmap[j].real_uid;
array_append(&ctx->all_adds, &add_rec, 1);
}
}
}
static int virtual_add_record_cmp(const struct virtual_add_record *add1,
const struct virtual_add_record *add2)
{
if (add1->received_date < add2->received_date)
return -1;
if (add1->received_date > add2->received_date)
return 1;
/* if they're in same mailbox, we can order them correctly by the UID.
if they're in different mailboxes, ordering by UID doesn't really
help but it doesn't really harm either. */
if (add1->rec.real_uid < add2->rec.real_uid)
return -1;
if (add1->rec.real_uid > add2->rec.real_uid)
return 1;
/* two messages in different mailboxes have the same received date
and UID. */
return 0;
}
static int virtual_sync_backend_sort_new(struct virtual_sync_context *ctx)
{
struct virtual_backend_box *bbox;
struct virtual_add_record *adds;
const struct virtual_mail_index_record *vrec;
unsigned int i, count;
/* get all messages' received dates */
adds = array_get_modifiable(&ctx->all_adds, &count);
for (bbox = NULL, i = 0; i < count; i++) {
vrec = &adds[i].rec;
if (bbox == NULL || bbox->mailbox_id != vrec->mailbox_id) {
bbox = virtual_backend_box_lookup(ctx->mbox,
vrec->mailbox_id);
if (!bbox->box->opened &&
virtual_backend_box_open(ctx->mbox, bbox) < 0)
return -1;
virtual_backend_box_sync_mail_set(bbox);
}
if (!mail_set_uid(bbox->sync_mail, vrec->real_uid)) {
/* we may have reopened the mailbox, which could have
caused the mail to be expunged already. */
adds[i].received_date = 0;
} else if (mail_get_received_date(bbox->sync_mail,
&adds[i].received_date) < 0) {
if (!bbox->sync_mail->expunged)
return -1;
/* expunged already, just add it somewhere */
adds[i].received_date = 0;
}
}
array_sort(&ctx->all_adds, virtual_add_record_cmp);
return 0;
}
static int virtual_sync_backend_add_new(struct virtual_sync_context *ctx)
{
uint32_t virtual_ext_id = ctx->mbox->virtual_ext_id;
struct virtual_add_record *adds;
struct virtual_backend_box *bbox;
struct virtual_backend_uidmap *uidmap;
const struct mail_index_header *hdr;
const struct virtual_mail_index_record *vrec;
unsigned int i, count, idx;
ARRAY_TYPE(seq_range) saved_uids;
uint32_t vseq, first_uid;
hdr = mail_index_get_header(ctx->sync_view);
adds = array_get_modifiable(&ctx->all_adds, &count);
if (count == 0) {
ctx->mbox->sync_virtual_next_uid = hdr->next_uid;
return 0;
}
if (adds[0].rec.mailbox_id == adds[count-1].rec.mailbox_id) {
/* all messages are from a single mailbox. add them in
the same order. */
} else {
/* sort new messages by received date to get the add order */
if (virtual_sync_backend_sort_new(ctx) < 0)
return -1;
}
for (bbox = NULL, i = 0; i < count; i++) {
vrec = &adds[i].rec;
if (bbox == NULL || bbox->mailbox_id != vrec->mailbox_id) {
bbox = virtual_backend_box_lookup(ctx->mbox,
vrec->mailbox_id);
if (!bbox->box->opened &&
virtual_backend_box_open(ctx->mbox, bbox) < 0)
return -1;
virtual_backend_box_sync_mail_set(bbox);
}
mail_index_append(ctx->trans, 0, &vseq);
mail_index_update_ext(ctx->trans, vseq, virtual_ext_id,
vrec, NULL);
virtual_sync_external_flags(ctx, bbox, vseq, vrec->real_uid);
}
/* assign UIDs to new messages */
first_uid = hdr->next_uid;
t_array_init(&saved_uids, 1);
mail_index_append_finish_uids(ctx->trans, first_uid, &saved_uids);
i_assert(seq_range_count(&saved_uids) == count);
/* update virtual UIDs in uidmap */
for (bbox = NULL, i = 0; i < count; i++) {
vrec = &adds[i].rec;
if (bbox == NULL || bbox->mailbox_id != vrec->mailbox_id) {
bbox = virtual_backend_box_lookup(ctx->mbox,
vrec->mailbox_id);
}
if (!array_bsearch_insert_pos(&bbox->uids, &vrec->real_uid,
virtual_backend_uidmap_bsearch_cmp,
&idx))
i_unreached();
uidmap = array_idx_modifiable(&bbox->uids, idx);
i_assert(uidmap->virtual_uid == 0);
uidmap->virtual_uid = first_uid + i;
}
ctx->mbox->sync_virtual_next_uid = first_uid + i;
return 0;
}
static int
virtual_sync_apply_existing_appends(struct virtual_sync_context *ctx)
{
uint32_t virtual_ext_id = ctx->mbox->virtual_ext_id;
struct virtual_backend_box *bbox = NULL;
const struct mail_index_header *hdr;
const struct virtual_mail_index_record *vrec;
struct virtual_backend_uidmap uidmap;
const void *data;
uint32_t seq, seq2;
if (!ctx->mbox->uids_mapped)
return 0;
hdr = mail_index_get_header(ctx->sync_view);
if (ctx->mbox->sync_virtual_next_uid >= hdr->next_uid)
return 0;
/* another process added messages to virtual index. get backend boxes'
uid lists up-to-date by adding the new messages there. */
if (!mail_index_lookup_seq_range(ctx->sync_view,
ctx->mbox->sync_virtual_next_uid,
(uint32_t)-1, &seq, &seq2))
return 0;
memset(&uidmap, 0, sizeof(uidmap));
for (; seq <= seq2; seq++) {
mail_index_lookup_ext(ctx->sync_view, seq, virtual_ext_id,
&data, NULL);
vrec = data;
uidmap.real_uid = vrec->real_uid;
mail_index_lookup_uid(ctx->sync_view, seq, &uidmap.virtual_uid);
if (bbox == NULL || bbox->mailbox_id != vrec->mailbox_id) {
bbox = virtual_backend_box_lookup(ctx->mbox,
vrec->mailbox_id);
if (bbox == NULL) {
mail_storage_set_critical(
ctx->mbox->box.storage,
"Mailbox ID %u unexpectedly lost",
vrec->mailbox_id);
return -1;
}
}
array_append(&bbox->uids, &uidmap, 1);
bbox->uids_nonsorted = TRUE;
}
virtual_sync_backend_boxes_sort_uids(ctx->mbox);
return 0;
}
static void
virtual_sync_apply_existing_expunges(struct virtual_mailbox *mbox,
struct mailbox_sync_context *sync_ctx)
{
struct index_mailbox_sync_context *isync_ctx =
(struct index_mailbox_sync_context *)sync_ctx;
struct virtual_backend_box *bbox = NULL;
struct seq_range_iter iter;
const struct virtual_mail_index_record *vrec;
const void *data;
unsigned int n = 0;
uint32_t seq;
if (isync_ctx->expunges == NULL)
return;
seq_range_array_iter_init(&iter, isync_ctx->expunges);
while (seq_range_array_iter_nth(&iter, n++, &seq)) {
mail_index_lookup_ext(mbox->box.view, seq,
mbox->virtual_ext_id, &data, NULL);
vrec = data;
if (bbox == NULL || bbox->mailbox_id != vrec->mailbox_id) {
bbox = virtual_backend_box_lookup(mbox,
vrec->mailbox_id);
if (!array_is_created(&bbox->sync_outside_expunges))
i_array_init(&bbox->sync_outside_expunges, 32);
}
seq_range_array_add(&bbox->sync_outside_expunges,
vrec->real_uid);
}
}
static int virtual_sync_mail_mailbox_cmp(const struct virtual_sync_mail *m1,
const struct virtual_sync_mail *m2)
{
if (m1->vrec.mailbox_id < m2->vrec.mailbox_id)
return -1;
if (m1->vrec.mailbox_id > m2->vrec.mailbox_id)
return 1;
return 0;
}
static void virtual_sync_bboxes_get_mails(struct virtual_sync_context *ctx)
{
uint32_t messages, vseq;
const void *mail_data;
const struct virtual_mail_index_record *vrec;
struct virtual_sync_mail *sync_mail;
messages = mail_index_view_get_messages_count(ctx->sync_view);
i_array_init(&ctx->all_mails, messages);
for (vseq = 1; vseq <= messages; vseq++) {
mail_index_lookup_ext(ctx->sync_view, vseq,
ctx->mbox->virtual_ext_id, &mail_data, NULL);
vrec = mail_data;
sync_mail = array_append_space(&ctx->all_mails);
sync_mail->vseq = vseq;
sync_mail->vrec = *vrec;
}
array_sort(&ctx->all_mails, virtual_sync_mail_mailbox_cmp);
}
static int virtual_sync_backend_boxes(struct virtual_sync_context *ctx)
{
struct virtual_backend_box *const *bboxes;
unsigned int i, count;
int ret;
if (virtual_sync_apply_existing_appends(ctx) < 0)
return -1;
i_array_init(&ctx->all_adds, 128);
bboxes = array_get(&ctx->mbox->backend_boxes, &count);
/* we have different optimizations depending on whether the virtual
mailbox consists of multiple backend boxes or just one */
if (count > 1)
virtual_sync_bboxes_get_mails(ctx);
for (i = 0; i < count; i++) {
if (virtual_sync_backend_box(ctx, bboxes[i]) < 0) {
/* backend failed, copy the error */
virtual_box_copy_error(&ctx->mbox->box,
bboxes[i]->box);
return -1;
}
}
if (!ctx->mbox->uids_mapped) {
/* initial sync: assign virtual UIDs to existing messages and
sync all flags */
ctx->mbox->uids_mapped = TRUE;
virtual_sync_backend_map_uids(ctx);
virtual_sync_new_backend_boxes(ctx);
}
ret = virtual_sync_backend_add_new(ctx);
array_free(&ctx->all_adds);
if (array_is_created(&ctx->all_mails))
array_free(&ctx->all_mails);
return ret;
}
static void virtual_sync_backend_boxes_finish(struct virtual_sync_context *ctx)
{
struct virtual_backend_box *const *bboxes;
unsigned int i, count;
bboxes = array_get(&ctx->mbox->backend_boxes, &count);
for (i = 0; i < count; i++)
virtual_backend_box_sync_mail_unset(bboxes[i]);
}
static int virtual_sync_finish(struct virtual_sync_context *ctx, bool success)
{
int ret = success ? 0 : -1;
virtual_sync_backend_boxes_finish(ctx);
if (success) {
if (mail_index_sync_commit(&ctx->index_sync_ctx) < 0) {
mailbox_set_index_error(&ctx->mbox->box);
ret = -1;
}
} else {
if (ctx->index_broken) {
/* make sure we don't complain about the same errors
over and over again. */
if (mail_index_unlink(ctx->index) < 0) {
i_error("virtual index %s: Failed to unlink() "
"broken indexes: %m",
mailbox_get_path(&ctx->mbox->box));
}
}
mail_index_sync_rollback(&ctx->index_sync_ctx);
}
i_free(ctx);
return ret;
}
static int virtual_sync(struct virtual_mailbox *mbox,
enum mailbox_sync_flags flags)
{
struct virtual_sync_context *ctx;
enum mail_index_sync_flags index_sync_flags;
int ret;
ctx = i_new(struct virtual_sync_context, 1);
ctx->mbox = mbox;
ctx->flags = flags;
ctx->index = mbox->box.index;
/* Removed messages are expunged when
a) EXPUNGE is used
b) Mailbox is being opened (FIX_INCONSISTENT is set) */
ctx->expunge_removed =
(ctx->flags & (MAILBOX_SYNC_FLAG_EXPUNGE |
MAILBOX_SYNC_FLAG_FIX_INCONSISTENT)) != 0;
index_sync_flags = MAIL_INDEX_SYNC_FLAG_FLUSH_DIRTY |
MAIL_INDEX_SYNC_FLAG_AVOID_FLAG_UPDATES;
if ((mbox->box.flags & MAILBOX_FLAG_DROP_RECENT) != 0)
index_sync_flags |= MAIL_INDEX_SYNC_FLAG_DROP_RECENT;
ret = mail_index_sync_begin(ctx->index, &ctx->index_sync_ctx,
&ctx->sync_view, &ctx->trans,
index_sync_flags);
if (ret <= 0) {
if (ret < 0)
mailbox_set_index_error(&mbox->box);
i_free(ctx);
return ret;
}
ret = virtual_sync_ext_header_read(ctx);
if (ret < 0)
return virtual_sync_finish(ctx, FALSE);
if (ret == 0)
ctx->ext_header_rewrite = TRUE;
/* apply changes from virtual index to backend mailboxes */
if (virtual_sync_index_changes(ctx) < 0)
return virtual_sync_finish(ctx, FALSE);
/* update list of UIDs in backend mailboxes */
if (virtual_sync_backend_boxes(ctx) < 0)
return virtual_sync_finish(ctx, FALSE);
virtual_sync_index_finish(ctx);
return virtual_sync_finish(ctx, TRUE);
}
struct mailbox_sync_context *
virtual_storage_sync_init(struct mailbox *box, enum mailbox_sync_flags flags)
{
struct virtual_mailbox *mbox = (struct virtual_mailbox *)box;
struct mailbox_sync_context *sync_ctx;
int ret = 0;
if (!box->opened) {
if (mailbox_open(box) < 0)
ret = -1;
}
if (index_mailbox_want_full_sync(&mbox->box, flags) && ret == 0)
ret = virtual_sync(mbox, flags);
sync_ctx = index_mailbox_sync_init(box, flags, ret < 0);
virtual_sync_apply_existing_expunges(mbox, sync_ctx);
return sync_ctx;
}