dsync-mailbox-import.c revision 1c95b8403d2d4dcf35e23fc0a1b51922f120a82a
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen/* Copyright (c) 2012 Dovecot authors, see the included COPYING file */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "lib.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "array.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "hash.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "istream.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "seq-range-array.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "mail-storage-private.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "mail-search-build.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "dsync-transaction-log-scan.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "dsync-mail.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen#include "dsync-mailbox-import.h"
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstruct importer_mail {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const char *guid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uint32_t uid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen};
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstruct importer_new_mail {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* linked list of mails for this GUID */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct importer_new_mail *next;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* if non-NULL, this mail exists in both local and remote. this link
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen points to the other side. */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct importer_new_mail *link;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const char *guid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct dsync_mail_change *change;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uint32_t uid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int uid_in_local:1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int uid_is_usable:1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int skip:1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int copy_failed:1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen};
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
678d0463849ba777106eb7875f27db07a5d8e3dfTimo SirainenHASH_TABLE_DEFINE_TYPE(guid_new_mail, const char *, struct importer_new_mail *);
a75d470c9223a75801418fcdda258885c36317e0Timo SirainenHASH_TABLE_DEFINE_TYPE(uid_new_mail, void *, struct importer_new_mail *);
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstruct dsync_mailbox_importer {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen pool_t pool;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mailbox *box;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uint32_t last_common_uid;
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen uint64_t last_common_modseq, last_common_pvt_modseq;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uint32_t remote_uid_next;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uint32_t remote_first_recent_uid;
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen uint64_t remote_highest_modseq, remote_highest_pvt_modseq;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mailbox_transaction_context *trans, *ext_trans;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mail_search_context *search_ctx;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mail *mail, *ext_mail;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mail *cur_mail;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const char *cur_guid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* UID => struct dsync_mail_change */
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen HASH_TABLE_TYPE(dsync_uid_mail_change) local_changes;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen ARRAY_TYPE(seq_range) maybe_expunge_uids;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen ARRAY(struct dsync_mail_change *) maybe_saves;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* GUID => struct importer_new_mail */
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen HASH_TABLE_TYPE(guid_new_mail) import_guids;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* UID => struct importer_new_mail */
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen HASH_TABLE_TYPE(uid_new_mail) import_uids;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen ARRAY(struct importer_new_mail *) newmails;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen ARRAY_TYPE(uint32_t) wanted_uids;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen ARRAY(struct dsync_mail_request) mail_requests;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int mail_request_idx;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uint32_t prev_uid, next_local_seq, local_uid_next;
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen uint64_t local_initial_highestmodseq, local_initial_highestpvtmodseq;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int failed:1;
307ec6c2c319e3335ddb1a7aca2d2884fe17fae0Timo Sirainen unsigned int debug:1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int last_common_uid_found:1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int cur_uid_has_change:1;
471a6b2b4e64eca5d5779ae20a477312b32c89eeTimo Sirainen unsigned int cur_mail_skip:1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int local_expunged_guids_set:1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int new_uids_assigned:1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int want_mail_requests:1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int mails_have_guids:1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int master_brain:1;
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen unsigned int revert_local_changes:1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen};
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic void
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainendsync_mailbox_import_search_init(struct dsync_mailbox_importer *importer)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mail_search_args *search_args;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mail_search_arg *sarg;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen search_args = mail_search_build_init();
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen sarg = mail_search_build_add(search_args, SEARCH_UIDSET);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen p_array_init(&sarg->value.seqset, search_args->pool, 128);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen seq_range_array_add_range(&sarg->value.seqset,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->last_common_uid+1, (uint32_t)-1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->search_ctx =
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_search_init(importer->trans, search_args, NULL,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen 0, NULL);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mail_search_args_unref(&search_args);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (mailbox_search_next(importer->search_ctx, &importer->cur_mail))
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->next_local_seq = importer->cur_mail->seq;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* this flag causes cur_guid to be looked up later */
471a6b2b4e64eca5d5779ae20a477312b32c89eeTimo Sirainen importer->cur_mail_skip = TRUE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstruct dsync_mailbox_importer *
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainendsync_mailbox_import_init(struct mailbox *box,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct dsync_transaction_log_scan *log_scan,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uint32_t last_common_uid,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uint64_t last_common_modseq,
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen uint64_t last_common_pvt_modseq,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uint32_t remote_uid_next,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uint32_t remote_first_recent_uid,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uint64_t remote_highest_modseq,
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen uint64_t remote_highest_pvt_modseq,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen enum dsync_mailbox_import_flags flags)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const enum mailbox_transaction_flags ext_trans_flags =
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen MAILBOX_TRANSACTION_FLAG_SYNC |
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen MAILBOX_TRANSACTION_FLAG_EXTERNAL |
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen MAILBOX_TRANSACTION_FLAG_ASSIGN_UIDS;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct dsync_mailbox_importer *importer;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mailbox_status status;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen pool_t pool;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen pool = pool_alloconly_create(MEMPOOL_GROWING"dsync mailbox importer",
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen 10240);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer = p_new(pool, struct dsync_mailbox_importer, 1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->pool = pool;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->box = box;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->last_common_uid = last_common_uid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->last_common_modseq = last_common_modseq;
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen importer->last_common_pvt_modseq = last_common_pvt_modseq;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->last_common_uid_found =
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen last_common_uid != 0 || last_common_modseq != 0;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->remote_uid_next = remote_uid_next;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->remote_first_recent_uid = remote_first_recent_uid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->remote_highest_modseq = remote_highest_modseq;
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen importer->remote_highest_pvt_modseq = remote_highest_pvt_modseq;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen hash_table_create(&importer->import_guids, pool, 0, str_hash, strcmp);
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen hash_table_create_direct(&importer->import_uids, pool, 0);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_array_init(&importer->maybe_expunge_uids, 16);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_array_init(&importer->maybe_saves, 128);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_array_init(&importer->newmails, 128);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_array_init(&importer->wanted_uids, 128);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->trans = mailbox_transaction_begin(importer->box,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen MAILBOX_TRANSACTION_FLAG_SYNC);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->ext_trans = mailbox_transaction_begin(box, ext_trans_flags);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->mail = mail_alloc(importer->trans, 0, NULL);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->ext_mail = mail_alloc(importer->ext_trans, 0, NULL);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if ((flags & DSYNC_MAILBOX_IMPORT_FLAG_WANT_MAIL_REQUESTS) != 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_array_init(&importer->mail_requests, 128);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->want_mail_requests = TRUE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->mails_have_guids =
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen (flags & DSYNC_MAILBOX_IMPORT_FLAG_MAILS_HAVE_GUIDS) != 0;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->master_brain =
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen (flags & DSYNC_MAILBOX_IMPORT_FLAG_MASTER_BRAIN) != 0;
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen importer->revert_local_changes =
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen (flags & DSYNC_MAILBOX_IMPORT_FLAG_REVERT_LOCAL_CHANGES) != 0;
307ec6c2c319e3335ddb1a7aca2d2884fe17fae0Timo Sirainen importer->debug = (flags & DSYNC_MAILBOX_IMPORT_FLAG_DEBUG) != 0;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen mailbox_get_open_status(importer->box, STATUS_UIDNEXT |
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen STATUS_HIGHESTMODSEQ | STATUS_HIGHESTPVTMODSEQ,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen &status);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->local_uid_next = status.uidnext;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->local_initial_highestmodseq = status.highest_modseq;
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen importer->local_initial_highestpvtmodseq = status.highest_pvt_modseq;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_mailbox_import_search_init(importer);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
08e9fec5ba9e1a26e658c4224207d666b6ced27dTimo Sirainen importer->local_changes = dsync_transaction_log_scan_get_hash(log_scan);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return importer;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainenstatic void dsync_mail_error(struct dsync_mailbox_importer *importer,
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen struct mail *mail, const char *field)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const char *errstr;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen enum mail_error error;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen errstr = mailbox_get_last_error(importer->box, &error);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (error == MAIL_ERROR_EXPUNGED)
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen return;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_error("Can't lookup %s for UID=%u: %s", field, mail->uid, errstr);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->failed = TRUE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic bool
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenimporter_next_mail(struct dsync_mailbox_importer *importer, uint32_t wanted_uid)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (importer->cur_mail == NULL) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* end of search */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return FALSE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen while (importer->cur_mail->seq < importer->next_local_seq ||
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->cur_mail->uid < wanted_uid) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (!importer->cur_uid_has_change &&
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen !importer->last_common_uid_found) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* this message exists locally, but remote didn't send
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen expunge-change for it. if the message's
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uid <= last-common-uid, it should be deleted */
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen seq_range_array_add(&importer->maybe_expunge_uids,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->cur_mail->uid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
471a6b2b4e64eca5d5779ae20a477312b32c89eeTimo Sirainen importer->cur_mail_skip = FALSE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (!mailbox_search_next(importer->search_ctx,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen &importer->cur_mail)) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->cur_mail = NULL;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->cur_guid = NULL;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return FALSE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->cur_uid_has_change = FALSE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->cur_uid_has_change = importer->cur_mail != NULL &&
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->cur_mail->uid == wanted_uid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (mail_get_special(importer->cur_mail, MAIL_FETCH_GUID,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen &importer->cur_guid) < 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_mail_error(importer, importer->cur_mail, "GUID");
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return importer_next_mail(importer, wanted_uid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* make sure next_local_seq gets updated in case we came here
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen because of min_uid */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->next_local_seq = importer->cur_mail->seq;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return TRUE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic int
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenimporter_mail_cmp(const struct importer_mail *m1,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const struct importer_mail *m2)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen int ret;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (m1->guid == NULL)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return 1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (m2->guid == NULL)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return -1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen ret = strcmp(m1->guid, m2->guid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (ret != 0)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return ret;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (m1->uid < m2->uid)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return -1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (m1->uid > m2->uid)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return 1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return 0;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic void importer_mail_request(struct dsync_mailbox_importer *importer,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct importer_new_mail *newmail)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct dsync_mail_request *request;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (importer->want_mail_requests && !newmail->uid_in_local) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen request = array_append_space(&importer->mail_requests);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen request->guid = newmail->guid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen request->uid = newmail->uid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic void newmail_link(struct dsync_mailbox_importer *importer,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct importer_new_mail *newmail)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct importer_new_mail *first_mail, **last, *mail, *link = NULL;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (*newmail->guid != '\0') {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen first_mail = hash_table_lookup(importer->import_guids,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen newmail->guid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (first_mail == NULL) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* first mail for this GUID */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen hash_table_insert(importer->import_guids,
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen newmail->guid, newmail);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer_mail_request(importer, newmail);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen } else {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (!newmail->uid_in_local) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* FIXME: ? */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen first_mail = hash_table_lookup(importer->import_uids,
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen POINTER_CAST(newmail->uid));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (first_mail == NULL) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* first mail for this UID */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen hash_table_insert(importer->import_uids,
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen POINTER_CAST(newmail->uid), newmail);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer_mail_request(importer, newmail);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* 1) add the newmail to the end of the linked list
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen 2) find our link */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen last = &first_mail->next;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen for (mail = first_mail; mail != NULL; mail = mail->next) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (mail->uid == newmail->uid)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mail->uid_is_usable = TRUE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (link == NULL && mail->link == NULL &&
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mail->uid_in_local != newmail->uid_in_local)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen link = mail;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen last = &mail->next;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen *last = newmail;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (link != NULL && newmail->link == NULL) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen link->link = newmail;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen newmail->link = link;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic bool dsync_mailbox_try_save_cur(struct dsync_mailbox_importer *importer,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct dsync_mail_change *save_change)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct importer_mail m1, m2;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct importer_new_mail *newmail;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen int diff;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen bool remote_saved;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen memset(&m1, 0, sizeof(m1));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (importer->cur_mail != NULL) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen m1.guid = importer->cur_guid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen m1.uid = importer->cur_mail->uid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen memset(&m2, 0, sizeof(m2));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (save_change != NULL) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen m2.guid = save_change->guid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen m2.uid = save_change->uid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen diff = importer_mail_cmp(&m1, &m2);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (diff < 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* add a record for local mail */
3ea86ed7cf06ba04e4aa6cd1c4df9be336c06cd3Timo Sirainen i_assert(importer->cur_mail != NULL);
471a6b2b4e64eca5d5779ae20a477312b32c89eeTimo Sirainen if (importer->revert_local_changes) {
471a6b2b4e64eca5d5779ae20a477312b32c89eeTimo Sirainen mail_expunge(importer->cur_mail);
471a6b2b4e64eca5d5779ae20a477312b32c89eeTimo Sirainen importer->cur_mail_skip = TRUE;
471a6b2b4e64eca5d5779ae20a477312b32c89eeTimo Sirainen importer->next_local_seq++;
471a6b2b4e64eca5d5779ae20a477312b32c89eeTimo Sirainen return FALSE;
471a6b2b4e64eca5d5779ae20a477312b32c89eeTimo Sirainen }
471a6b2b4e64eca5d5779ae20a477312b32c89eeTimo Sirainen newmail = p_new(importer->pool, struct importer_new_mail, 1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen newmail->guid = p_strdup(importer->pool, importer->cur_guid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen newmail->uid = importer->cur_mail->uid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen newmail->uid_in_local = TRUE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen newmail->uid_is_usable =
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen newmail->uid >= importer->remote_uid_next;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen remote_saved = FALSE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen } else if (diff > 0) {
3ea86ed7cf06ba04e4aa6cd1c4df9be336c06cd3Timo Sirainen i_assert(save_change != NULL);
471a6b2b4e64eca5d5779ae20a477312b32c89eeTimo Sirainen newmail = p_new(importer->pool, struct importer_new_mail, 1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen newmail->guid = save_change->guid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen newmail->uid = save_change->uid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen newmail->uid_in_local = FALSE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen newmail->uid_is_usable =
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen newmail->uid >= importer->local_uid_next;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen remote_saved = TRUE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen } else {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* identical */
3ea86ed7cf06ba04e4aa6cd1c4df9be336c06cd3Timo Sirainen i_assert(importer->cur_mail != NULL);
3ea86ed7cf06ba04e4aa6cd1c4df9be336c06cd3Timo Sirainen i_assert(save_change != NULL);
471a6b2b4e64eca5d5779ae20a477312b32c89eeTimo Sirainen newmail = p_new(importer->pool, struct importer_new_mail, 1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen newmail->guid = save_change->guid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen newmail->uid = importer->cur_mail->uid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen newmail->uid_in_local = TRUE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen newmail->uid_is_usable = TRUE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen newmail->link = newmail;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen remote_saved = TRUE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (newmail->uid_in_local) {
471a6b2b4e64eca5d5779ae20a477312b32c89eeTimo Sirainen importer->cur_mail_skip = TRUE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->next_local_seq++;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen } else {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* NOTE: assumes save_change is allocated from importer pool */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen newmail->change = save_change;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_append(&importer->newmails, &newmail, 1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen newmail_link(importer, newmail);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return remote_saved;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainenstatic bool ATTR_NULL(2)
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainendsync_mailbox_try_save(struct dsync_mailbox_importer *importer,
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen struct dsync_mail_change *save_change)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
471a6b2b4e64eca5d5779ae20a477312b32c89eeTimo Sirainen if (importer->cur_mail_skip) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (!importer_next_mail(importer, 0) && save_change == NULL)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return FALSE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return dsync_mailbox_try_save_cur(importer, save_change);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic void dsync_mailbox_save(struct dsync_mailbox_importer *importer,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct dsync_mail_change *save_change)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen while (!dsync_mailbox_try_save(importer, save_change)) ;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic bool
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainendsync_import_set_mail(struct dsync_mailbox_importer *importer,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const struct dsync_mail_change *change)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const char *guid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (!mail_set_uid(importer->mail, change->uid))
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return FALSE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (change->guid == NULL) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* GUID is unknown */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return TRUE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (*change->guid == '\0') {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* backend doesn't support GUIDs. if hdr_hash is set, we could
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen verify it, but since this message really is supposed to
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen match, it's probably too much trouble. */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return TRUE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* verify that GUID matches, just in case */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (mail_get_special(importer->mail, MAIL_FETCH_GUID, &guid) < 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_mail_error(importer, importer->mail, "GUID");
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return FALSE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (strcmp(guid, change->guid) != 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_error("Mailbox %s: Unexpected GUID mismatch for "
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen "UID=%u: %s != %s", mailbox_get_vname(importer->box),
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen change->uid, guid, change->guid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->last_common_uid = 1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->failed = TRUE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return FALSE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return TRUE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
cd70f7aec3bf49147fa80b77dd7ede7d7697202eTimo Sirainenstatic bool dsync_check_cur_guid(struct dsync_mailbox_importer *importer,
cd70f7aec3bf49147fa80b77dd7ede7d7697202eTimo Sirainen const struct dsync_mail_change *change)
cd70f7aec3bf49147fa80b77dd7ede7d7697202eTimo Sirainen{
cd70f7aec3bf49147fa80b77dd7ede7d7697202eTimo Sirainen if (change->guid == NULL || *change->guid == '\0')
cd70f7aec3bf49147fa80b77dd7ede7d7697202eTimo Sirainen return TRUE;
cd70f7aec3bf49147fa80b77dd7ede7d7697202eTimo Sirainen if (strcmp(importer->cur_guid, change->guid) != 0) {
cd70f7aec3bf49147fa80b77dd7ede7d7697202eTimo Sirainen i_error("Mailbox %s: Unexpected GUID mismatch for "
cd70f7aec3bf49147fa80b77dd7ede7d7697202eTimo Sirainen "UID=%u: %s != %s", mailbox_get_vname(importer->box),
cd70f7aec3bf49147fa80b77dd7ede7d7697202eTimo Sirainen change->uid, importer->cur_guid, change->guid);
cd70f7aec3bf49147fa80b77dd7ede7d7697202eTimo Sirainen importer->last_common_uid = 1;
cd70f7aec3bf49147fa80b77dd7ede7d7697202eTimo Sirainen importer->failed = TRUE;
cd70f7aec3bf49147fa80b77dd7ede7d7697202eTimo Sirainen return FALSE;
cd70f7aec3bf49147fa80b77dd7ede7d7697202eTimo Sirainen }
cd70f7aec3bf49147fa80b77dd7ede7d7697202eTimo Sirainen return TRUE;
cd70f7aec3bf49147fa80b77dd7ede7d7697202eTimo Sirainen}
cd70f7aec3bf49147fa80b77dd7ede7d7697202eTimo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic void
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenmerge_flags(uint32_t local_final, uint32_t local_add, uint32_t local_remove,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uint32_t remote_final, uint32_t remote_add, uint32_t remote_remove,
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen uint32_t pvt_mask, bool prefer_remote, bool prefer_pvt_remote,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uint32_t *change_add_r, uint32_t *change_remove_r)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uint32_t combined_add, combined_remove, conflict_flags;
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen uint32_t local_wanted, remote_wanted, conflict_pvt_flags;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* resolve conflicts */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen conflict_flags = local_add & remote_remove;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (conflict_flags != 0) {
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen conflict_pvt_flags = conflict_flags & pvt_mask;
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen conflict_flags &= ~pvt_mask;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (prefer_remote)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen local_add &= ~conflict_flags;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen else
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen remote_remove &= ~conflict_flags;
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen if (prefer_pvt_remote)
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen local_add &= ~conflict_pvt_flags;
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen else
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen remote_remove &= ~conflict_pvt_flags;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen conflict_flags = (local_remove & remote_add) & ~pvt_mask;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (conflict_flags != 0) {
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen conflict_pvt_flags = conflict_flags & pvt_mask;
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen conflict_flags &= ~pvt_mask;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (prefer_remote)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen local_remove &= ~conflict_flags;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen else
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen remote_add &= ~conflict_flags;
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen if (prefer_pvt_remote)
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen local_remove &= ~conflict_pvt_flags;
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen else
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen remote_add &= ~conflict_pvt_flags;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen combined_add = local_add|remote_add;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen combined_remove = local_remove|remote_remove;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert((combined_add & combined_remove) == 0);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* see if there are conflicting final flags */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen local_wanted = (local_final|combined_add) & ~combined_remove;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen remote_wanted = (remote_final|combined_add) & ~combined_remove;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen conflict_flags = local_wanted ^ remote_wanted;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (conflict_flags != 0) {
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen if (prefer_remote && prefer_pvt_remote)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen local_wanted = remote_wanted;
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen else if (prefer_remote && !prefer_pvt_remote) {
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen local_wanted = (local_wanted & pvt_mask) |
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen (remote_wanted & ~pvt_mask);
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen } else if (!prefer_remote && prefer_pvt_remote) {
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen local_wanted = (local_wanted & ~pvt_mask) |
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen (remote_wanted & pvt_mask);
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen *change_add_r = local_wanted & ~local_final;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen *change_remove_r = local_final & ~local_wanted;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic bool
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenkeyword_find(ARRAY_TYPE(const_string) *keywords, const char *name,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int *idx_r)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const char *const *names;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int i, count;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen names = array_get(keywords, &count);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen for (i = 0; i < count; i++) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (strcmp(names[i], name) == 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen *idx_r = i;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return TRUE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return FALSE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic void keywords_append(ARRAY_TYPE(const_string) *dest,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const ARRAY_TYPE(const_string) *keywords,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uint32_t bits, unsigned int start_idx)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const char *const *namep;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int i;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen for (i = 0; i < 32; i++) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if ((bits & (1U << i)) == 0)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen continue;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen namep = array_idx(keywords, start_idx+i);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_append(dest, namep, 1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic void
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenmerge_keywords(struct mail *mail, const ARRAY_TYPE(const_string) *local_changes,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const ARRAY_TYPE(const_string) *remote_changes,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen bool prefer_remote)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* local_changes and remote_changes are assumed to have no
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen duplicates names */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uint32_t *local_add, *local_remove, *local_final;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uint32_t *remote_add, *remote_remove, *remote_final;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uint32_t *change_add, *change_remove;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen ARRAY_TYPE(const_string) all_keywords, add_keywords, remove_keywords;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const char *const *changes, *name, *const *local_keywords;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mail_keywords *kw;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int i, count, name_idx, array_size;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen local_keywords = mail_get_keywords(mail);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* we'll assign a common index for each keyword name and place
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen the changes to separate bit arrays. */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (array_is_created(remote_changes))
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen changes = array_get(remote_changes, &count);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen else {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen changes = NULL;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen count = 0;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_size = str_array_length(local_keywords) + count;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (array_is_created(local_changes))
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_size += array_count(local_changes);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (array_size == 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* this message has no keywords */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen t_array_init(&all_keywords, array_size);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen t_array_init(&add_keywords, array_size);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen t_array_init(&remove_keywords, array_size);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* @UNSAFE: create large enough arrays to fit all keyword indexes. */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_size = (array_size+31)/32;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen local_add = t_new(uint32_t, array_size);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen local_remove = t_new(uint32_t, array_size);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen local_final = t_new(uint32_t, array_size);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen remote_add = t_new(uint32_t, array_size);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen remote_remove = t_new(uint32_t, array_size);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen remote_final = t_new(uint32_t, array_size);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen change_add = t_new(uint32_t, array_size);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen change_remove = t_new(uint32_t, array_size);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* get remote changes */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen for (i = 0; i < count; i++) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen name = changes[i]+1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen name_idx = array_count(&all_keywords);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_append(&all_keywords, &name, 1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen switch (changes[i][0]) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen case KEYWORD_CHANGE_ADD:
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen remote_add[name_idx/32] |= 1U << (name_idx%32);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* fall through */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen case KEYWORD_CHANGE_FINAL:
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen remote_final[name_idx/32] |= 1U << (name_idx%32);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen break;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen case KEYWORD_CHANGE_REMOVE:
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen remote_remove[name_idx/32] |= 1U << (name_idx%32);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen break;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* get local changes. use existing indexes for names when they exist. */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (array_is_created(local_changes))
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen changes = array_get(local_changes, &count);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen else {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen changes = NULL;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen count = 0;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen for (i = 0; i < count; i++) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen name = changes[i]+1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (!keyword_find(&all_keywords, name, &name_idx)) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen name_idx = array_count(&all_keywords);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_append(&all_keywords, &name, 1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen switch (changes[i][0]) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen case KEYWORD_CHANGE_ADD:
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen local_add[name_idx/32] |= 1U << (name_idx%32);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen break;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen case KEYWORD_CHANGE_REMOVE:
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen local_remove[name_idx/32] |= 1U << (name_idx%32);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen break;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen case KEYWORD_CHANGE_FINAL:
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_unreached();
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen for (i = 0; local_keywords[i] != NULL; i++) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen name = local_keywords[i];
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (!keyword_find(&all_keywords, name, &name_idx)) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen name_idx = array_count(&all_keywords);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_append(&all_keywords, &name, 1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen local_final[name_idx/32] |= 1U << (name_idx%32);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(array_count(&all_keywords) <= array_size*32);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_size = (array_count(&all_keywords)+31) / 32;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* merge keywords */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen for (i = 0; i < array_size; i++) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen merge_flags(local_final[i], local_add[i], local_remove[i],
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen remote_final[i], remote_add[i], remote_remove[i],
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen 0, prefer_remote, prefer_remote,
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen &change_add[i], &change_remove[i]);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (change_add[i] != 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen keywords_append(&add_keywords, &all_keywords,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen change_add[i], i*32);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (change_remove[i] != 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen keywords_append(&remove_keywords, &all_keywords,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen change_add[i], i*32);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* apply changes */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (array_count(&add_keywords) > 0) {
31a574fda352ef4f71dbff9c30e15e4744e132c0Timo Sirainen array_append_zero(&add_keywords);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen kw = mailbox_keywords_create_valid(mail->box,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_idx(&add_keywords, 0));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mail_update_keywords(mail, MODIFY_ADD, kw);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_keywords_unref(&kw);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (array_count(&remove_keywords) > 0) {
31a574fda352ef4f71dbff9c30e15e4744e132c0Timo Sirainen array_append_zero(&remove_keywords);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen kw = mailbox_keywords_create_valid(mail->box,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_idx(&remove_keywords, 0));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mail_update_keywords(mail, MODIFY_REMOVE, kw);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_keywords_unref(&kw);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainenstatic void
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainendsync_mailbox_import_replace_flags(struct mail *mail,
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen const struct dsync_mail_change *change)
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen{
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen ARRAY_TYPE(const_string) keywords;
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen struct mail_keywords *kw;
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen const char *const *changes, *name;
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen unsigned int i, count;
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen if (array_is_created(&change->keyword_changes))
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen changes = array_get(&change->keyword_changes, &count);
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen else {
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen changes = NULL;
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen count = 0;
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen }
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen t_array_init(&keywords, count+1);
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen for (i = 0; i < count; i++) {
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen switch (changes[i][0]) {
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen case KEYWORD_CHANGE_ADD:
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen case KEYWORD_CHANGE_FINAL:
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen name = changes[i]+1;
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen array_append(&keywords, &name, 1);
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen break;
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen case KEYWORD_CHANGE_REMOVE:
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen break;
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen }
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen }
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen array_append_zero(&keywords);
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen kw = mailbox_keywords_create_valid(mail->box, array_idx(&keywords, 0));
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen mail_update_keywords(mail, MODIFY_REPLACE, kw);
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen mailbox_keywords_unref(&kw);
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen mail_update_flags(mail, MODIFY_REPLACE,
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen change->add_flags | change->final_flags);
ccd7b4e0a5f09058a59cc4b3f878254e93e7cb0aTimo Sirainen if (mail_get_modseq(mail) < change->modseq)
ccd7b4e0a5f09058a59cc4b3f878254e93e7cb0aTimo Sirainen mail_update_modseq(mail, change->modseq);
ccd7b4e0a5f09058a59cc4b3f878254e93e7cb0aTimo Sirainen if (mail_get_pvt_modseq(mail) < change->pvt_modseq)
ccd7b4e0a5f09058a59cc4b3f878254e93e7cb0aTimo Sirainen mail_update_pvt_modseq(mail, change->pvt_modseq);
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen}
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic void
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainendsync_mailbox_import_flag_change(struct dsync_mailbox_importer *importer,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const struct dsync_mail_change *change)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const struct dsync_mail_change *local_change;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen enum mail_flags local_add, local_remove;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uint32_t change_add, change_remove;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen ARRAY_TYPE(const_string) local_keyword_changes = ARRAY_INIT;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mail *mail;
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen bool prefer_remote, prefer_pvt_remote;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert((change->add_flags & change->remove_flags) == 0);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (importer->cur_mail != NULL &&
cd70f7aec3bf49147fa80b77dd7ede7d7697202eTimo Sirainen importer->cur_mail->uid == change->uid) {
cd70f7aec3bf49147fa80b77dd7ede7d7697202eTimo Sirainen if (!dsync_check_cur_guid(importer, change))
cd70f7aec3bf49147fa80b77dd7ede7d7697202eTimo Sirainen return;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mail = importer->cur_mail;
cd70f7aec3bf49147fa80b77dd7ede7d7697202eTimo Sirainen } else {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (!dsync_import_set_mail(importer, change))
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mail = importer->mail;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen if (importer->revert_local_changes) {
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen /* dsync backup: just make the local look like remote. */
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen dsync_mailbox_import_replace_flags(mail, change);
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen return;
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen }
efeb13303798b47d2c4295468d233c1bcfd79c94Timo Sirainen
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen local_change = hash_table_lookup(importer->local_changes,
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen POINTER_CAST(change->uid));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (local_change == NULL) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen local_add = local_remove = 0;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen } else {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen local_add = local_change->add_flags;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen local_remove = local_change->remove_flags;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen local_keyword_changes = local_change->keyword_changes;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (mail_get_modseq(mail) < change->modseq)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen prefer_remote = TRUE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen else if (mail_get_modseq(mail) > change->modseq)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen prefer_remote = FALSE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen else {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* identical modseq, we'll just have to pick one.
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen Note that both brains need to pick the same one, otherwise
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen they become unsynced. */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen prefer_remote = !importer->master_brain;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen if (mail_get_pvt_modseq(mail) < change->pvt_modseq)
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen prefer_pvt_remote = TRUE;
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen else if (mail_get_pvt_modseq(mail) > change->pvt_modseq)
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen prefer_pvt_remote = FALSE;
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen else
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen prefer_pvt_remote = !importer->master_brain;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* merge flags */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen merge_flags(mail_get_flags(mail), local_add, local_remove,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen change->final_flags, change->add_flags, change->remove_flags,
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen mailbox_get_private_flags_mask(mail->box),
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen prefer_remote, prefer_pvt_remote,
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen &change_add, &change_remove);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (change_add != 0)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mail_update_flags(mail, MODIFY_ADD, change_add);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (change_remove != 0)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mail_update_flags(mail, MODIFY_REMOVE, change_remove);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* merge keywords */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen merge_keywords(mail, &local_keyword_changes, &change->keyword_changes,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen prefer_remote);
ccd7b4e0a5f09058a59cc4b3f878254e93e7cb0aTimo Sirainen if (mail_get_modseq(mail) < change->modseq)
ccd7b4e0a5f09058a59cc4b3f878254e93e7cb0aTimo Sirainen mail_update_modseq(mail, change->modseq);
ccd7b4e0a5f09058a59cc4b3f878254e93e7cb0aTimo Sirainen if (mail_get_pvt_modseq(mail) < change->pvt_modseq)
ccd7b4e0a5f09058a59cc4b3f878254e93e7cb0aTimo Sirainen mail_update_pvt_modseq(mail, change->pvt_modseq);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic void
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainendsync_mailbox_import_save(struct dsync_mailbox_importer *importer,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const struct dsync_mail_change *change)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct dsync_mail_change *save;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(change->guid != NULL);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (change->uid == importer->last_common_uid) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* we've already verified that the GUID matches.
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen apply flag changes if there are any. */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(!importer->last_common_uid_found);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_mailbox_import_flag_change(importer, change);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen save = p_new(importer->pool, struct dsync_mail_change, 1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_mail_change_dup(importer->pool, change, save);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (importer->last_common_uid_found) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* this is a new mail. its UID may or may not conflict with
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen an existing local mail, we'll figure it out later. */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(change->uid > importer->last_common_uid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_mailbox_save(importer, save);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen } else {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* the local mail is expunged. we'll decide later if we want
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen to save this mail locally or expunge it form remote. */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(change->uid > importer->last_common_uid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(change->uid < importer->cur_mail->uid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_append(&importer->maybe_saves, &save, 1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic void
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainendsync_mailbox_import_expunge(struct dsync_mailbox_importer *importer,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const struct dsync_mail_change *change)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (importer->last_common_uid_found) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* expunge the message, unless its GUID unexpectedly doesn't
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen match */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(change->uid <= importer->last_common_uid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (dsync_import_set_mail(importer, change))
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mail_expunge(importer->mail);
d8504a5ac72efb86a8da852c8d814ccaf0ae8625Timo Sirainen } else if (importer->cur_mail == NULL ||
d8504a5ac72efb86a8da852c8d814ccaf0ae8625Timo Sirainen change->uid < importer->cur_mail->uid) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* already expunged locally, we can ignore this.
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uid=last_common_uid if we managed to verify from
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen transaction log that the GUIDs match */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(change->uid >= importer->last_common_uid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen } else if (change->uid == importer->last_common_uid) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* already verified that the GUID matches */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(importer->cur_mail->uid == change->uid);
cd70f7aec3bf49147fa80b77dd7ede7d7697202eTimo Sirainen if (dsync_check_cur_guid(importer, change))
cd70f7aec3bf49147fa80b77dd7ede7d7697202eTimo Sirainen mail_expunge(importer->cur_mail);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen } else {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* we don't know yet if we should expunge this
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen message or not. queue it until we do. */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(change->uid > importer->last_common_uid);
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainen seq_range_array_add(&importer->maybe_expunge_uids, change->uid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic void
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainendsync_mailbox_rewind_search(struct dsync_mailbox_importer *importer)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* If there are local mails after last_common_uid which we skipped
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen while trying to match the next message, we need to now go back */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (importer->cur_mail != NULL &&
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->cur_mail->uid <= importer->last_common_uid+1)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->cur_mail = NULL;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->cur_guid = NULL;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->next_local_seq = 0;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen (void)mailbox_search_deinit(&importer->search_ctx);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_mailbox_import_search_init(importer);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic void
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainendsync_mailbox_common_uid_found(struct dsync_mailbox_importer *importer)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct dsync_mail_change *const *saves;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct seq_range_iter iter;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int n, i, count;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uint32_t uid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->last_common_uid_found = TRUE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_mailbox_rewind_search(importer);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* expunge the messages whose expunge-decision we delayed previously */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen seq_range_array_iter_init(&iter, &importer->maybe_expunge_uids); n = 0;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen while (seq_range_array_iter_nth(&iter, n++, &uid)) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (uid > importer->last_common_uid) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* we expunge messages only up to last_common_uid,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen ignore the rest */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen break;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (mail_set_uid(importer->mail, uid))
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mail_expunge(importer->mail);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* handle pending saves */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen saves = array_get(&importer->maybe_saves, &count);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen for (i = 0; i < count; i++) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (saves[i]->uid > importer->last_common_uid)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_mailbox_save(importer, saves[i]);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic int
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainendsync_mailbox_import_match_msg(struct dsync_mailbox_importer *importer,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const struct dsync_mail_change *change)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const char *hdr_hash;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (*change->guid != '\0' && *importer->cur_guid != '\0') {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* we have GUIDs, verify them */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return strcmp(change->guid, importer->cur_guid) == 0 ? 1 : 0;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* verify hdr_hash if it exists */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (change->hdr_hash == NULL) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(*importer->cur_guid == '\0');
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_error("Mailbox %s: GUIDs not supported, "
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen "sync with header hashes instead",
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_get_vname(importer->box));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->failed = TRUE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return -1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (dsync_mail_get_hdr_hash(importer->cur_mail, &hdr_hash) < 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_mail_error(importer, importer->cur_mail, "hdr-stream");
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return -1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return strcmp(change->hdr_hash, hdr_hash) == 0 ? 1 : 0;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainenstatic bool
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainendsync_mailbox_find_common_expunged_uid(struct dsync_mailbox_importer *importer,
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen const struct dsync_mail_change *change)
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen{
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen const struct dsync_mail_change *local_change;
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen guid_128_t guid_128, change_guid_128;
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen if (*change->guid == '\0') {
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen /* remote doesn't support GUIDs, can't verify expunge */
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen return FALSE;
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen }
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen /* local message is expunged. see if we can find its GUID from
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen transaction log and check if the GUIDs match. The GUID in
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen log is a 128bit GUID, so we may need to convert the remote's
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen GUID string to 128bit GUID first. */
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen local_change = hash_table_lookup(importer->local_changes,
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen POINTER_CAST(change->uid));
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen if (local_change == NULL || local_change->guid == NULL)
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen return FALSE;
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen if (guid_128_from_string(local_change->guid, guid_128) < 0)
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen i_unreached();
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen mail_generate_guid_128_hash(change->guid, change_guid_128);
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen if (memcmp(change_guid_128, guid_128, GUID_128_SIZE) != 0) {
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen /* mismatch - found the first non-common UID */
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen dsync_mailbox_common_uid_found(importer);
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen } else {
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen importer->last_common_uid = change->uid;
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen }
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen return TRUE;
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen}
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic void
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainendsync_mailbox_find_common_uid(struct dsync_mailbox_importer *importer,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const struct dsync_mail_change *change)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen int ret;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* try to find the matching local mail */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (!importer_next_mail(importer, change->uid)) {
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen /* no more local mails. we can still try to match
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen expunged mails though. */
a5f297ac8cb8fb168edabf9fe93a7061539a0afaTimo Sirainen if (change->type == DSYNC_MAIL_CHANGE_TYPE_EXPUNGE) {
a5f297ac8cb8fb168edabf9fe93a7061539a0afaTimo Sirainen /* mail doesn't exist remotely either, don't bother
a5f297ac8cb8fb168edabf9fe93a7061539a0afaTimo Sirainen looking it up locally. */
a5f297ac8cb8fb168edabf9fe93a7061539a0afaTimo Sirainen return;
a5f297ac8cb8fb168edabf9fe93a7061539a0afaTimo Sirainen }
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen if (change->guid == NULL ||
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen !dsync_mailbox_find_common_expunged_uid(importer, change)) {
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen /* couldn't match it for an expunged mail. use the last
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen message with a matching GUID as the last common
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen UID. */
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen dsync_mailbox_common_uid_found(importer);
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (change->guid == NULL) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* we can't know if this UID matches */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (importer->cur_mail->uid == change->uid) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* we have a matching local UID. check GUID to see if it's
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen really the same mail or not */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if ((ret = dsync_mailbox_import_match_msg(importer, change)) < 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* unknown */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (ret == 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* mismatch - found the first non-common UID */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_mailbox_common_uid_found(importer);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen } else {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->last_common_uid = change->uid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
f3053c3637f64633c8ef642e1b9b689b333ebf73Timo Sirainen dsync_mailbox_find_common_expunged_uid(importer, change);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenvoid dsync_mailbox_import_change(struct dsync_mailbox_importer *importer,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const struct dsync_mail_change *change)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(!importer->new_uids_assigned);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(importer->prev_uid < change->uid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->prev_uid = change->uid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (!importer->last_common_uid_found)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_mailbox_find_common_uid(importer, change);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (importer->last_common_uid_found) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* a) uid <= last_common_uid for flag changes and expunges.
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen this happens only when last_common_uid was originally given
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen as parameter to importer.
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen when we're finding the last_common_uid ourself,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uid>last_common_uid always in here, because
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen last_common_uid_found=TRUE only after we find the first
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mismatch.
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen b) uid > last_common_uid for i) new messages, ii) expunges
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen that were sent "just in case" */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (change->uid <= importer->last_common_uid) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(change->type != DSYNC_MAIL_CHANGE_TYPE_SAVE);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen } else if (change->type == DSYNC_MAIL_CHANGE_TYPE_EXPUNGE) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* ignore */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen } else {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(change->type == DSYNC_MAIL_CHANGE_TYPE_SAVE);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen } else {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* a) uid < last_common_uid can never happen */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(change->uid >= importer->last_common_uid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* b) uid = last_common_uid if we've verified that the
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen messages' GUIDs match so far.
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen c) uid > last_common_uid: i) TYPE_EXPUNGE change has
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen GUID=NULL, so we couldn't verify yet if it matches our
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen local message, ii) local message is expunged and we couldn't
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen find its GUID */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (change->uid > importer->last_common_uid) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(change->type == DSYNC_MAIL_CHANGE_TYPE_EXPUNGE ||
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen change->uid < importer->cur_mail->uid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen switch (change->type) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen case DSYNC_MAIL_CHANGE_TYPE_SAVE:
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_mailbox_import_save(importer, change);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen break;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen case DSYNC_MAIL_CHANGE_TYPE_EXPUNGE:
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_mailbox_import_expunge(importer, change);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen break;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen case DSYNC_MAIL_CHANGE_TYPE_FLAG_CHANGE:
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(importer->last_common_uid_found);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_mailbox_import_flag_change(importer, change);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen break;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic void
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainendsync_msg_update_uid(struct dsync_mailbox_importer *importer,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uint32_t old_uid, uint32_t new_uid)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mail_save_context *save_ctx;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (!mail_set_uid(importer->mail, old_uid))
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen save_ctx = mailbox_save_alloc(importer->ext_trans);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_save_copy_flags(save_ctx, importer->mail);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_save_set_uid(save_ctx, new_uid);
3e6903afa5bd125e8bb14f996a558e032674dfbfTimo Sirainen if (mailbox_move(&save_ctx, importer->mail) == 0)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_append(&importer->wanted_uids, &new_uid, 1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic void
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainendsync_mailbox_import_assign_new_uids(struct dsync_mailbox_importer *importer)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct importer_new_mail *newmail, *const *newmailp;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uint32_t common_uid_next, new_uid;
c45baa023828a14f440eb184c24d186ffe8666edTimo Sirainen bool linked_uid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen common_uid_next = I_MAX(importer->local_uid_next,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->remote_uid_next);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_foreach_modifiable(&importer->newmails, newmailp) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen newmail = *newmailp;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (newmail->skip) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* already assigned */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (newmail->uid_in_local) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (mail_set_uid(importer->mail, newmail->uid))
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mail_expunge(importer->mail);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen continue;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* figure out what UID to use for the mail */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (newmail->uid_is_usable) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* keep the UID */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen new_uid = newmail->uid;
c45baa023828a14f440eb184c24d186ffe8666edTimo Sirainen linked_uid = FALSE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen } else if (newmail->link != NULL &&
c45baa023828a14f440eb184c24d186ffe8666edTimo Sirainen newmail->link->uid_is_usable) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen new_uid = newmail->link->uid;
c45baa023828a14f440eb184c24d186ffe8666edTimo Sirainen linked_uid = TRUE;
c45baa023828a14f440eb184c24d186ffe8666edTimo Sirainen } else {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen new_uid = common_uid_next++;
c45baa023828a14f440eb184c24d186ffe8666edTimo Sirainen linked_uid = FALSE;
c45baa023828a14f440eb184c24d186ffe8666edTimo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (newmail->uid_in_local && newmail->uid != new_uid) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* local UID changed, reassign it by copying */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_msg_update_uid(importer, newmail->uid, new_uid);
c45baa023828a14f440eb184c24d186ffe8666edTimo Sirainen } else if (linked_uid && newmail->link->uid_in_local) {
c45baa023828a14f440eb184c24d186ffe8666edTimo Sirainen /* the linked message already exists. we'll just need
c45baa023828a14f440eb184c24d186ffe8666edTimo Sirainen to forget about this message. */
c45baa023828a14f440eb184c24d186ffe8666edTimo Sirainen i_assert(!newmail->uid_in_local);
c45baa023828a14f440eb184c24d186ffe8666edTimo Sirainen newmail->skip = TRUE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen newmail->uid = new_uid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
c45baa023828a14f440eb184c24d186ffe8666edTimo Sirainen if (newmail->link != NULL && !newmail->skip) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* skip the linked mail */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen newmail->link->skip = TRUE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainen importer->last_common_uid = common_uid_next-1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->new_uids_assigned = TRUE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenvoid dsync_mailbox_import_changes_finish(struct dsync_mailbox_importer *importer)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(!importer->new_uids_assigned);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (!importer->last_common_uid_found) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* handle pending expunges and flag updates */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_mailbox_common_uid_found(importer);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* skip common local mails */
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen (void)importer_next_mail(importer, importer->last_common_uid+1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* if there are any local mails left, add them to newmails list */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen while (importer->cur_mail != NULL)
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen (void)dsync_mailbox_try_save(importer, NULL);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_mailbox_import_assign_new_uids(importer);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenconst struct dsync_mail_request *
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainendsync_mailbox_import_next_request(struct dsync_mailbox_importer *importer)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const struct dsync_mail_request *requests;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int count;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen requests = array_get(&importer->mail_requests, &count);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (importer->mail_request_idx == count)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return NULL;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return &requests[importer->mail_request_idx++];
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic const char *const *
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainendsync_mailbox_get_final_keywords(const struct dsync_mail_change *change)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen ARRAY_TYPE(const_string) keywords;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const char *const *changes;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int i, count;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (!array_is_created(&change->keyword_changes))
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return NULL;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen changes = array_get(&change->keyword_changes, &count);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen t_array_init(&keywords, count);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen for (i = 0; i < count; i++) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (changes[i][0] == KEYWORD_CHANGE_ADD ||
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen changes[i][0] == KEYWORD_CHANGE_FINAL) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const char *name = changes[i]+1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_append(&keywords, &name, 1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (array_count(&keywords) == 0)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return NULL;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
31a574fda352ef4f71dbff9c30e15e4744e132c0Timo Sirainen array_append_zero(&keywords);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return array_idx(&keywords, 0);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic void
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainendsync_mailbox_save_set_metadata(struct dsync_mailbox_importer *importer,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mail_save_context *save_ctx,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const struct dsync_mail_change *change)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const char *const *keyword_names;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mail_keywords *keywords;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen keyword_names = dsync_mailbox_get_final_keywords(change);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen keywords = keyword_names == NULL ? NULL :
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_keywords_create_valid(importer->box,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen keyword_names);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_save_set_flags(save_ctx, change->final_flags, keywords);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (keywords != NULL)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_keywords_unref(&keywords);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_save_set_save_date(save_ctx, change->save_timestamp);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (change->modseq > 1) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen (void)mailbox_enable(importer->box, MAILBOX_FEATURE_CONDSTORE);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_save_set_min_modseq(save_ctx, change->modseq);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen /* FIXME: if there already are private flags, they get lost because
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen saving can't handle updating private index. they get added on the
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen next sync though. if this is fixed here, set min_pvt_modseq also. */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic int
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainendsync_msg_try_copy(struct dsync_mailbox_importer *importer,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mail_save_context **save_ctx_p,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct importer_new_mail *all_newmails)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct importer_new_mail *inst;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen for (inst = all_newmails; inst != NULL; inst = inst->next) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (inst->uid_in_local && !inst->copy_failed &&
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mail_set_uid(importer->mail, inst->uid)) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (mailbox_copy(save_ctx_p, importer->mail) < 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen inst->copy_failed = TRUE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return -1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return 1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return 0;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic struct mail_save_context *
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainendsync_mailbox_save_init(struct dsync_mailbox_importer *importer,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const struct dsync_mail *mail,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct importer_new_mail *newmail)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mail_save_context *save_ctx;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen save_ctx = mailbox_save_alloc(importer->ext_trans);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_save_set_uid(save_ctx, newmail->uid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (*mail->guid != '\0')
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_save_set_guid(save_ctx, mail->guid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_mailbox_save_set_metadata(importer, save_ctx, newmail->change);
89f0ab8c7daae308fbcb1c8537ee415d236816c0Timo Sirainen if (mail->pop3_uidl != NULL && *mail->pop3_uidl != '\0')
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_save_set_pop3_uidl(save_ctx, mail->pop3_uidl);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (mail->pop3_order > 0)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_save_set_pop3_order(save_ctx, mail->pop3_order);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_save_set_received_date(save_ctx, mail->received_date, 0);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return save_ctx;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic void dsync_mailbox_save_body(struct dsync_mailbox_importer *importer,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const struct dsync_mail *mail,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct importer_new_mail *newmail,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct importer_new_mail *all_newmails)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mail_save_context *save_ctx;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen ssize_t ret;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen bool save_failed = FALSE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* try to save the mail by copying an existing mail */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen save_ctx = dsync_mailbox_save_init(importer, mail, newmail);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if ((ret = dsync_msg_try_copy(importer, &save_ctx, all_newmails)) < 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (save_ctx == NULL)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen save_ctx = dsync_mailbox_save_init(importer, mail, newmail);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (ret > 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_append(&importer->wanted_uids, &newmail->uid, 1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* fallback to saving from remote stream */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (mail->input == NULL) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* it was just expunged in remote, skip it */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_save_cancel(&save_ctx);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_stream_seek(mail->input, 0);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (mailbox_save_begin(&save_ctx, mail->input) < 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_error("Can't save message to mailbox %s: %s",
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_get_vname(importer->box),
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_get_last_error(importer->box, NULL));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->failed = TRUE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen while ((ret = i_stream_read(mail->input)) > 0 || ret == -2) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (mailbox_save_continue(save_ctx) < 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen save_failed = TRUE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen ret = -1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen break;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(ret == -1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (mail->input->stream_errno != 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen errno = mail->input->stream_errno;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_error("read(msg input) failed: %m");
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_save_cancel(&save_ctx);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->failed = TRUE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen } else if (save_failed) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_save_cancel(&save_ctx);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->failed = TRUE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen } else {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(mail->input->eof);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (mailbox_save_finish(&save_ctx) < 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_error("Can't save message to mailbox %s: %s",
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_get_vname(importer->box),
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_get_last_error(importer->box, NULL));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->failed = TRUE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen } else {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_append(&importer->wanted_uids, &newmail->uid, 1);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenvoid dsync_mailbox_import_mail(struct dsync_mailbox_importer *importer,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const struct dsync_mail *mail)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct importer_new_mail *newmail, *allmails;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
89f0ab8c7daae308fbcb1c8537ee415d236816c0Timo Sirainen i_assert(mail->input == NULL || mail->input->seekable);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(importer->new_uids_assigned);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen newmail = *mail->guid != '\0' ?
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen hash_table_lookup(importer->import_guids, mail->guid) :
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen hash_table_lookup(importer->import_uids, POINTER_CAST(mail->uid));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (newmail == NULL) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (importer->want_mail_requests) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_error("%s: Remote sent unwanted message body for "
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen "GUID=%s UID=%u",
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_get_vname(importer->box),
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mail->guid, mail->uid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (*mail->guid != '\0')
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen hash_table_remove(importer->import_guids, mail->guid);
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen else {
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen hash_table_remove(importer->import_uids,
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen POINTER_CAST(mail->uid));
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* save all instances of the message */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen allmails = newmail;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen for (; newmail != NULL; newmail = newmail->next) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (newmail->skip) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* no need to do anything for this mail */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen continue;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (newmail->uid_in_local) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* we already handled this by copying the mail */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen continue;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen T_BEGIN {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_mailbox_save_body(importer, mail, newmail,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen allmails);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen } T_END;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic int
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenreassign_uids_in_seq_range(struct mailbox *box, uint32_t seq1, uint32_t seq2)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const enum mailbox_transaction_flags trans_flags =
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen MAILBOX_TRANSACTION_FLAG_EXTERNAL |
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen MAILBOX_TRANSACTION_FLAG_ASSIGN_UIDS;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mailbox_transaction_context *trans;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mail_save_context *save_ctx;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mail *mail;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uint32_t seq;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen int ret = 0;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen trans = mailbox_transaction_begin(box, trans_flags);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mail = mail_alloc(trans, 0, NULL);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen for (seq = seq1; seq <= seq2; seq++) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mail_set_seq(mail, seq);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen save_ctx = mailbox_save_alloc(trans);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_save_copy_flags(save_ctx, mail);
3e6903afa5bd125e8bb14f996a558e032674dfbfTimo Sirainen if (mailbox_move(&save_ctx, mail) < 0) {
3e6903afa5bd125e8bb14f996a558e032674dfbfTimo Sirainen i_error("Couldn't move mail within mailbox %s: %s",
3e6903afa5bd125e8bb14f996a558e032674dfbfTimo Sirainen mailbox_get_vname(box),
3e6903afa5bd125e8bb14f996a558e032674dfbfTimo Sirainen mailbox_get_last_error(box, NULL));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen ret = -1;
3e6903afa5bd125e8bb14f996a558e032674dfbfTimo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mail_free(&mail);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (mailbox_transaction_commit(&trans) < 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_error("UID reassign commit failed to mailbox %s: %s",
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_get_vname(box),
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_get_last_error(box, NULL));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen ret = -1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return ret;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
91ec3b77f0bb5365ff9601422f09c729a0e19897Timo Sirainenstatic int
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenreassign_unwanted_uids(struct dsync_mailbox_importer *importer,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const struct mail_transaction_commit_changes *changes,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen bool *changes_during_sync_r)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct seq_range_iter iter;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen const uint32_t *wanted_uids;
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen uint32_t saved_uid, highest_wanted_uid = 0;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uint32_t seq1, seq2, lowest_saved_uid = (uint32_t)-1;
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen uint32_t lowest_unwanted_uid = (uint32_t)-1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen unsigned int i, n, wanted_count;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen int ret = 0;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen /* wanted_uids contains the UIDs we tried to save mails with.
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen if nothing changed during dsync, we should have the expected UIDs
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen (changes->saved_uids) and all is well.
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen if any new messages got inserted during dsync, we'll need to fix up
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen the UIDs and let the next dsync fix up the other side. for example:
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen remote uids = 5,7,9 = wanted_uids
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen remote uidnext = 12
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen locally added new uid=5 ->
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen saved_uids = 10,7,9
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen we'll now need to reassign UIDs 5 and 10. or more generally, we
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen need to reassign UIDs [original local uidnext .. lowest saved_uid-1]
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen and [lowest unwanted uid .. remote uidnext-1] */
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* find the highest wanted UID that doesn't match what we got */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen wanted_uids = array_get(&importer->wanted_uids, &wanted_count);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen seq_range_array_iter_init(&iter, &changes->saved_uids); i = n = 0;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen while (seq_range_array_iter_nth(&iter, n++, &saved_uid)) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_assert(i < wanted_count);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (lowest_saved_uid > saved_uid)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen lowest_saved_uid = saved_uid;
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen if (saved_uid == wanted_uids[i]) {
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen if (highest_wanted_uid < saved_uid)
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen highest_wanted_uid = saved_uid;
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen } else {
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen if (lowest_unwanted_uid > saved_uid)
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen lowest_unwanted_uid = saved_uid;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i++;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen i_assert(lowest_unwanted_uid == (uint32_t)-1 ||
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen lowest_unwanted_uid == highest_wanted_uid+1 ||
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen highest_wanted_uid == 0);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen if (importer->local_uid_next != lowest_saved_uid &&
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen lowest_saved_uid != (uint32_t)-1) {
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen /* [original local uidnext .. lowest saved_uid-1] */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_get_seq_range(importer->box, importer->local_uid_next,
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen lowest_saved_uid-1, &seq1, &seq2);
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen if (seq1 > 0) {
91ec3b77f0bb5365ff9601422f09c729a0e19897Timo Sirainen if (reassign_uids_in_seq_range(importer->box,
91ec3b77f0bb5365ff9601422f09c729a0e19897Timo Sirainen seq1, seq2) < 0)
91ec3b77f0bb5365ff9601422f09c729a0e19897Timo Sirainen ret = -1;
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen *changes_during_sync_r = TRUE;
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen if (lowest_unwanted_uid < importer->remote_uid_next) {
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen /* [highest wanted_uid+1 .. remote uidnext-1] */
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen mailbox_get_seq_range(importer->box, lowest_unwanted_uid,
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen importer->remote_uid_next-1, &seq1, &seq2);
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen if (seq1 > 0) {
91ec3b77f0bb5365ff9601422f09c729a0e19897Timo Sirainen if (reassign_uids_in_seq_range(importer->box,
91ec3b77f0bb5365ff9601422f09c729a0e19897Timo Sirainen seq1, seq2) < 0)
91ec3b77f0bb5365ff9601422f09c729a0e19897Timo Sirainen ret = -1;
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen *changes_during_sync_r = TRUE;
14460e21d9acf5812876832c53f7625b23a0bd69Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return ret;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenstatic int dsync_mailbox_import_commit(struct dsync_mailbox_importer *importer,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen bool *changes_during_sync_r)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mail_transaction_commit_changes changes;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct mailbox_update update;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen int ret = 0;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* commit saves */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (mailbox_transaction_commit_get_changes(&importer->ext_trans,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen &changes) < 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_error("Save commit failed to mailbox %s: %s",
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_get_vname(importer->box),
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_get_last_error(importer->box, NULL));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_transaction_rollback(&importer->trans);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return -1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* commit flag changes and expunges */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (mailbox_transaction_commit(&importer->trans) < 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_error("Commit failed to mailbox %s: %s",
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_get_vname(importer->box),
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_get_last_error(importer->box, NULL));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen pool_unref(&changes.pool);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return -1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* update mailbox metadata. */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen memset(&update, 0, sizeof(update));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen update.min_next_uid = importer->remote_uid_next;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen update.min_first_recent_uid =
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen I_MIN(importer->last_common_uid+1,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->remote_first_recent_uid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen update.min_highest_modseq = importer->remote_highest_modseq;
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen update.min_highest_pvt_modseq = importer->remote_highest_pvt_modseq;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (mailbox_update(importer->box, &update) < 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_error("Mailbox update failed to mailbox %s: %s",
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_get_vname(importer->box),
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_get_last_error(importer->box, NULL));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen ret = -1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* sync mailbox to finish flag changes and expunges. */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (mailbox_sync(importer->box, 0) < 0) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen i_error("Mailbox sync failed to mailbox %s: %s",
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_get_vname(importer->box),
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mailbox_get_last_error(importer->box, NULL));
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen ret = -1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (reassign_unwanted_uids(importer, &changes,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen changes_during_sync_r) < 0)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen ret = -1;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen pool_unref(&changes.pool);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return ret;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
1c95b8403d2d4dcf35e23fc0a1b51922f120a82aTimo Sirainenstatic void
1c95b8403d2d4dcf35e23fc0a1b51922f120a82aTimo Sirainendsync_mailbox_import_check_missing_guid_imports(struct dsync_mailbox_importer *importer)
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen{
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen struct hash_iterate_context *iter;
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen const char *key;
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen struct importer_new_mail *mail;
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen
307ec6c2c319e3335ddb1a7aca2d2884fe17fae0Timo Sirainen iter = hash_table_iterate_init(importer->import_guids);
307ec6c2c319e3335ddb1a7aca2d2884fe17fae0Timo Sirainen while (hash_table_iterate(iter, importer->import_guids, &key, &mail)) {
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen for (; mail != NULL; mail = mail->next) {
307ec6c2c319e3335ddb1a7aca2d2884fe17fae0Timo Sirainen if (mail->uid_in_local || mail->skip)
307ec6c2c319e3335ddb1a7aca2d2884fe17fae0Timo Sirainen continue;
307ec6c2c319e3335ddb1a7aca2d2884fe17fae0Timo Sirainen
1c95b8403d2d4dcf35e23fc0a1b51922f120a82aTimo Sirainen i_error("Mailbox %s: Remote didn't send mail GUID=%s (UID=%u)",
1c95b8403d2d4dcf35e23fc0a1b51922f120a82aTimo Sirainen mailbox_get_vname(importer->box),
1c95b8403d2d4dcf35e23fc0a1b51922f120a82aTimo Sirainen mail->guid, mail->uid);
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen }
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen }
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen hash_table_iterate_deinit(&iter);
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen}
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen
1c95b8403d2d4dcf35e23fc0a1b51922f120a82aTimo Sirainenstatic void
1c95b8403d2d4dcf35e23fc0a1b51922f120a82aTimo Sirainendsync_mailbox_import_check_missing_uid_imports(struct dsync_mailbox_importer *importer)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct hash_iterate_context *iter;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen void *key;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen struct importer_new_mail *mail;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
307ec6c2c319e3335ddb1a7aca2d2884fe17fae0Timo Sirainen iter = hash_table_iterate_init(importer->import_uids);
307ec6c2c319e3335ddb1a7aca2d2884fe17fae0Timo Sirainen while (hash_table_iterate(iter, importer->import_uids, &key, &mail)) {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen for (; mail != NULL; mail = mail->next) {
307ec6c2c319e3335ddb1a7aca2d2884fe17fae0Timo Sirainen if (mail->uid_in_local || mail->skip)
307ec6c2c319e3335ddb1a7aca2d2884fe17fae0Timo Sirainen continue;
307ec6c2c319e3335ddb1a7aca2d2884fe17fae0Timo Sirainen
1c95b8403d2d4dcf35e23fc0a1b51922f120a82aTimo Sirainen i_error("Mailbox %s: Remote didn't send mail UID=%u",
1c95b8403d2d4dcf35e23fc0a1b51922f120a82aTimo Sirainen mailbox_get_vname(importer->box),
1c95b8403d2d4dcf35e23fc0a1b51922f120a82aTimo Sirainen mail->uid);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen hash_table_iterate_deinit(&iter);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainenint dsync_mailbox_import_deinit(struct dsync_mailbox_importer **_importer,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uint32_t *last_common_uid_r,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen uint64_t *last_common_modseq_r,
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen uint64_t *last_common_pvt_modseq_r,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen bool *changes_during_sync_r)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen{
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen struct dsync_mailbox_importer *importer = *_importer;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen int ret;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen *_importer = NULL;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen *changes_during_sync_r = FALSE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (!importer->new_uids_assigned)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen dsync_mailbox_import_assign_new_uids(importer);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
1c95b8403d2d4dcf35e23fc0a1b51922f120a82aTimo Sirainen dsync_mailbox_import_check_missing_guid_imports(importer);
1c95b8403d2d4dcf35e23fc0a1b51922f120a82aTimo Sirainen dsync_mailbox_import_check_missing_uid_imports(importer);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen if (importer->search_ctx != NULL) {
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen if (mailbox_search_deinit(&importer->search_ctx) < 0)
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen importer->failed = TRUE;
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mail_free(&importer->mail);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen mail_free(&importer->ext_mail);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (dsync_mailbox_import_commit(importer, changes_during_sync_r) < 0)
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen importer->failed = TRUE;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen hash_table_destroy(&importer->import_guids);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen hash_table_destroy(&importer->import_uids);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_free(&importer->maybe_expunge_uids);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_free(&importer->maybe_saves);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_free(&importer->wanted_uids);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_free(&importer->newmails);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen if (array_is_created(&importer->mail_requests))
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen array_free(&importer->mail_requests);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen *last_common_uid_r = importer->last_common_uid;
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen if (!*changes_during_sync_r) {
c307328f59c963eba21091ecd36c9435d42b47d8Timo Sirainen *last_common_modseq_r = importer->remote_highest_modseq;
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen *last_common_pvt_modseq_r = importer->remote_highest_pvt_modseq;
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen } else {
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen /* local changes occurred during dsync. we exported changes up
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen to local_initial_highestmodseq, so all of the changes have
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen happened after it. we want the next run to see those changes,
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen so return it as the last common modseq */
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen *last_common_modseq_r = importer->local_initial_highestmodseq;
6abf66a3731d52889517bd644595c540e3a9b3ecTimo Sirainen *last_common_pvt_modseq_r = importer->local_initial_highestpvtmodseq;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen }
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen ret = importer->failed ? -1 : 0;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen pool_unref(&importer->pool);
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen return ret;
7bd5b1c64cc987715bdaf8cc4907c3c37d5d7b29Timo Sirainen}