virtual-sync.c revision 5fe2339f8ad2698f0ea7c87a968c8ed2b853bad9
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2008-2017 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen#include "array.h"
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen#include "bsearch-insert-pos.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "ioloop.h"
993e6c2caaae971dd3c34913a42d854e3b623261Timo Sirainen#include "str.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mail-index-modseq.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mail-search-build.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mailbox-search-result-private.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "mailbox-recent-flags.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "index-sync-private.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "index-search-result.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "virtual-storage.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
7888a9d2008eab9985096c46e1da9ee985c22a2aTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct virtual_add_record {
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen struct virtual_mail_index_record rec;
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen time_t received_date;
213b139965e8bde6c8aff02ffd9fd39a74c887a9Timo Sirainen};
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainenstruct virtual_sync_mail {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t vseq;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct virtual_mail_index_record vrec;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen};
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct virtual_sync_context {
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen struct virtual_mailbox *mbox;
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen struct mail_index_sync_ctx *index_sync_ctx;
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen struct mail_index *index;
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen struct mail_index_view *sync_view;
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen struct mail_index_transaction *trans;
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen const char *const *kw_all;
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen /* messages expunged within this sync */
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen ARRAY_TYPE(seq_range) sync_expunges;
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen ARRAY(struct virtual_add_record) all_adds;
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen /* all messages in this sync, sorted by mailbox_id
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen (but unsorted inside it for now, since it doesn't matter) */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ARRAY(struct virtual_sync_mail) all_mails;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen uint32_t all_mails_idx, all_mails_prev_mailbox_id;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen enum mailbox_sync_flags flags;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen uint32_t uid_validity;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen bool ext_header_changed:1;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen bool expunge_removed:1;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen bool index_broken:1;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen};
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainenstatic void virtual_sync_backend_box_deleted(struct virtual_sync_context *ctx,
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen struct virtual_backend_box *bbox);
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainenstatic void virtual_sync_set_uidvalidity(struct virtual_sync_context *ctx)
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen{
bbce20cb4e5739e9a06058cf8ee1f38a7f6884f6Timo Sirainen uint32_t uid_validity = ioloop_time;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_update_header(ctx->trans,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen offsetof(struct mail_index_header, uid_validity),
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen &uid_validity, sizeof(uid_validity), TRUE);
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen ctx->uid_validity = uid_validity;
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen}
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainenstatic void virtual_sync_external_flags(struct virtual_sync_context *ctx,
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen struct virtual_backend_box *bbox,
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen uint32_t vseq, uint32_t real_uid)
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen{
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen enum mail_flags flags;
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen const char *const *kw_names;
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen struct mail_keywords *keywords;
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen if (!mail_set_uid(bbox->sync_mail, real_uid)) {
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen /* we may have reopened the mailbox, which could have
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen caused the mail to be expunged already. */
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen return;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* copy flags */
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen flags = mail_get_flags(bbox->sync_mail);
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen /* we don't need to keep recent flags here */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_update_flags(ctx->trans, vseq, MODIFY_REPLACE, flags & ~(MAIL_RECENT));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* copy keywords */
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen kw_names = mail_get_keywords(bbox->sync_mail);
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen keywords = mail_index_keywords_create(ctx->index, kw_names);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen mail_index_update_keywords(ctx->trans, vseq, MODIFY_REPLACE, keywords);
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen mail_index_keywords_unref(&keywords);
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen}
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainenstatic int virtual_sync_mail_uid_cmp(const void *p1, const void *p2)
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen{
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen const struct virtual_sync_mail *m1 = p1, *m2 = p2;
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen if (m1->vrec.mailbox_id < m2->vrec.mailbox_id)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return -1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (m1->vrec.mailbox_id > m2->vrec.mailbox_id)
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen return 1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen if (m1->vrec.real_uid < m2->vrec.real_uid)
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen return -1;
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen if (m1->vrec.real_uid > m2->vrec.real_uid)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return 1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* broken */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return 0;
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen}
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainenstatic void
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainenvirtual_backend_box_sync_mail_set(struct virtual_backend_box *bbox)
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen{
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen struct mailbox_transaction_context *trans;
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen if (bbox->sync_mail == NULL) {
0d658231054332c3f4c04aab0422af649de89a8cTimo Sirainen trans = mailbox_transaction_begin(bbox->box, 0);
89334d8c6915db0fc8630470b7f3cd5ee9aa29aaTimo Sirainen bbox->sync_mail = mail_alloc(trans, 0, NULL);
89334d8c6915db0fc8630470b7f3cd5ee9aa29aaTimo Sirainen }
89334d8c6915db0fc8630470b7f3cd5ee9aa29aaTimo Sirainen}
89334d8c6915db0fc8630470b7f3cd5ee9aa29aaTimo Sirainen
89334d8c6915db0fc8630470b7f3cd5ee9aa29aaTimo Sirainenstatic int bbox_mailbox_id_cmp(struct virtual_backend_box *const *b1,
89334d8c6915db0fc8630470b7f3cd5ee9aa29aaTimo Sirainen struct virtual_backend_box *const *b2)
89334d8c6915db0fc8630470b7f3cd5ee9aa29aaTimo Sirainen{
89334d8c6915db0fc8630470b7f3cd5ee9aa29aaTimo Sirainen if ((*b1)->mailbox_id < (*b2)->mailbox_id)
89334d8c6915db0fc8630470b7f3cd5ee9aa29aaTimo Sirainen return -1;
89334d8c6915db0fc8630470b7f3cd5ee9aa29aaTimo Sirainen if ((*b1)->mailbox_id > (*b2)->mailbox_id)
89334d8c6915db0fc8630470b7f3cd5ee9aa29aaTimo Sirainen return 1;
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen return 0;
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen}
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainenstatic int
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainenvirtual_sync_get_backend_box(struct virtual_mailbox *mbox, const char *name,
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen struct virtual_backend_box **bbox_r)
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen{
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen *bbox_r = virtual_backend_box_lookup_name(mbox, name);
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen if (*bbox_r != NULL || !mbox->sync_initialized)
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen return 0;
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen /* another process just added a new mailbox.
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen we can't handle this currently. */
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen mbox->inconsistent = TRUE;
23c502c6ef08d83e8ed68f90ed75138e14a3a246Timo Sirainen mail_storage_set_error(mbox->box.storage, MAIL_ERROR_TEMP, t_strdup_printf(
9df8c9225140d9d1df5ddf4c6c9da61662ae6c44Timo Sirainen "Backend mailbox '%s' added by another session. "
40ef82c46f6652412b068ebcdac7c3e74840a284Timo Sirainen "Reopen the virtual mailbox.", name));
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen return -1;
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen}
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainenint virtual_mailbox_ext_header_read(struct virtual_mailbox *mbox,
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen struct mail_index_view *view,
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen bool *broken_r)
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen{
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen const char *box_path = mailbox_get_path(&mbox->box);
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen const struct virtual_mail_index_header *ext_hdr;
8eeafcb306872435f3171e6acf5a9937aec3a175Timo Sirainen const struct mail_index_header *hdr;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen const struct virtual_mail_index_mailbox_record *mailboxes;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen struct virtual_backend_box *bbox, **bboxes;
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen const void *ext_data;
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen size_t ext_size;
faee566824fe3567c8beacf097f9dcfc0d3761b7Timo Sirainen unsigned int i, count, ext_name_offset, ext_mailbox_count;
faee566824fe3567c8beacf097f9dcfc0d3761b7Timo Sirainen uint32_t prev_mailbox_id;
faee566824fe3567c8beacf097f9dcfc0d3761b7Timo Sirainen int ret = 1;
faee566824fe3567c8beacf097f9dcfc0d3761b7Timo Sirainen
faee566824fe3567c8beacf097f9dcfc0d3761b7Timo Sirainen *broken_r = FALSE;
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen hdr = mail_index_get_header(view);
f537e7efaec891d6b3320ca94331d09ca8c4a4dbTimo Sirainen mail_index_get_header_ext(view, mbox->virtual_ext_id,
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen &ext_data, &ext_size);
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen ext_hdr = ext_data;
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen if (mbox->sync_initialized &&
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen mbox->prev_uid_validity == hdr->uid_validity &&
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen ext_size >= sizeof(*ext_hdr) &&
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen mbox->prev_change_counter == ext_hdr->change_counter) {
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen /* fully refreshed */
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen return 1;
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen }
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen mbox->prev_uid_validity = hdr->uid_validity;
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen if (ext_hdr == NULL ||
fc7b17677ac1a5fa3f7fe13d5ef7dcfea8d9b4a1Timo Sirainen mbox->search_args_crc32 != ext_hdr->search_args_crc32) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen mailboxes = NULL;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen ext_name_offset = 0;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen ext_mailbox_count = 0;
ccb77e2f63626ec46e5745ef4f38baa8e8e504fcTimo Sirainen ret = 0;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen } else {
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen const void *guid_data;
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen size_t guid_size;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen mail_index_get_header_ext(view, mbox->virtual_guid_ext_id,
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen &guid_data, &guid_size);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (guid_size >= GUID_128_SIZE)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen guid_128_copy(mbox->guid, guid_data);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen mbox->prev_change_counter = ext_hdr->change_counter;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen mailboxes = (const void *)(ext_hdr + 1);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen ext_name_offset = sizeof(*ext_hdr) +
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen ext_hdr->mailbox_count * sizeof(*mailboxes);
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen if (ext_name_offset >= ext_size ||
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen ext_hdr->mailbox_count > INT_MAX/sizeof(*mailboxes)) {
6a4bfb2b0bb9f53fb1d4e705bf3948ef4d1ecccbTimo Sirainen i_error("virtual index %s: Broken mailbox_count header",
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen box_path);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen *broken_r = TRUE;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen ext_mailbox_count = 0;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen ret = 0;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen } else {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen ext_mailbox_count = ext_hdr->mailbox_count;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen /* update mailbox backends */
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen prev_mailbox_id = 0;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen for (i = 0; i < ext_mailbox_count; i++) {
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen if (mailboxes[i].id > ext_hdr->highest_mailbox_id ||
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen mailboxes[i].id <= prev_mailbox_id) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen i_error("virtual index %s: Broken mailbox id",
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen box_path);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen break;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen }
e376e08040b5f21ff79a15ae728d2532a34207f6Timo Sirainen if (mailboxes[i].name_len == 0 ||
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mailboxes[i].name_len > ext_size) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen i_error("virtual index %s: Broken mailbox name_len",
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen box_path);
c21c33a8c98972c45349066fc76ac9e2c05013c1Timo Sirainen break;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (ext_name_offset + mailboxes[i].name_len > ext_size) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen i_error("virtual index %s: Broken mailbox list",
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen box_path);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen break;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen T_BEGIN {
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen const unsigned char *nameptr;
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen const char *name;
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen nameptr = CONST_PTR_OFFSET(ext_data, ext_name_offset);
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen name = t_strndup(nameptr, mailboxes[i].name_len);
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen if (virtual_sync_get_backend_box(mbox, name, &bbox) < 0)
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen ret = -1;
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen } T_END;
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen if (bbox == NULL) {
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen if (ret < 0)
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen return -1;
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen /* mailbox no longer exists. */
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen ret = 0;
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen } else {
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen bbox->mailbox_id = mailboxes[i].id;
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen bbox->sync_uid_validity = mailboxes[i].uid_validity;
dcf4c70f8358db12859c3ab5b81b3abaac4109a3Timo Sirainen bbox->ondisk_highest_modseq =
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen bbox->sync_highest_modseq =
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen mailboxes[i].highest_modseq;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen bbox->sync_next_uid = mailboxes[i].next_uid;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen bbox->sync_mailbox_idx = i;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen }
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen ext_name_offset += mailboxes[i].name_len;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen prev_mailbox_id = mailboxes[i].id;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen }
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen if (i < ext_mailbox_count) {
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen *broken_r = TRUE;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen mbox->ext_header_rewrite = TRUE;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen ret = 0;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen }
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen mbox->highest_mailbox_id = ext_hdr == NULL ? 0 :
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen ext_hdr->highest_mailbox_id;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen /* do not mark it initialized if it's broken */
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen mbox->sync_initialized = !*broken_r;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen /* assign new mailbox IDs if any are missing */
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen bboxes = array_get_modifiable(&mbox->backend_boxes, &count);
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen for (i = 0; i < count; i++) {
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen if (bboxes[i]->mailbox_id == 0) {
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen bboxes[i]->mailbox_id = ++mbox->highest_mailbox_id;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen ret = 0;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen }
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen }
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen /* sort the backend mailboxes by mailbox_id. */
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen array_sort(&mbox->backend_boxes, bbox_mailbox_id_cmp);
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen if (ret == 0)
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen mbox->ext_header_rewrite = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainenstatic void virtual_sync_ext_header_rewrite(struct virtual_sync_context *ctx)
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen{
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen struct virtual_mail_index_header ext_hdr;
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen struct virtual_mail_index_mailbox_record mailbox;
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen struct virtual_backend_box **bboxes;
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen buffer_t *buf;
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen const void *ext_data;
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen size_t ext_size;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen unsigned int i, mailbox_pos, name_pos, count;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen bboxes = array_get_modifiable(&ctx->mbox->backend_boxes, &count);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen mailbox_pos = sizeof(ext_hdr);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen name_pos = mailbox_pos + sizeof(mailbox) * count;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen i_zero(&ext_hdr);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen i_zero(&mailbox);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen ext_hdr.change_counter = ++ctx->mbox->prev_change_counter;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen ext_hdr.mailbox_count = count;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen ext_hdr.highest_mailbox_id = ctx->mbox->highest_mailbox_id;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen ext_hdr.search_args_crc32 = ctx->mbox->search_args_crc32;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buf = buffer_create_dynamic(pool_datastack_create(), name_pos + 256);
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen buffer_append(buf, &ext_hdr, sizeof(ext_hdr));
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen for (i = 0; i < count; i++) {
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen i_assert(i == 0 ||
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen bboxes[i]->mailbox_id > bboxes[i-1]->mailbox_id);
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen bboxes[i]->sync_mailbox_idx = i;
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen mailbox.id = bboxes[i]->mailbox_id;
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen mailbox.name_len = strlen(bboxes[i]->name);
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen mailbox.uid_validity = bboxes[i]->sync_uid_validity;
7471f28b16b81f9af413c879b3efb16eeafd2bd9Timo Sirainen mailbox.highest_modseq = bboxes[i]->ondisk_highest_modseq;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen mailbox.next_uid = bboxes[i]->sync_next_uid;
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen buffer_write(buf, mailbox_pos, &mailbox, sizeof(mailbox));
527ed64bc924b4a13b570a8450f8be3efdf71879Timo Sirainen buffer_write(buf, name_pos, bboxes[i]->name, mailbox.name_len);
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen
688f0fdfb7ca946e38ae34459b0ca30b71c8457cTimo Sirainen mailbox_pos += sizeof(mailbox);
688f0fdfb7ca946e38ae34459b0ca30b71c8457cTimo Sirainen name_pos += mailbox.name_len;
688f0fdfb7ca946e38ae34459b0ca30b71c8457cTimo Sirainen
688f0fdfb7ca946e38ae34459b0ca30b71c8457cTimo Sirainen /* repair the value */
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen if (ctx->mbox->highest_mailbox_id < mailbox.id)
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen ctx->mbox->highest_mailbox_id = mailbox.id;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ctx->mbox->highest_mailbox_id != ext_hdr.highest_mailbox_id) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ext_hdr.highest_mailbox_id = ctx->mbox->highest_mailbox_id;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen buffer_write(buf, 0, &ext_hdr, sizeof(ext_hdr));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
1cf72a848805fcf014b01c9d3665b6a157846a21Timo Sirainen i_assert(buf->used == name_pos);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen mail_index_get_header_ext(ctx->sync_view, ctx->mbox->virtual_ext_id,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen &ext_data, &ext_size);
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen if (ext_size < name_pos) {
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen mail_index_ext_resize(ctx->trans, ctx->mbox->virtual_ext_id,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen name_pos,
1f4f81ba81bb9fa8abe2d94f344373c230066d67Timo Sirainen sizeof(struct virtual_mail_index_record),
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen sizeof(uint32_t));
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen }
a050ca9def13949dbaa67bd6574a41c4f397ae26Timo Sirainen mail_index_update_header_ext(ctx->trans, ctx->mbox->virtual_ext_id,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen 0, buf->data, name_pos);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainenstatic void virtual_sync_ext_header_update(struct virtual_sync_context *ctx)
1e16e4fb4b1d99e835f19f0f5720d6c75d8c6783Timo Sirainen{
3ea86ed7cf06ba04e4aa6cd1c4df9be336c06cd3Timo Sirainen struct virtual_mail_index_header ext_hdr;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen if (!ctx->ext_header_changed)
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen return;
1e16e4fb4b1d99e835f19f0f5720d6c75d8c6783Timo Sirainen
1e16e4fb4b1d99e835f19f0f5720d6c75d8c6783Timo Sirainen /* we changed something - update the change counter in header */
1e16e4fb4b1d99e835f19f0f5720d6c75d8c6783Timo Sirainen ext_hdr.change_counter = ++ctx->mbox->prev_change_counter;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen mail_index_update_header_ext(ctx->trans, ctx->mbox->virtual_ext_id,
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen offsetof(struct virtual_mail_index_header, change_counter),
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen &ext_hdr.change_counter, sizeof(ext_hdr.change_counter));
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen}
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainenstatic int virtual_sync_index_rec(struct virtual_sync_context *ctx,
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen const struct mail_index_sync_rec *sync_rec)
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen{
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen uint32_t virtual_ext_id = ctx->mbox->virtual_ext_id;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen struct virtual_backend_box *bbox;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen const struct virtual_mail_index_record *vrec;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen const void *data;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen enum mail_flags flags;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen struct mail_keywords *keywords;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen enum modify_type modify_type;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen const char *kw_names[2];
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen uint32_t vseq, seq1, seq2;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen switch (sync_rec->type) {
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen case MAIL_INDEX_SYNC_TYPE_EXPUNGE:
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen case MAIL_INDEX_SYNC_TYPE_FLAGS:
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen case MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD:
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen case MAIL_INDEX_SYNC_TYPE_KEYWORD_REMOVE:
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen break;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen }
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen if (!mail_index_lookup_seq_range(ctx->sync_view,
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen sync_rec->uid1, sync_rec->uid2,
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen &seq1, &seq2)) {
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen /* already expunged, nothing to do. */
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen return 0;
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen }
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen for (vseq = seq1; vseq <= seq2; vseq++) {
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen mail_index_lookup_ext(ctx->sync_view, vseq, virtual_ext_id,
6d3bb841d4ec2c12ac2d4ecf6146ef8d8a7dd731Timo Sirainen &data, NULL);
c680a6b35b459045e92814778908da5a93922107Timo Sirainen vrec = data;
c680a6b35b459045e92814778908da5a93922107Timo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen bbox = virtual_backend_box_lookup(ctx->mbox, vrec->mailbox_id);
c680a6b35b459045e92814778908da5a93922107Timo Sirainen if (bbox == NULL)
c680a6b35b459045e92814778908da5a93922107Timo Sirainen continue;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (!bbox->box->opened) {
0fa842717a8b163252e55c229c37ca0c5d7ff056Timo Sirainen if (virtual_backend_box_open(ctx->mbox, bbox) < 0) {
0fa842717a8b163252e55c229c37ca0c5d7ff056Timo Sirainen virtual_box_copy_error(&ctx->mbox->box,
c680a6b35b459045e92814778908da5a93922107Timo Sirainen bbox->box);
096953143c4032bad154637f687551856f7946cbTimo Sirainen return -1;
096953143c4032bad154637f687551856f7946cbTimo Sirainen }
096953143c4032bad154637f687551856f7946cbTimo Sirainen } else {
096953143c4032bad154637f687551856f7946cbTimo Sirainen virtual_backend_box_accessed(ctx->mbox, bbox);
c680a6b35b459045e92814778908da5a93922107Timo Sirainen }
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen virtual_backend_box_sync_mail_set(bbox);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen if (!mail_set_uid(bbox->sync_mail, vrec->real_uid)) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen /* message is already expunged from backend mailbox. */
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen continue;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen switch (sync_rec->type) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen case MAIL_INDEX_SYNC_TYPE_EXPUNGE:
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen mail_expunge(bbox->sync_mail);
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen break;
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen case MAIL_INDEX_SYNC_TYPE_FLAGS:
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen flags = sync_rec->add_flags & MAIL_FLAGS_NONRECENT;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (flags != 0) {
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen mail_update_flags(bbox->sync_mail,
ae8817f05005f57bba32479a610b52d083e2b6ebTimo Sirainen MODIFY_ADD, flags);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen flags = sync_rec->remove_flags & MAIL_FLAGS_NONRECENT;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (flags != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_update_flags(bbox->sync_mail,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen MODIFY_REMOVE, flags);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case MAIL_INDEX_SYNC_TYPE_KEYWORD_REMOVE:
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen kw_names[0] = ctx->kw_all[sync_rec->keyword_idx];
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen kw_names[1] = NULL;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen keywords = mailbox_keywords_create_valid(bbox->box,
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen kw_names);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen modify_type = sync_rec->type ==
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen MAIL_INDEX_SYNC_TYPE_KEYWORD_ADD ?
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen MODIFY_ADD : MODIFY_REMOVE;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen mail_update_keywords(bbox->sync_mail,
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen modify_type, keywords);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen mailbox_keywords_unref(&keywords);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen break;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen }
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen }
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return 0;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen}
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainenstatic int virtual_sync_index_changes(struct virtual_sync_context *ctx)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen{
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen const ARRAY_TYPE(keywords) *keywords;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen struct mail_index_sync_rec sync_rec;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen keywords = mail_index_get_keywords(ctx->index);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen ctx->kw_all = array_count(keywords) == 0 ? NULL :
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen array_idx(keywords, 0);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen while (mail_index_sync_next(ctx->index_sync_ctx, &sync_rec)) {
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (virtual_sync_index_rec(ctx, &sync_rec) < 0)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return -1;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen }
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen return 0;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen}
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainenstatic void virtual_sync_index_finish(struct virtual_sync_context *ctx)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen{
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen struct mailbox *box = &ctx->mbox->box;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen const struct mail_index_header *hdr;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen struct mail_index_view *view;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen uint32_t seq1, seq2;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen view = mail_index_transaction_open_updated_view(ctx->trans);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen hdr = mail_index_get_header(ctx->sync_view);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (hdr->uid_validity != 0)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen ctx->uid_validity = hdr->uid_validity;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen else
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen virtual_sync_set_uidvalidity(ctx);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen /* mark the newly seen messages as recent */
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen if (mail_index_lookup_seq_range(view, hdr->first_recent_uid,
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen (uint32_t)-1, &seq1, &seq2)) {
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen mailbox_recent_flags_set_seqs(&ctx->mbox->box, view,
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen seq1, seq2);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen }
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen mail_index_view_close(&view);
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ctx->mbox->ext_header_rewrite) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* entire mailbox list needs to be rewritten */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen virtual_sync_ext_header_rewrite(ctx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* update only changed parts in the header */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen virtual_sync_ext_header_update(ctx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (box->v.sync_notify != NULL)
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen box->v.sync_notify(box, 0, 0);
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen}
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainenstatic int virtual_sync_backend_box_init(struct virtual_backend_box *bbox)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mailbox_transaction_context *trans;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct mail_search_context *search_ctx;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen struct mail *mail;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct virtual_backend_uidmap uidmap;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen enum mailbox_search_result_flags result_flags;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen trans = mailbox_transaction_begin(bbox->box, 0);
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen if (!bbox->search_args_initialized) {
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen mail_search_args_init(bbox->search_args, bbox->box, FALSE, NULL);
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen bbox->search_args_initialized = TRUE;
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen }
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen search_ctx = mailbox_search_init(trans, bbox->search_args, NULL,
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen 0, NULL);
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen /* save the result and keep it updated */
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen result_flags = MAILBOX_SEARCH_RESULT_FLAG_UPDATE |
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen MAILBOX_SEARCH_RESULT_FLAG_QUEUE_SYNC;
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen bbox->search_result =
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen mailbox_search_result_save(search_ctx, result_flags);
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen /* add the found UIDs to uidmap. virtual_uid gets assigned later. */
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen i_zero(&uidmap);
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen array_clear(&bbox->uids);
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen while (mailbox_search_next(search_ctx, &mail)) {
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen uidmap.real_uid = mail->uid;
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen array_append(&bbox->uids, &uidmap, 1);
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen }
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen ret = mailbox_search_deinit(&search_ctx);
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen (void)mailbox_transaction_commit(&trans);
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen return ret;
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen}
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainenstatic int
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainenvirtual_backend_uidmap_bsearch_cmp(const uint32_t *uidp,
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen const struct virtual_backend_uidmap *uidmap)
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen{
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen return *uidp < uidmap->real_uid ? -1 :
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen (*uidp > uidmap->real_uid ? 1 : 0);
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen}
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainenstatic void
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainenvirtual_sync_mailbox_box_remove(struct virtual_sync_context *ctx,
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen struct virtual_backend_box *bbox,
8bae533c96e129dca8ee7b494d7de5aeb4a043a2Timo Sirainen const ARRAY_TYPE(seq_range) *removed_uids)
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen{
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen const struct seq_range *uids;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen struct virtual_backend_uidmap *uidmap;
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen unsigned int i, src, dest, uid_count, rec_count;
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen uint32_t uid, vseq;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen uids = array_get(removed_uids, &uid_count);
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen if (uid_count == 0)
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen return;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen /* everything in removed_uids should exist in bbox->uids */
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen uidmap = array_get_modifiable(&bbox->uids, &rec_count);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen i_assert(rec_count >= uid_count);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen /* find the first uidmap record to be removed */
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (!array_bsearch_insert_pos(&bbox->uids, &uids[0].seq1,
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen virtual_backend_uidmap_bsearch_cmp, &src))
37b805dfb45902b6b41c45482f67e6f98e08b0a3Timo Sirainen i_unreached();
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen /* remove the unwanted messages */
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen dest = src;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen for (i = 0; i < uid_count; i++) {
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen uid = uids[i].seq1;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen while (uidmap[src].real_uid != uid) {
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen uidmap[dest++] = uidmap[src++];
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen i_assert(src < rec_count);
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen }
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen for (; uid <= uids[i].seq2; uid++, src++) {
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen i_assert(src < rec_count);
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen i_assert(uidmap[src].real_uid == uid);
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen if (uidmap[src].virtual_uid == 0) {
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen /* has not been assigned yet */
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen continue;
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen if (mail_index_lookup_seq(ctx->sync_view,
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen uidmap[src].virtual_uid,
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen &vseq))
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen mail_index_expunge(ctx->trans, vseq);
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen }
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen }
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen array_delete(&bbox->uids, dest, src - dest);
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen}
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainenstatic void
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainenvirtual_sync_mailbox_box_add(struct virtual_sync_context *ctx,
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen struct virtual_backend_box *bbox,
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen const ARRAY_TYPE(seq_range) *added_uids_arr)
3281669db44d09a087a203201248abbc81b3cc1aTimo Sirainen{
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen const struct seq_range *added_uids;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen struct virtual_backend_uidmap *uidmap;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen struct virtual_add_record rec;
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen unsigned int i, src, dest, uid_count, add_count, rec_count;
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen uint32_t add_uid;
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen added_uids = array_get(added_uids_arr, &uid_count);
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen if (uid_count == 0)
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen return;
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen add_count = seq_range_count(added_uids_arr);
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen /* none of added_uids should exist in bbox->uids. find the position
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen of the first inserted index. */
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen uidmap = array_get_modifiable(&bbox->uids, &rec_count);
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen if (rec_count == 0 ||
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen added_uids[0].seq1 > uidmap[rec_count-1].real_uid) {
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen /* fast path: usually messages are appended */
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen dest = rec_count;
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen } else if (array_bsearch_insert_pos(&bbox->uids, &added_uids[0].seq1,
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen virtual_backend_uidmap_bsearch_cmp,
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen &dest))
6f0bb992c9f55de912295493892651d57e5e9827Timo Sirainen i_unreached();
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen
3281669db44d09a087a203201248abbc81b3cc1aTimo Sirainen /* make space for all added UIDs. */
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen if (rec_count == dest)
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen array_idx_clear(&bbox->uids, dest + add_count-1);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen else {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen array_copy(&bbox->uids.arr, dest + add_count,
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen &bbox->uids.arr, dest, rec_count - dest);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen uidmap = array_get_modifiable(&bbox->uids, &rec_count);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen src = dest + add_count;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen /* add/move the UIDs to their correct positions */
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen i_zero(&rec);
d200ae87140a1985fe527e6527bc4bd3035189b1Timo Sirainen rec.rec.mailbox_id = bbox->mailbox_id;
d200ae87140a1985fe527e6527bc4bd3035189b1Timo Sirainen for (i = 0; i < uid_count; i++) {
d200ae87140a1985fe527e6527bc4bd3035189b1Timo Sirainen add_uid = added_uids[i].seq1;
d200ae87140a1985fe527e6527bc4bd3035189b1Timo Sirainen while (src < rec_count && uidmap[src].real_uid < add_uid)
d200ae87140a1985fe527e6527bc4bd3035189b1Timo Sirainen uidmap[dest++] = uidmap[src++];
a5b331e18b220fac557480b569b85215a1b3bd8eTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen for (; add_uid <= added_uids[i].seq2; add_uid++, dest++) {
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen i_assert(dest < rec_count);
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen uidmap[dest].real_uid = add_uid;
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen uidmap[dest].virtual_uid = 0;
3281669db44d09a087a203201248abbc81b3cc1aTimo Sirainen
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen if (ctx->mbox->uids_mapped) {
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen rec.rec.real_uid = add_uid;
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen array_append(&ctx->all_adds, &rec, 1);
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen}
3281669db44d09a087a203201248abbc81b3cc1aTimo Sirainen
8e361d2906b0e44f7175a20981f8d2280645b58bTimo Sirainenstatic void
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainenvirtual_sync_mailbox_box_update_flags(struct virtual_sync_context *ctx,
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen struct virtual_backend_box *bbox,
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen const ARRAY_TYPE(seq_range) *uids_arr)
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen{
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen unsigned int i, uid, vseq;
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen struct virtual_backend_uidmap *vuid;
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen struct seq_range_iter iter;
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen i = 0;
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen seq_range_array_iter_init(&iter, uids_arr);
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen while(seq_range_array_iter_nth(&iter, i++, &uid)) {
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen vuid = array_bsearch(&bbox->uids, &uid,
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen virtual_backend_uidmap_bsearch_cmp);
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen if (vuid == NULL ||
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen vuid->virtual_uid == 0 ||
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen !mail_index_lookup_seq(ctx->sync_view,
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen vuid->virtual_uid, &vseq)) {
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen /* the entry has been already removed either by
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen us or some other session. doesn't matter,
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen we don't need to update the flags.
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen it might also have not yet been assigned a uid
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen so we don't want to update the flags then either.
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen */
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen continue;
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen }
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen virtual_sync_external_flags(ctx, bbox, vseq,
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen vuid->real_uid);
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen }
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen}
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainenstatic int virtual_backend_uidmap_cmp(const struct virtual_backend_uidmap *u1,
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen const struct virtual_backend_uidmap *u2)
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen{
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen if (u1->real_uid < u2->real_uid)
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen return -1;
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen if (u1->real_uid > u2->real_uid)
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen return 1;
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen return 0;
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen}
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainenstatic void virtual_sync_bbox_uids_sort(struct virtual_backend_box *bbox)
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen{
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen /* the uidmap must be sorted by real_uids */
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen array_sort(&bbox->uids, virtual_backend_uidmap_cmp);
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen bbox->uids_nonsorted = FALSE;
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen}
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainenstatic void virtual_sync_backend_boxes_sort_uids(struct virtual_mailbox *mbox)
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen{
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen struct virtual_backend_box *const *bboxes;
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen unsigned int i, count;
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen bboxes = array_get(&mbox->backend_boxes, &count);
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen for (i = 0; i < count; i++) {
fee561b9d9162b130e662914fcebc9dd99b5c320Timo Sirainen if (bboxes[i]->uids_nonsorted)
cf05507f63b12bd1ee4efffc2f316ebcd9fd7089Timo Sirainen virtual_sync_bbox_uids_sort(bboxes[i]);
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen }
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen}
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainenstatic void
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainenvirtual_sync_backend_add_vmsgs_results(struct virtual_sync_context *ctx,
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen struct virtual_backend_box *bbox,
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen uint32_t real_uid,
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen struct mail_search_result *result,
7f7533a29d0e65876acc0ab9dd56b3d7840c3ee7Timo Sirainen const uint32_t vseq)
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen{
c91de2744f8c1e61e91082ff5e214450f28a0e7cTimo Sirainen struct virtual_backend_uidmap uidmap;
a8012fea2a7315033bc467acbf46be8e7323318cTimo Sirainen uint32_t vuid, seq;
a8012fea2a7315033bc467acbf46be8e7323318cTimo Sirainen
a8012fea2a7315033bc467acbf46be8e7323318cTimo Sirainen mail_index_lookup_uid(ctx->sync_view, vseq, &vuid);
834b90e1f426d1e3308670e09c050bcdea546eb8Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_zero(&uidmap);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uidmap.real_uid = real_uid;
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainen uidmap.virtual_uid = vuid;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen array_append(&bbox->uids, &uidmap, 1);
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen if (result == NULL)
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen ;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen else if (mail_index_lookup_seq(bbox->box->view, real_uid, &seq))
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen seq_range_array_add(&result->uids, real_uid);
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen else
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen seq_range_array_add(&result->removed_uids, real_uid);
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen}
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainenstatic void
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainenvirtual_sync_backend_handle_old_vmsgs(struct virtual_sync_context *ctx,
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen struct virtual_backend_box *bbox,
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen struct mail_search_result *result)
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen{
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen const struct virtual_mail_index_record *vrec;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen const struct virtual_sync_mail *sync_mail, *sync_mails;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen const void *data;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen uint32_t i, vseq, messages;
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen /* find the messages that currently exist in virtual index and add them
c9c24293550541307f1bb41bba4a0fdfe2fa59e0Timo Sirainen to the backend mailbox's list of uids. */
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen array_clear(&bbox->uids);
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen
f2786c07cbd4a7a0a6a46c3e06dc4545aaf2f278Timo Sirainen if (array_is_created(&ctx->all_mails)) {
fadd878cd6098f5b873c21c121209a922679dae4Timo Sirainen i_assert(ctx->all_mails_prev_mailbox_id < bbox->mailbox_id);
b7cf555b699d73f2d71de0dabc088af6a7be3627Timo Sirainen sync_mails = array_get(&ctx->all_mails, &messages);
b88c43d09a288e99d439c78de4cc613212ea924cTimo Sirainen for (i = ctx->all_mails_idx; i < messages; i++) {
b88c43d09a288e99d439c78de4cc613212ea924cTimo Sirainen sync_mail = &sync_mails[i];
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen if (sync_mail->vrec.mailbox_id != bbox->mailbox_id) {
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen if (sync_mail->vrec.mailbox_id < bbox->mailbox_id) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* stale mailbox_id, ignore */
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen continue;
f1e1d821d93e4a1dc6ed8f23febde868b5d64cd5Timo Sirainen }
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen /* Should be in mailbox_id order,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen so skip to next box */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen
a24f6b02ed8d0dde933a715be1c86f01977bf610Timo Sirainen virtual_sync_backend_add_vmsgs_results(ctx, bbox,
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen sync_mail->vrec.real_uid, result, sync_mail->vseq);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen ctx->all_mails_idx = i;
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen ctx->all_mails_prev_mailbox_id = bbox->mailbox_id;
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen } else {
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen /* there should be only a single backend mailbox, but in the
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen existing index there may be stale mailbox_ids that we'll
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen just skip over. */
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen messages = mail_index_view_get_messages_count(ctx->sync_view);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (vseq = 1; vseq <= messages; vseq++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_lookup_ext(ctx->sync_view, vseq,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->mbox->virtual_ext_id, &data, NULL);
075912b4566a79c7bc59bf229c9f629ef7be0ea2Timo Sirainen vrec = data;
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen if (vrec->mailbox_id == bbox->mailbox_id) {
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen virtual_sync_backend_add_vmsgs_results(ctx,
1225a5a7ce39f1d5545d5ed3b84ecd4f72438d36Timo Sirainen bbox, vrec->real_uid, result, vseq);
b5ac20e30146562322ceb7939f044d52d1e51184Timo Sirainen }
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen }
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen }
6eb30032b4a50c383dea4c9c74342d906de6ad36Timo Sirainen virtual_sync_bbox_uids_sort(bbox);
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen}
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainenstatic int virtual_sync_backend_box_continue(struct virtual_sync_context *ctx,
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen struct virtual_backend_box *bbox)
ad48319996942463675b53877092ab7e13a7a75aTimo Sirainen{
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen const enum mailbox_search_result_flags result_flags =
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen MAILBOX_SEARCH_RESULT_FLAG_UPDATE |
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen MAILBOX_SEARCH_RESULT_FLAG_QUEUE_SYNC;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen struct mail_index_view *view = bbox->box->view;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen struct mail_search_result *result;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ARRAY_TYPE(seq_range) expunged_uids = ARRAY_INIT, removed_uids;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ARRAY_TYPE(seq_range) added_uids, flag_update_uids;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint64_t modseq, old_highest_modseq;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t seq, uid, old_msg_count;
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* initialize the search result from all the existing messages in
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen virtual index. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!bbox->search_args_initialized) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_search_args_init(bbox->search_args, bbox->box, FALSE, NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen bbox->search_args_initialized = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen result = mailbox_search_result_alloc(bbox->box, bbox->search_args,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen result_flags);
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen mailbox_search_result_initial_done(result);
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen i_assert(array_count(&result->removed_uids) == 0);
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen virtual_sync_backend_handle_old_vmsgs(ctx, bbox, result);
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen if (array_count(&result->removed_uids) > 0) {
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen /* these are all expunged messages. treat them separately from
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "no longer matching messages" (=removed_uids) */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t_array_init(&expunged_uids, array_count(&result->removed_uids));
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen array_append_array(&expunged_uids, &result->removed_uids);
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen array_clear(&result->removed_uids);
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen }
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen
0c909e3461607eadcd66f4eac69b7f34e37fccf1Timo Sirainen /* get list of changed old messages (messages already once seen by
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen virtual index), based on modseq changes. (we'll assume all modseq
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen changes are due to flag changes, which may not be true in future) */
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen if (bbox->sync_next_uid <= 1 ||
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen !mail_index_lookup_seq_range(view, 1, bbox->sync_next_uid-1,
8bae533c96e129dca8ee7b494d7de5aeb4a043a2Timo Sirainen &seq, &old_msg_count))
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen old_msg_count = 0;
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen old_highest_modseq = mail_index_modseq_get_highest(view);
5f78b33aa505b17e23cdf27b071a24e127b3db54Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t_array_init(&flag_update_uids, I_MIN(128, old_msg_count));
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen if (bbox->sync_highest_modseq < old_highest_modseq) {
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen for (seq = 1; seq <= old_msg_count; seq++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen modseq = mail_index_modseq_lookup(view, seq);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (modseq > bbox->sync_highest_modseq) {
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen mail_index_lookup_uid(view, seq, &uid);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen seq_range_array_add(&flag_update_uids, uid);
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen /* update the search result based on the flag changes and
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen new messages */
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (index_search_result_update_flags(result, &flag_update_uids) < 0 ||
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen index_search_result_update_appends(result, old_msg_count) < 0) {
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen mailbox_search_result_free(&result);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen return -1;
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen }
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen t_array_init(&removed_uids, 128);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen t_array_init(&added_uids, 128);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen mailbox_search_result_sync(result, &removed_uids, &added_uids);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen if (array_is_created(&expunged_uids)) {
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen seq_range_array_remove_seq_range(&removed_uids, &expunged_uids);
95a1a5195d56f3cf5d1e529aad668f87ad3b979bTimo Sirainen virtual_sync_mailbox_box_remove(ctx, bbox, &expunged_uids);
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen }
if (ctx->expunge_removed)
virtual_sync_mailbox_box_remove(ctx, bbox, &removed_uids);
else {
/* delayed remove */
seq_range_array_merge(&bbox->sync_pending_removes,
&removed_uids);
}
virtual_sync_mailbox_box_add(ctx, bbox, &added_uids);
virtual_sync_mailbox_box_update_flags(ctx, bbox, &flag_update_uids);
bbox->search_result = result;
return 0;
}
static void virtual_sync_drop_existing(struct virtual_backend_box *bbox,
ARRAY_TYPE(seq_range) *added_uids)
{
ARRAY_TYPE(seq_range) drop_uids;
const struct virtual_backend_uidmap *uidmap;
struct seq_range_iter iter;
unsigned int i, n = 0, count;
uint32_t add_uid;
seq_range_array_iter_init(&iter, added_uids);
if (!seq_range_array_iter_nth(&iter, n++, &add_uid))
return;
(void)array_bsearch_insert_pos(&bbox->uids, &add_uid,
virtual_backend_uidmap_bsearch_cmp, &i);
uidmap = array_get_modifiable(&bbox->uids, &count);
if (i == count)
return;
t_array_init(&drop_uids, array_count(added_uids));
for (; i < count; ) {
if (uidmap[i].real_uid < add_uid) {
i++;
continue;
}
if (uidmap[i].real_uid == add_uid) {
seq_range_array_add(&drop_uids, add_uid);
i++;
}
if (!seq_range_array_iter_nth(&iter, n++, &add_uid))
break;
}
seq_range_array_remove_seq_range(added_uids, &drop_uids);
}
static void virtual_sync_drop_nonexistent(struct virtual_backend_box *bbox,
ARRAY_TYPE(seq_range) *removed_uids)
{
ARRAY_TYPE(seq_range) drop_uids;
const struct virtual_backend_uidmap *uidmap;
struct seq_range_iter iter;
unsigned int i, n = 0, count;
uint32_t remove_uid;
bool iter_done = FALSE;
seq_range_array_iter_init(&iter, removed_uids);
if (!seq_range_array_iter_nth(&iter, n++, &remove_uid))
return;
(void)array_bsearch_insert_pos(&bbox->uids, &remove_uid,
virtual_backend_uidmap_bsearch_cmp, &i);
t_array_init(&drop_uids, array_count(removed_uids)); iter_done = FALSE;
uidmap = array_get_modifiable(&bbox->uids, &count);
for (; i < count; ) {
if (uidmap[i].real_uid < remove_uid) {
i++;
continue;
}
if (uidmap[i].real_uid != remove_uid)
seq_range_array_add(&drop_uids, remove_uid);
else
i++;
if (!seq_range_array_iter_nth(&iter, n++, &remove_uid)) {
iter_done = TRUE;
break;
}
}
if (!iter_done) {
do {
seq_range_array_add(&drop_uids, remove_uid);
} while (seq_range_array_iter_nth(&iter, n++, &remove_uid));
}
seq_range_array_remove_seq_range(removed_uids, &drop_uids);
}
static void virtual_sync_mailbox_box_update(struct virtual_sync_context *ctx,
struct virtual_backend_box *bbox)
{
ARRAY_TYPE(seq_range) removed_uids, added_uids, temp_uids;
unsigned int count1, count2;
t_array_init(&removed_uids, 128);
t_array_init(&added_uids, 128);
mailbox_search_result_sync(bbox->search_result,
&removed_uids, &added_uids);
if (array_is_created(&bbox->sync_outside_expunges)) {
seq_range_array_remove_seq_range(&bbox->sync_outside_expunges,
&added_uids);
seq_range_array_merge(&removed_uids,
&bbox->sync_outside_expunges);
array_clear(&bbox->sync_outside_expunges);
}
virtual_sync_drop_existing(bbox, &added_uids);
virtual_sync_drop_nonexistent(bbox, &removed_uids);
/* if any of the pending removes came back, we don't want to expunge
them anymore. also since they already exist, remove them from
added_uids. */
count1 = array_count(&bbox->sync_pending_removes);
count2 = array_count(&added_uids);
if (count1 > 0 && count2 > 0) {
t_array_init(&temp_uids, count1);
array_append_array(&temp_uids, &bbox->sync_pending_removes);
if (seq_range_array_remove_seq_range(
&bbox->sync_pending_removes, &added_uids) > 0) {
seq_range_array_remove_seq_range(&added_uids,
&temp_uids);
}
}
if (!ctx->expunge_removed) {
/* delay removing messages that don't match the search
criteria, but don't delay removing expunged messages */
if (array_count(&ctx->sync_expunges) > 0) {
seq_range_array_remove_seq_range(&bbox->sync_pending_removes,
&ctx->sync_expunges);
seq_range_array_remove_seq_range(&removed_uids,
&ctx->sync_expunges);
virtual_sync_mailbox_box_remove(ctx, bbox,
&ctx->sync_expunges);
}
seq_range_array_merge(&bbox->sync_pending_removes,
&removed_uids);
} else if (array_count(&bbox->sync_pending_removes) > 0) {
/* remove all current and old */
seq_range_array_merge(&bbox->sync_pending_removes,
&removed_uids);
virtual_sync_mailbox_box_remove(ctx, bbox,
&bbox->sync_pending_removes);
array_clear(&bbox->sync_pending_removes);
} else {
virtual_sync_mailbox_box_remove(ctx, bbox, &removed_uids);
}
virtual_sync_mailbox_box_add(ctx, bbox, &added_uids);
}
static bool virtual_sync_find_seqs(struct virtual_backend_box *bbox,
const struct mailbox_sync_rec *sync_rec,
unsigned int *idx1_r,
unsigned int *idx2_r)
{
const struct virtual_backend_uidmap *uidmap;
unsigned int idx, count;
uint32_t uid1, uid2;
mail_index_lookup_uid(bbox->box->view, sync_rec->seq1, &uid1);
mail_index_lookup_uid(bbox->box->view, sync_rec->seq2, &uid2);
(void)array_bsearch_insert_pos(&bbox->uids, &uid1,
virtual_backend_uidmap_bsearch_cmp,
&idx);
uidmap = array_get_modifiable(&bbox->uids, &count);
if (idx == count || uidmap[idx].real_uid > uid2)
return FALSE;
*idx1_r = idx;
while (idx < count && uidmap[idx].real_uid <= uid2) idx++;
*idx2_r = idx - 1;
return TRUE;
}
static void virtual_sync_expunge_add(struct virtual_sync_context *ctx,
struct virtual_backend_box *bbox,
const struct mailbox_sync_rec *sync_rec)
{
struct virtual_backend_uidmap *uidmap;
uint32_t uid1, uid2;
unsigned int i, idx1, count;
mail_index_lookup_uid(bbox->box->view, sync_rec->seq1, &uid1);
mail_index_lookup_uid(bbox->box->view, sync_rec->seq2, &uid2);
/* remember only the expunges for messages that
already exist for this mailbox */
(void)array_bsearch_insert_pos(&bbox->uids, &uid1,
virtual_backend_uidmap_bsearch_cmp,
&idx1);
uidmap = array_get_modifiable(&bbox->uids, &count);
for (i = idx1; i < count; i++) {
if (uidmap[i].real_uid > uid2)
break;
seq_range_array_add(&ctx->sync_expunges, uidmap[i].real_uid);
}
}
static int virtual_sync_backend_box_sync(struct virtual_sync_context *ctx,
struct virtual_backend_box *bbox,
enum mailbox_sync_flags sync_flags)
{
struct mailbox_sync_context *sync_ctx;
const struct virtual_backend_uidmap *uidmap;
struct mailbox_sync_rec sync_rec;
struct mailbox_sync_status sync_status;
unsigned int idx1, idx2;
uint32_t vseq, vuid;
sync_ctx = mailbox_sync_init(bbox->box, sync_flags);
virtual_backend_box_sync_mail_set(bbox);
while (mailbox_sync_next(sync_ctx, &sync_rec)) {
switch (sync_rec.type) {
case MAILBOX_SYNC_TYPE_EXPUNGE:
if (ctx->expunge_removed) {
/* no need to keep track of expunges */
break;
}
virtual_sync_expunge_add(ctx, bbox, &sync_rec);
break;
case MAILBOX_SYNC_TYPE_FLAGS:
if (!virtual_sync_find_seqs(bbox, &sync_rec,
&idx1, &idx2))
break;
uidmap = array_idx(&bbox->uids, 0);
for (; idx1 <= idx2; idx1++) {
vuid = uidmap[idx1].virtual_uid;
if (vuid == 0) {
/* has not been even assigned yet */
continue;
}
if (!mail_index_lookup_seq(ctx->sync_view,
vuid, &vseq)) {
/* expunged by another session,
but we haven't yet updated
bbox->uids. */
continue;
}
virtual_sync_external_flags(ctx, bbox, vseq,
uidmap[idx1].real_uid);
}
break;
case MAILBOX_SYNC_TYPE_MODSEQ:
break;
}
}
if (mailbox_sync_deinit(&sync_ctx, &sync_status) < 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;
}
return 0;
}
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->mbox->ext_header_rewrite) {
/* we'll rewrite the entire header later */
return;
}
i_zero(&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);
bbox->deleted = TRUE;
}
static int
virtual_try_open_and_sync_backend_box(struct virtual_sync_context *ctx,
struct virtual_backend_box *bbox,
enum mailbox_sync_flags sync_flags)
{
int ret = 0;
if (!bbox->box->opened)
ret = virtual_backend_box_open(ctx->mbox, bbox);
if (ret == 0)
ret = mailbox_sync(bbox->box, sync_flags);
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;
}
return 1;
}
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;
int ret;
if (bbox->deleted)
return 0;
/* 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->box->opened || bbox->open_failed) {
/* a) index already opened, refresh it
b) delayed error handling for mailbox_open()
that failed in virtual_notify_changes() */
if ((ret = virtual_try_open_and_sync_backend_box(ctx, bbox, sync_flags)) <= 0)
return ret;
bbox->open_failed = FALSE;
}
if (mailbox_get_status(bbox->box, STATUS_UIDVALIDITY |
STATUS_UIDNEXT | STATUS_HIGHESTMODSEQ,
&status) < 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->box->opened) {
/* first time we're opening the index */
if ((ret = virtual_try_open_and_sync_backend_box(ctx, bbox, sync_flags)) <= 0)
return ret;
}
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 */
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->box->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 */
i_zero(&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 */
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;
}
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;
if (bbox->search_result == NULL) {
/* mailbox is completely unchanged since last
sync - no need to sync flags */
} else {
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 */
i_zero(&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;
i_zero(&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_index_expunge(ctx->trans, seq);
continue;
}
}
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);
#ifdef DEBUG
for (i = 0; i < count; i++) {
const struct virtual_backend_uidmap *uidmap;
array_foreach(&bboxes[i]->uids, uidmap)
i_assert(uidmap->virtual_uid > 0);
}
#endif
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;
}
ctx->mbox->ext_header_rewrite = FALSE;
} 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;
bool broken;
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_mailbox_ext_header_read(mbox, ctx->sync_view, &broken);
if (ret < 0)
return virtual_sync_finish(ctx, FALSE);
if (broken)
ctx->index_broken = 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;
}