dsync-mailbox-import.c revision b0ead8fffe8dfdee92fca875b91fadf3f3f2262b
8c294c1cd4d721818a59684cf7f2b36123f79163Stephen Gallagher/* Copyright (c) 2013-2017 Dovecot authors, see the included COPYING file */
9d453f1e8b28983b363b44c49b7cd701a994fd97Nikolai Kondrashov /* linked list of mails for this GUID */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* if non-NULL, this mail exists in both local and remote. this link
df4cc3a83c5d6700b6a09ff96cb4a6b1949b1aa9Stephen Gallagher points to the other side. */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* the final UID for the message */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* the original local UID, or 0 if exists only remotely */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* the original remote UID, or 0 if exists only remotely */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* UID for the mail in the virtual \All mailbox */
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke/* for quickly testing that two-way sync doesn't actually do any unexpected
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke modifications. */
1d1a0a019d8d4d9ab0f51ada03604cd2cada287eSumit Bose#define IMPORTER_DEBUG_CHANGE(importer) /*i_assert(!importer->master_brain)*/
1d1a0a019d8d4d9ab0f51ada03604cd2cada287eSumit BoseHASH_TABLE_DEFINE_TYPE(guid_new_mail, const char *, struct importer_new_mail *);
f3c85d900c4663854cc7bbae7d9f77867ed1f69bSumit BoseHASH_TABLE_DEFINE_TYPE(uid_new_mail, void *, struct importer_new_mail *);
41291f19dbc5bf14f20729959b852fa605fcc02dJakub Hrozek uint64_t last_common_modseq, last_common_pvt_modseq;
a5bb518446d5ce565d7ba819590a009cabb0b0b4Jakub Hrozek uint64_t remote_highest_modseq, remote_highest_pvt_modseq;
eb2e21b764d03544d8161e9956d7f70b07b75f77Simo Sorce struct mailbox_transaction_context *trans, *ext_trans;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct mailbox_transaction_context *virtual_trans;
59744cff6edb106ae799b2321cb8731edadf409aStephen Gallagher /* UID => struct dsync_mail_change */
6dcbfe52d5e64205c0d922f3e89add066b42c496Jakub Hrozek HASH_TABLE_TYPE(dsync_uid_mail_change) local_changes;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher HASH_TABLE_TYPE(dsync_attr_change) local_attr_changes;
b32159300fea63222d8dd9200ed634087704ea74Stephen Gallagher ARRAY(struct dsync_mail_change *) maybe_saves;
87d3b47abba6a40fcf809c85a2b138bc1013d9c5Jakub Hrozek /* GUID => struct importer_new_mail */
bc13c352ba9c2877f1e9bc62e55ad60fc000a55dJakub Hrozek /* UID => struct importer_new_mail */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ARRAY(struct dsync_mail_request) mail_requests;
054b5d4bb98973698f74d66b14ccd14394b53f10Lukas Slebodnik uint32_t prev_uid, next_local_seq, local_uid_next;
62bda5f75bda6b77aea30d708c74efaf725d9367Lukas Slebodnik uint64_t local_initial_highestmodseq, local_initial_highestpvtmodseq;
a3d176d116ceccd6a7547c128fab5df5cdd2c2b6Michal Zidek unsigned int first_unsaved_idx, saves_since_commit;
f1828234a850dd28465425248a83a993f262918fPavel Březinastatic const char *dsync_mail_change_type_names[] = {
e157b9f6cb370e1b94bcac2044d26ad66d640fbaPavel Březinastatic bool dsync_mailbox_save_newmails(struct dsync_mailbox_importer *importer,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic int dsync_mailbox_import_commit(struct dsync_mailbox_importer *importer,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherimp_debug(struct dsync_mailbox_importer *importer, const char *fmt, ...)
cb4d5b588e704114b7090678752d33512baa718eJakub Hrozekdsync_import_unexpected_state(struct dsync_mailbox_importer *importer,
f3a25949de81f80c136bb073e4a8f504b080c20cJakub Hrozek i_error("Mailbox %s: %s", mailbox_get_vname(importer->box),
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose i_warning("Mailbox %s doesn't match previous state: %s "
45726939a48e605b0166521f94300ae04981a3a7Sumit Bose "(dsync must be run again without the state)",
5484044ea7bb632b915f706685fce509f6eacc48Jakub Hrozekdsync_mailbox_import_search_init(struct dsync_mailbox_importer *importer)
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose sarg = mail_search_build_add(search_args, SEARCH_UIDSET);
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose p_array_init(&sarg->value.seqset, search_args->pool, 128);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher importer->last_common_uid+1, (uint32_t)-1);
4b39208286ca0351ee76d4e64e077e7ad5ca8568Jakub Hrozek mailbox_search_init(importer->trans, search_args, NULL,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (mailbox_search_next(importer->search_ctx, &importer->cur_mail))
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher importer->next_local_seq = importer->cur_mail->seq;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* this flag causes cur_guid to be looked up later */
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagherdsync_mailbox_import_transaction_begin(struct dsync_mailbox_importer *importer)
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher const enum mailbox_transaction_flags ext_trans_flags =
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek importer->trans = mailbox_transaction_begin(importer->box,
71e7918be3ca5d38794a16a17f6b4f19a24d51fcPavel Březina importer->ext_trans = mailbox_transaction_begin(importer->box,
71e7918be3ca5d38794a16a17f6b4f19a24d51fcPavel Březina importer->mail = mail_alloc(importer->trans, 0, NULL);
71e7918be3ca5d38794a16a17f6b4f19a24d51fcPavel Březina importer->ext_mail = mail_alloc(importer->ext_trans, 0, NULL);
939246537b0b9a4af6862c513d3919501ad57d92Sumit Bose pool = pool_alloconly_create(MEMPOOL_GROWING"dsync mailbox importer",
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek importer = p_new(pool, struct dsync_mailbox_importer, 1);
e592d5f157be869151983bd1b46d6f4f7a29daafJakub Hrozek importer->last_common_modseq = last_common_modseq;
50b8a36b0932a510e825ed1ad8103f81ead2b7d8Pavel Reichl importer->last_common_pvt_modseq = last_common_pvt_modseq;
e592d5f157be869151983bd1b46d6f4f7a29daafJakub Hrozek last_common_uid != 0 || last_common_modseq != 0;
6ea6662287147308b81b9c9f2f1f3c992d01bc50Jakub Hrozek importer->remote_first_recent_uid = remote_first_recent_uid;
526a15438525417cd701f837d7085b7f8c8a6325Jakub Hrozek importer->remote_highest_modseq = remote_highest_modseq;
27a7dedb0ee4d4b51ca4c196aa894ad30cb3e821Petr Cech importer->remote_highest_pvt_modseq = remote_highest_pvt_modseq;
1d93029624d708119bbf803e6647a2cbb271f001Sumit Bose importer->sync_since_timestamp = sync_since_timestamp;
a5623363d6042290fe652a1ca5ce5a85a821236fPavel Březina importer->sync_until_timestamp = sync_until_timestamp;
a0ab15ceb80290db80c2052520830a95390de385Sumit Bose importer->stateful_import = importer->last_common_uid_found;
b590f44c06158485357d69cc5b24d5af05f1bb95Petr Cech importer->sync_flag = imap_parse_system_flag(sync_flag);
bf01e8179cbb2be476805340636098deda7e1366Sumit Bose importer->sync_keyword = p_strdup(pool, sync_flag);
99c5f2f6ba0af6ce52be0d82ec2794bacc215742Jakub Hrozek importer->commit_msgs_interval = commit_msgs_interval;
b9d83e10cec267ae11fee64a30f42a12bbf7abe4Pavel Březina importer->transaction_flags = MAILBOX_TRANSACTION_FLAG_SYNC;
49c467733ca65c9b77b9c33f38cdc223a99562e1Pavel Reichl if ((flags & DSYNC_MAILBOX_IMPORT_FLAG_NO_NOTIFY) != 0)
62370340092503baeaf6587d7ffe4fe25bd9582dPavel Reichl importer->transaction_flags |= MAILBOX_TRANSACTION_FLAG_NO_NOTIFY;
583c1b9a052f4eb5ba046c5f2b7d2ed2a81b6d66Jakub Hrozek hash_table_create(&importer->import_guids, pool, 0, str_hash, strcmp);
e592d5f157be869151983bd1b46d6f4f7a29daafJakub Hrozek hash_table_create_direct(&importer->import_uids, pool, 0);
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek i_array_init(&importer->maybe_expunge_uids, 16);
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek dsync_mailbox_import_transaction_begin(importer);
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek if ((flags & DSYNC_MAILBOX_IMPORT_FLAG_WANT_MAIL_REQUESTS) != 0) {
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik i_array_init(&importer->mail_requests, 128);
91d312000e6ded4a93327c137b10c5beda55f65cSumit Bose (flags & DSYNC_MAILBOX_IMPORT_FLAG_MASTER_BRAIN) != 0;
91d312000e6ded4a93327c137b10c5beda55f65cSumit Bose (flags & DSYNC_MAILBOX_IMPORT_FLAG_REVERT_LOCAL_CHANGES) != 0;
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik importer->debug = (flags & DSYNC_MAILBOX_IMPORT_FLAG_DEBUG) != 0;
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek (flags & DSYNC_MAILBOX_IMPORT_FLAG_MAILS_HAVE_GUIDS) != 0;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher (flags & DSYNC_MAILBOX_IMPORT_FLAG_MAILS_USE_GUID128) != 0;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher importer->hdr_hash_version = hdr_hash_version;
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek (flags & DSYNC_MAILBOX_IMPORT_FLAG_EMPTY_HDR_WORKAROUND) != 0;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher mailbox_get_open_status(importer->box, STATUS_UIDNEXT |
9f521c61c17cecd9625ebc1b33c666fa3488622cJakub Hrozek STATUS_HIGHESTMODSEQ | STATUS_HIGHESTPVTMODSEQ,
9f521c61c17cecd9625ebc1b33c666fa3488622cJakub Hrozek importer->local_initial_highestmodseq = status.highest_modseq;
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher importer->local_initial_highestpvtmodseq = status.highest_pvt_modseq;
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher dsync_mailbox_import_search_init(importer);
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik else if (importer->local_uid_next <= last_common_uid) {
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik dsync_import_unexpected_state(importer, t_strdup_printf(
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik "local UIDNEXT %u <= last common UID %u",
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik importer->local_uid_next, last_common_uid));
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik } else if (importer->local_initial_highestmodseq < last_common_modseq) {
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik dsync_import_unexpected_state(importer, t_strdup_printf(
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik "local HIGHESTMODSEQ %llu < last common HIGHESTMODSEQ %llu",
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik (unsigned long long)importer->local_initial_highestmodseq,
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher (unsigned long long)last_common_modseq));
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher } else if (importer->local_initial_highestpvtmodseq < last_common_pvt_modseq) {
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik dsync_import_unexpected_state(importer, t_strdup_printf(
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher "local HIGHESTMODSEQ %llu < last common HIGHESTMODSEQ %llu",
bf5a808fa92007c325c3996e79694badfab201d4Stephen Gallagher (unsigned long long)importer->local_initial_highestpvtmodseq,
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek (unsigned long long)last_common_pvt_modseq));
cbff3fcdce5b0377a62fbe74f32e476efbf7ca9cNikolai Kondrashov importer->local_changes = dsync_transaction_log_scan_get_hash(log_scan);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher importer->local_attr_changes = dsync_transaction_log_scan_get_attr_hash(log_scan);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherdsync_mailbox_import_lookup_attr(struct dsync_mailbox_importer *importer,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher enum mail_attribute_type type, const char *key,
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik struct dsync_mailbox_attribute lookup_attr, *attr;
a2e417f38c57ed87c956ddcecf4dafca93842b65Lukas Slebodnik const struct dsync_mailbox_attribute *attr_change;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (mailbox_attribute_get_stream(importer->box, type, key, &value) < 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_error("Mailbox %s: Failed to get attribute %s: %s",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher mailbox_get_last_internal_error(importer->box,
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose attr_change = hash_table_lookup(importer->local_attr_changes,
90fd1bbd6035cdab46faa3a695a2fb2be6508b17Sumit Bose value.value == NULL && value.value_stream == NULL) {
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke /* we have no knowledge of this attribute */
af4ffe1001adcc0a96897e426d26444f07af9aa1Benjamin Franzke attr = t_new(struct dsync_mailbox_attribute, 1);
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnikdsync_istreams_cmp(struct istream *input1, struct istream *input2, int *cmp_r)
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik (void)i_stream_read_more(input1, &data1, &size1);
4a5a18f489f4d19aa0571528a7f0c7a8d35ac83fLukas Slebodnik (void)i_stream_read_more(input2, &data2, &size2);
18372712592b30638772afb5b7e15bfca92c2058Lukas Slebodnik i_error("read(%s) failed: %s", i_stream_get_name(input1),
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov i_error("read(%s) failed: %s", i_stream_get_name(input2),
7bb9ba8688ec1ca930d693eea05e936bc38f6d1bSumit Bosedsync_attributes_cmp_values(const struct dsync_mailbox_attribute *attr1,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(attr1->value_stream != NULL || attr1->value != NULL);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(attr2->value_stream != NULL || attr2->value != NULL);
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov if (attr1->value != NULL && attr2->value != NULL) {
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov *cmp_r = strcmp(attr1->value, attr2->value);
3ce85a5f5264e7118beb6524e120fd8b53a13da4Nikolai Kondrashov /* at least one of them is a stream. make both of them streams. */
6398f22526303343193a18e514602f1af6fb29cbNikolai Kondrashov input1 = attr1->value_stream != NULL ? attr1->value_stream :
6398f22526303343193a18e514602f1af6fb29cbNikolai Kondrashov i_stream_create_from_data(attr1->value, strlen(attr1->value));
a8d887323f83984679a7d9b827a70146656bb7b2Sumit Bose input2 = attr2->value_stream != NULL ? attr2->value_stream :
a8d887323f83984679a7d9b827a70146656bb7b2Sumit Bose i_stream_create_from_data(attr2->value, strlen(attr2->value));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = dsync_istreams_cmp(input1, input2, cmp_r);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherdsync_attributes_cmp(const struct dsync_mailbox_attribute *attr,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const struct dsync_mailbox_attribute *local_attr,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* remote has a value and local doesn't -> use it */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* remote doesn't have a value, bt local does -> skip */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher return dsync_attributes_cmp_values(attr, local_attr, cmp_r);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherdsync_mailbox_import_attribute_real(struct dsync_mailbox_importer *importer,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const struct dsync_mailbox_attribute *local_attr,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(DSYNC_ATTR_HAS_VALUE(attr) || attr->deleted);
2cbdd12983eb85eddb90f64cfafb24eae5b448f4Jakub Hrozek (local_attr == NULL || !DSYNC_ATTR_HAS_VALUE(local_attr))) {
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta /* attribute doesn't exist on either side -> ignore */
b3b6189850d50c656d62efbd498789124c033b00Lukas Slebodnik /* we haven't seen this locally -> use whatever remote has */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher } else if (local_attr->modseq <= importer->last_common_modseq &&
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* we're doing incremental syncing, and we can see that the
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher attribute was changed remotely, but not locally -> use it */
c0f9698cd951b7223f251ff2511c4b22a6e4ba60Jan Zeleny } else if (local_attr->modseq > importer->last_common_modseq &&
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina /* we're doing incremental syncing, and we can see that the
83a79d93035c2d75a1941f3b54426119174044a0Pavel Březina attribute was changed locally, but not remotely -> ignore */
769347ad4d35d43488eb98f980143495b0db415dStef Walter } else if (attr->last_change > local_attr->last_change) {
376eaf187c13c2a1eaea0ffbdd970b6b563ab74cPetr Cech /* remote has a newer timestamp -> use it */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher } else if (attr->last_change < local_attr->last_change) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* remote has an older timestamp -> ignore */
284937e6b5b0c9d7a1d3382d0d2820d1168842fbPavel Březina /* the timestamps are the same. now we're down to guessing
aea1d5c0ca9bb1470759b024c8b97b6c1f577193Pavel Březina the right answer, unless the values are actually equal,
d2d8f342cd5e90bb9fd947c448492225f959aa86Pavel Březina so check that first. next try to use modseqs, but if even
284937e6b5b0c9d7a1d3382d0d2820d1168842fbPavel Březina they are the same, fallback to just picking one based on the
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (dsync_attributes_cmp(attr, local_attr, &cmp) < 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* identical scripts */
77d165f0629966db65753a3aee84a8b4971673afPavel Březina /* remote has a higher modseq -> use it */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher } else if (attr->modseq < local_attr->modseq) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* remote has an older modseq -> ignore */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher } else if (cmp < 0) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher *result_r = "Value changed, but unknown which is newer - picking local";
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher *result_r = "Value changed, but unknown which is newer - picking remote";
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (mailbox_attribute_set(importer->trans, attr->type,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_error("Mailbox %s: Failed to set attribute %s: %s",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher mailbox_get_vname(importer->box), attr->key,
eaa723b4d06b4c1e588df67bef44a84bbfaebf1aLukas Slebodnik mailbox_get_last_internal_error(importer->box, NULL));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* the attributes aren't vital, don't fail everything just
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher because of them. */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherint dsync_mailbox_import_attribute(struct dsync_mailbox_importer *importer,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const struct dsync_mailbox_attribute *attr)
2e6087c6cc903d5164b9a1d5e3d791fd046001d9Jakub Hrozek if (dsync_mailbox_import_lookup_attr(importer, attr->type,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher ret = dsync_mailbox_import_attribute_real(importer, attr,
3b08dec5ee634f83ee18e1753d5ffe0ac5e3c458Jakub Hrozek if (local_attr != NULL && local_attr->value_stream != NULL)
558ec7d717735bb16c210c675c2cc5bee1da4576Lukas Slebodnik imp_debug(importer, "Import attribute %s: %s", attr->key,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherstatic void dsync_mail_error(struct dsync_mailbox_importer *importer,
29be7d76c949b82350c7603cfd362a1fcb47eb1bJan Zeleny const char *errstr;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher errstr = mailbox_get_last_internal_error(importer->box, &error);
748ba184db97b7534254f97018fa04e8aa458faeJan Cholasta i_error("Mailbox %s: Can't lookup %s for UID=%u: %s",
7de6e3534fd61c7619ed34a6b1afe7230b5e6504Ondrej Kos mailbox_get_vname(mail->box), field, mail->uid, errstr);
5a70b84cb66fb8c7a3fce0e3f2e4b61e0b2ea9d4Simo Sorcedsync_mail_change_guid_equals(struct dsync_mailbox_importer *importer,
2fa8d6655ac37f9bdeb34420000052d921f4a543Michal Zidek if (change->type == DSYNC_MAIL_CHANGE_TYPE_EXPUNGE) {
a473fb88e6015cf0ccbd2e9005c7e6acca18f452Pavel Březina if (guid_128_from_string(change->guid, change_guid_128) < 0)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher mail_generate_guid_128_hash(change->guid, change_guid_128);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher mail_generate_guid_128_hash(guid, guid_128);
d844aab866ae237844360cea70e2dccdc90c783dStephen Gallagher if (memcmp(change_guid_128, guid_128, GUID_128_SIZE) != 0) {
ef39c0adcb61b16f9edc7beb4cdc8f3b0d5a8f15Stephen Gallagher *cmp_guid_r = t_strdup_printf("%s(guid128, orig=%s)",
ef39c0adcb61b16f9edc7beb4cdc8f3b0d5a8f15Stephen Gallagher binary_to_hex(change_guid_128, sizeof(change_guid_128)),
7ac503a73a26abe49f9f7d175c74df705380898dPavel Březinaimporter_try_next_mail(struct dsync_mailbox_importer *importer,
d3c82d0170d6d7407549afdadd08aa7e11aeb9a2Pavel Březina /* end of search */
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce while (importer->cur_mail->seq < importer->next_local_seq ||
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter /* this message exists locally, but remote didn't send
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher expunge-change for it. if the message's
df4e1db5d41c903ae57fd880acc76a0ad84aa7b2Pavel Březina uid <= last-common-uid, it should be deleted */
364b3572bab5a9649e8f2d4da835d05d3c8ca7a9Pavel Březina seq_range_array_add(&importer->maybe_expunge_uids,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (!mailbox_search_next(importer->search_ctx,
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina importer->cur_uid_has_change = importer->cur_mail->uid == wanted_uid;
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina if (mail_get_special(importer->cur_mail, MAIL_FETCH_GUID,
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina dsync_mail_error(importer, importer->cur_mail, "GUID");
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina if (dsync_mail_get_hdr_hash(importer->cur_mail,
3b99f7a97553a0a357d50abe507d4f0060c4eceaPavel Březina dsync_mail_error(importer, importer->cur_mail,
3b99f7a97553a0a357d50abe507d4f0060c4eceaPavel Březina "header hash");
f9961e5f82e0ef474d6492371bfdf9e74e208a99Pavel Březina pmail = (struct mail_private *)importer->cur_mail;
87c07559af5cfcd2752295ef7c425bd3205f426fStephen Gallagher importer->cur_hdr_hash = p_strdup(pmail->pool, hdr_hash);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* make sure next_local_seq gets updated in case we came here
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher because of min_uid */
3441d0c2d11aea0c39b009751a1898333c009674Stephen Gallagher importer->next_local_seq = importer->cur_mail->seq;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherimporter_next_mail(struct dsync_mailbox_importer *importer, uint32_t wanted_uid)
cc84fd46f356c4a36a721ab135a33ec77c93e34dJakub Hrozek ret = importer_try_next_mail(importer, wanted_uid);
ae8d047122c7ba8123f72b2eac68944868ac37d4Stephen Gallagher importer->next_local_seq = importer->cur_mail->seq + 1;
dea636af4d1902a081ee891f1b19ee2f8729d759Pavel Březinastatic void newmail_link(struct dsync_mailbox_importer *importer,
dea636af4d1902a081ee891f1b19ee2f8729d759Pavel Březina struct importer_new_mail *newmail, uint32_t remote_uid)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct importer_new_mail *first_mail, **last, *mail, *link = NULL;
347f7c4d1e8e83fc7ffcaf9524a67e8b3ad5d7c5Jan Cholasta first_mail = hash_table_lookup(importer->import_guids,
50fe3d79ab12b795a687b676761bef265701626aStephen Gallagher /* first mail for this GUID */
7ac503a73a26abe49f9f7d175c74df705380898dPavel Březina /* mail exists only locally. we don't want to request
bf6c3f07d653d474da9e43b2b7cced57fc4ea069Sumit Bose it, and we'll assume it has no duplicate
b6dfbf81c61d4431aaa81687ec53e892f8b71edbSumit Bose instances. */
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose first_mail = hash_table_lookup(importer->import_uids,
b9c8ce2bdd4045782c243605a1b999098bedcffcNoam Meltzer /* first mail for this UID */
aea1d5c0ca9bb1470759b024c8b97b6c1f577193Pavel Březina /* 1) add the newmail to the end of the linked list
23fb01bf67a6058fb508da6d81515e8b18634bebPavel Březina 2) find our link
53f1b03f4e61ebe21df0c2fd05e09e0504fd8881Jakub Hrozek FIXME: this loop is slow if the same GUID has a ton of instances.
462db32918a05097652f8232cd6c8d78a826e63cLukas Slebodnik Could it be improved in some way? */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher for (mail = first_mail; mail != NULL; mail = mail->next) {
eaa723b4d06b4c1e588df67bef44a84bbfaebf1aLukas Slebodnikdsync_mailbox_revert_existing_uid(struct dsync_mailbox_importer *importer,
86b61156743b7ebdc049450a6f88452890fd9a61Jakub Hrozek /* UID either already exists or UIDNEXT is too high. we can't set the
77c0d1f6074059dafd2293f9c42ea0f9d60f8aadJakub Hrozek wanted UID, so we'll need to delete the whole mailbox and resync */
77c0d1f6074059dafd2293f9c42ea0f9d60f8aadJakub Hrozek i_warning("Deleting mailbox '%s': UID=%u already exists locally for a different mail: %s",
77c0d1f6074059dafd2293f9c42ea0f9d60f8aadJakub Hrozek mailbox_get_vname(importer->box), uid, reason);
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagherstatic bool dsync_mailbox_try_save_cur(struct dsync_mailbox_importer *importer,
87c07559af5cfcd2752295ef7c425bd3205f426fStephen Gallagher importer->cur_guid : importer->cur_hdr_hash;
87c07559af5cfcd2752295ef7c425bd3205f426fStephen Gallagher i_assert(save_change->type != DSYNC_MAIL_CHANGE_TYPE_EXPUNGE);
69b46c32357ccf1aab9c0bd6d1afa33a8724ad77Lukas Slebodnik if (importer->empty_hdr_workaround && !importer->mails_have_guids &&
69b46c32357ccf1aab9c0bd6d1afa33a8724ad77Lukas Slebodnik importer->cur_mail != NULL && save_change != NULL &&
69b46c32357ccf1aab9c0bd6d1afa33a8724ad77Lukas Slebodnik /* one of the headers is empty. assume it's broken and that
25d4435998d0446f7699e7ab0874c7a6f610ab58Lukas Slebodnik the header matches what we have currently. */
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce /* add a record for local mail */
25d4435998d0446f7699e7ab0874c7a6f610ab58Lukas Slebodnik importer->cur_mail->uid >= importer->remote_uid_next) {
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose dsync_mailbox_revert_existing_uid(importer, importer->cur_mail->uid,
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose t_strdup_printf("higher than remote's UIDs (remote UIDNEXT=%u)", importer->remote_uid_next));
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose newmail = p_new(importer->pool, struct importer_new_mail, 1);
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose newmail->guid = p_strdup(importer->pool, importer->cur_guid);
25d4435998d0446f7699e7ab0874c7a6f610ab58Lukas Slebodnik newmail->final_uid = importer->cur_mail->uid;
25d4435998d0446f7699e7ab0874c7a6f610ab58Lukas Slebodnik newmail->local_uid = importer->cur_mail->uid;
625bb2ddf15e8f305a53afa44e87f2146fa930afSimo Sorce } else if (diff > 0) {
25d4435998d0446f7699e7ab0874c7a6f610ab58Lukas Slebodnik newmail = p_new(importer->pool, struct importer_new_mail, 1);
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose if (!newmail->uid_is_usable && importer->revert_local_changes) {
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose dsync_mailbox_revert_existing_uid(importer, newmail->final_uid,
0d5bb38364a6976e9c85d6349aa13a04d181a090Sumit Bose t_strdup_printf("UID >= local UIDNEXT=%u", importer->local_uid_next));
25d4435998d0446f7699e7ab0874c7a6f610ab58Lukas Slebodnik /* identical */
25d4435998d0446f7699e7ab0874c7a6f610ab58Lukas Slebodnik newmail = p_new(importer->pool, struct importer_new_mail, 1);
25d4435998d0446f7699e7ab0874c7a6f610ab58Lukas Slebodnik newmail->final_uid = importer->cur_mail->uid;
25d4435998d0446f7699e7ab0874c7a6f610ab58Lukas Slebodnik newmail->local_uid = importer->cur_mail->uid;
bf01e8179cbb2be476805340636098deda7e1366Sumit Bose /* NOTE: assumes save_change is allocated from importer pool */
bf01e8179cbb2be476805340636098deda7e1366Sumit Bosedsync_mailbox_try_save(struct dsync_mailbox_importer *importer,
bf01e8179cbb2be476805340636098deda7e1366Sumit Bose if (!importer_next_mail(importer, 0) && save_change == NULL)
96453f402831275a39d5fb89c33c9776e148d03fStephen Gallagher return dsync_mailbox_try_save_cur(importer, save_change);
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagherstatic void dsync_mailbox_save(struct dsync_mailbox_importer *importer,
4c11f752e1f10cf5740d53a3206bb795e9e34fe8Jan Zeleny while (!dsync_mailbox_try_save(importer, save_change)) ;
1f1e6cbc59868f06dee3ab4b3df660fcb77ce1c8Jakub Hrozekdsync_import_set_mail(struct dsync_mailbox_importer *importer,
64074e584a56611d7563667e0fcdadd215b0c922Yassir Elley if (!mail_set_uid(importer->mail, change->uid))
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher /* GUID is unknown */
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher /* backend doesn't support GUIDs. if hdr_hash is set, we could
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter verify it, but since this message really is supposed to
d87e960c17d7598781cf032d06ba03a3ecadbfa2Pavel Březina match, it's probably too much trouble. */
d9577dbd92555b0755881e37724019ef9c578404Stef Walter /* verify that GUID matches, just in case */
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher if (mail_get_special(importer->mail, MAIL_FETCH_GUID, &guid) < 0) {
ae7247551b78a05a5397d3c790afad7ef51b0d9dPavel Březina dsync_mail_error(importer, importer->mail, "GUID");
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher if (!dsync_mail_change_guid_equals(importer, change, guid, &cmp_guid)) {
b9d8c6172e48a2633ebe196b2e88bebdf9523c20Stef Walter dsync_import_unexpected_state(importer, t_strdup_printf(
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher "Unexpected GUID mismatch for UID=%u: %s != %s",
29be7d76c949b82350c7603cfd362a1fcb47eb1bJan Zelenystatic bool dsync_check_cur_guid(struct dsync_mailbox_importer *importer,
918b2a5a91f1c551d48f4bffed2a28c36fdb4be1Simo Sorce if (change->guid == NULL || change->guid[0] == '\0' ||
0a55f903a1da319338fdcf147efa01ed22f9710dMichal Zidek if (!dsync_mail_change_guid_equals(importer, change,
22d381367c27910fe82f476a76b9f4ede555e35aLukas Slebodnik dsync_import_unexpected_state(importer, t_strdup_printf(
12805da52a93c268290cec7b8fbbdbd4ea8abc3eLukas Slebodnik "Unexpected GUID mismatch (2) for UID=%u: %s != %s",
022c6b90bb37851c0e8704c0e5388ebc113c6470Lukas Slebodnikmerge_flags(uint32_t local_final, uint32_t local_add, uint32_t local_remove,
12805da52a93c268290cec7b8fbbdbd4ea8abc3eLukas Slebodnik uint32_t remote_final, uint32_t remote_add, uint32_t remote_remove,
12805da52a93c268290cec7b8fbbdbd4ea8abc3eLukas Slebodnik uint32_t pvt_mask, bool prefer_remote, bool prefer_pvt_remote,
ac40d2f2b2b2fc35c95389f5e28febd580bd2b7aJakub Hrozek uint32_t *change_add_r, uint32_t *change_remove_r,
ac40d2f2b2b2fc35c95389f5e28febd580bd2b7aJakub Hrozek bool *remote_changed, bool *remote_pvt_changed)
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher uint32_t combined_add, combined_remove, conflict_flags;
12805da52a93c268290cec7b8fbbdbd4ea8abc3eLukas Slebodnik uint32_t local_wanted, remote_wanted, conflict_pvt_flags;
5a05b6127064c74349f1edae32e5e13032c386feLukas Slebodnik /* resolve conflicts */
96453f402831275a39d5fb89c33c9776e148d03fStephen Gallagher conflict_pvt_flags = conflict_flags & pvt_mask;
42ec8af02ecf1937e4db9b1ecc6216022634f0f9Michal Zidek i_assert((combined_add & combined_remove) == 0);
42ec8af02ecf1937e4db9b1ecc6216022634f0f9Michal Zidek /* don't change flags that are currently identical in both sides */
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnik /* see if there are conflicting final flags */
fd98a28d6e94080e52bbedc789b06606a6019b10Lukas Slebodnik local_wanted = (local_final|combined_add) & ~combined_remove;
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnik remote_wanted = (remote_final|combined_add) & ~combined_remove;
3fc158e59eebbc2f538fe0076a03928d0d4eab9fPavel Březina else if (prefer_remote && !prefer_pvt_remote) {
3fc158e59eebbc2f538fe0076a03928d0d4eab9fPavel Březina } else if (!prefer_remote && prefer_pvt_remote) {
3fc158e59eebbc2f538fe0076a03928d0d4eab9fPavel Březina *change_remove_r = local_final & ~local_wanted;
3fc158e59eebbc2f538fe0076a03928d0d4eab9fPavel Březina if ((local_wanted & ~pvt_mask) != (remote_final & ~pvt_mask))
3fc158e59eebbc2f538fe0076a03928d0d4eab9fPavel Březina if ((local_wanted & pvt_mask) != (remote_final & pvt_mask))
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bosekeyword_find(ARRAY_TYPE(const_string) *keywords, const char *name,
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose unsigned int *idx_r)
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose const char *const *names;
e0c86d21388bffe2e3919e780780c40d96186abbJakub Hrozek unsigned int i, count;
e0c86d21388bffe2e3919e780780c40d96186abbJakub Hrozek for (i = 0; i < count; i++) {
de5fa34860886ad68fba5e739987e16c342e8f14Lukas Slebodnikstatic void keywords_append(ARRAY_TYPE(const_string) *dest,
654757bcead49427baaeb1b368c0e3433b67c51aJan Engelhardt const char *const *namep;
e0c86d21388bffe2e3919e780780c40d96186abbJakub Hrozek unsigned int i;
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher for (i = 0; i < 32; i++) {
f28b09f887870c10c8c611beee3c17eaa9ef74f3Lukas Slebodnikmerge_keywords(struct mail *mail, const ARRAY_TYPE(const_string) *local_changes,
8babbeee01e67893af4828ddfc922ecac0be4197Pavel Reichl const ARRAY_TYPE(const_string) *remote_changes,
f28b09f887870c10c8c611beee3c17eaa9ef74f3Lukas Slebodnik bool *remote_changed, bool *remote_pvt_changed)
4f6931e854c698dcb1c09f99eb330ce2fb97e7c6Lukas Slebodnik /* local_changes and remote_changes are assumed to have no
f28b09f887870c10c8c611beee3c17eaa9ef74f3Lukas Slebodnik duplicates names */
2a9af1f71887f02935e2fb6ad5023afba5b6d43eSumit Bose uint32_t *local_add, *local_remove, *local_final;
2a9af1f71887f02935e2fb6ad5023afba5b6d43eSumit Bose uint32_t *remote_add, *remote_remove, *remote_final;
2a9af1f71887f02935e2fb6ad5023afba5b6d43eSumit Bose ARRAY_TYPE(const_string) all_keywords, add_keywords, remove_keywords;
654757bcead49427baaeb1b368c0e3433b67c51aJan Engelhardt const char *const *changes, *name, *const *local_keywords;
f28b09f887870c10c8c611beee3c17eaa9ef74f3Lukas Slebodnik /* we'll assign a common index for each keyword name and place
f28b09f887870c10c8c611beee3c17eaa9ef74f3Lukas Slebodnik the changes to separate bit arrays. */
f3c85d900c4663854cc7bbae7d9f77867ed1f69bSumit Bose array_size = str_array_length(local_keywords) + count;
1270ffe9f3809f2fd488ef4a320d344ae107ab87Sumit Bose /* this message has no keywords */
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose /* @UNSAFE: create large enough arrays to fit all keyword indexes. */
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose /* get remote changes */
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose for (i = 0; i < count; i++) {
885386b7e3f1c3e74b354576b98a092b0835d64eSumit Bose switch (changes[i][0]) {
1270ffe9f3809f2fd488ef4a320d344ae107ab87Sumit Bose remote_remove[name_idx/32] |= 1U << (name_idx%32);
a9c287bda3fc2a1e12cef2135ade96945f11ad01Sumit Bose remote_final[name_idx/32] |= 1U << (name_idx%32);
a7e27c11866a48742bb70564b88e15bf15e9367dPavel Březina remote_add[name_idx/32] |= 1U << (name_idx%32);
a7e27c11866a48742bb70564b88e15bf15e9367dPavel Březina remote_final[name_idx/32] |= 1U << (name_idx%32);
a7e27c11866a48742bb70564b88e15bf15e9367dPavel Březina /* get local changes. use existing indexes for names when they exist. */
a7e27c11866a48742bb70564b88e15bf15e9367dPavel Březina for (i = 0; i < count; i++) {
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina if (!keyword_find(&all_keywords, name, &name_idx)) {
a7e27c11866a48742bb70564b88e15bf15e9367dPavel Březina switch (changes[i][0]) {
a7e27c11866a48742bb70564b88e15bf15e9367dPavel Březina local_add[name_idx/32] |= 1U << (name_idx%32);
a7e27c11866a48742bb70564b88e15bf15e9367dPavel Březina local_remove[name_idx/32] |= 1U << (name_idx%32);
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek if (!keyword_find(&all_keywords, name, &name_idx)) {
8c829226ce0cf98c35ffce39a66f9645cff65767Jakub Hrozek local_final[name_idx/32] |= 1U << (name_idx%32);
8c829226ce0cf98c35ffce39a66f9645cff65767Jakub Hrozek i_assert(array_count(&all_keywords) <= array_size*32);
8c829226ce0cf98c35ffce39a66f9645cff65767Jakub Hrozek array_size = (array_count(&all_keywords)+31) / 32;
41291f19dbc5bf14f20729959b852fa605fcc02dJakub Hrozek /* merge keywords */
c23ea7772113a163139a7b7669303e9e80dc1d09Jakub Hrozek for (i = 0; i < array_size; i++) {
41291f19dbc5bf14f20729959b852fa605fcc02dJakub Hrozek merge_flags(local_final[i], local_add[i], local_remove[i],
41291f19dbc5bf14f20729959b852fa605fcc02dJakub Hrozek remote_final[i], remote_add[i], remote_remove[i],
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek if (change_add[i] != 0) {
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek keywords_append(&remove_keywords, &all_keywords,
29c5542feb4c45865ea61be97e0e84a1d1f04918Jakub Hrozek /* apply changes */
769347ad4d35d43488eb98f980143495b0db415dStef Walterdsync_mailbox_import_replace_flags(struct mail *mail,
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter unsigned int i, count;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter changes = array_get(&change->keyword_changes, &count);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter for (i = 0; i < count; i++) {
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter switch (changes[i][0]) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher kw = mailbox_keywords_create_valid(mail->box, array_idx(&keywords, 0));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher mail_update_keywords(mail, MODIFY_REPLACE, kw);
d2d8f342cd5e90bb9fd947c448492225f959aa86Pavel Březina if (mail_get_pvt_modseq(mail) < change->pvt_modseq)
7ac503a73a26abe49f9f7d175c74df705380898dPavel Březina mail_update_pvt_modseq(mail, change->pvt_modseq);
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagherdsync_mailbox_import_flag_change(struct dsync_mailbox_importer *importer,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher const struct dsync_mail_change *local_change;
ef39c0adcb61b16f9edc7beb4cdc8f3b0d5a8f15Stephen Gallagher ARRAY_TYPE(const_string) local_keyword_changes = ARRAY_INIT;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher bool remote_changed = FALSE, remote_pvt_changed = FALSE;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert((change->add_flags & change->remove_flags) == 0);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (!dsync_import_set_mail(importer, change))
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* dsync backup: just make the local look like remote. */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher dsync_mailbox_import_replace_flags(mail, change);
bdc2aced1185c4ee36921fa01b8dc01789a63900Jakub Hrozek local_change = hash_table_lookup(importer->local_changes,
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina local_keyword_changes = local_change->keyword_changes;
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina else if (mail_get_modseq(mail) > change->modseq)
e5911e72198df96ec7cfe486ff66363c2297a5f7Simo Sorce /* identical modseq, we'll just have to pick one.
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnik Note that both brains need to pick the same one, otherwise
2827b0d03f7b6bafa504d22a5d7ca39cbda048b3Pavel Březina they become unsynced. */
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek if (mail_get_pvt_modseq(mail) < change->pvt_modseq)
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek else if (mail_get_pvt_modseq(mail) > change->pvt_modseq)
e5911e72198df96ec7cfe486ff66363c2297a5f7Simo Sorce /* merge flags */
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnik merge_flags(mail_get_flags(mail), local_add, local_remove,
9e80079370ff3b943832adc3c5ef430e64be0a0cJakub Hrozek change->final_flags, change->add_flags, change->remove_flags,
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta mail_update_flags(mail, MODIFY_REMOVE, change_remove);
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose /* merge keywords */
e5911e72198df96ec7cfe486ff66363c2297a5f7Simo Sorce merge_keywords(mail, &local_keyword_changes, &change->keyword_changes,
4de84af23db74e13e867985c9093f394c9fa8d51Sumit Bose prefer_remote, &remote_changed, &remote_pvt_changed);
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta /* update modseqs. try to anticipate when we have to increase modseq
e7311aec8d691e5427317442387af1bc8fff3742Jan Cholasta to get it closer to what remote has (although we can't guess it
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose exactly correctly) */
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose if (remote_changed && new_modseq <= importer->remote_highest_modseq)
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose if (remote_pvt_changed && new_modseq <= importer->remote_highest_pvt_modseq)
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bose new_modseq = importer->remote_highest_pvt_modseq+1;
b9e5bd09a5ff7009537a18914dbebcf10498f592Sumit Bosedsync_mail_change_have_keyword(const struct dsync_mail_change *change,
cb4d5b588e704114b7090678752d33512baa718eJakub Hrozek const char *const *strp;
8214510f125879c3b1d247f2ce981ee20b5375d1Jakub Hrozek if (!array_is_created(&change->keyword_changes))
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek array_foreach(&change->keyword_changes, strp) {
590582be38cdbfde387fcc57df92903d48c5a083Jakub Hrozek switch ((*strp)[0]) {
8214510f125879c3b1d247f2ce981ee20b5375d1Jakub Hrozekdsync_mailbox_import_want_change(struct dsync_mailbox_importer *importer,
1a59af8245f183f22d87d067a90197d8e2ea958dJakub Hrozek const char **result_r)
8a1fd0633e85221da1fb63451516a70d66c0af31Pavel Březina if (change->received_timestamp < importer->sync_since_timestamp) {
8a1fd0633e85221da1fb63451516a70d66c0af31Pavel Březina /* mail has too old timestamp - skip it */
8a1fd0633e85221da1fb63451516a70d66c0af31Pavel Březina *result_r = "Ignoring missing local mail with too old timestamp";
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce if (change->received_timestamp > importer->sync_until_timestamp) {
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce /* mail has too new timestamp - skip it */
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce *result_r = "Ignoring missing local mail with too new timestamp";
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce if (change->virtual_size < importer->sync_max_size) {
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce /* mail is too large - skip it */
1dd679584241a0f9b29072c7eed1c5c5e4a577e4Simo Sorce *result_r = "Ignoring missing local mail with too large size";
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce bool have_flag = (change->final_flags & importer->sync_flag) != 0;
a8d1a344e580f29699aed9b88d87fc3c6f5d113bSimo Sorce *result_r = "Ignoring missing local mail that doesn't have wanted flags";
376eaf187c13c2a1eaea0ffbdd970b6b563ab74cPetr Cech if (!have_flag && !importer->sync_flag_dontwant) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher *result_r = "Ignoring missing local mail that has unwanted flags";
38b2bd97e41388995594126ea4e6b7c55ea0eb5cPavel Březina bool have_kw = dsync_mail_change_have_keyword(change, importer->sync_keyword);
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina *result_r = "Ignoring missing local mail that doesn't have wanted keywords";
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina if (!have_kw && !importer->sync_flag_dontwant) {
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březina *result_r = "Ignoring missing local mail that has unwanted keywords";
d3dee2a07f1a8ee9ae6f94e149ced754ef76c248Pavel Březinadsync_mailbox_import_save(struct dsync_mailbox_importer *importer,
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher if (change->uid == importer->last_common_uid) {
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher /* we've already verified that the GUID matches.
ccf340e56364851f2e5b75e52d3d63701b662954Lukas Slebodnik apply flag changes if there are any. */
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher i_assert(!importer->last_common_uid_found);
fe2091327ff44f80d6681c261494e4432404e9baStephen Gallagher dsync_mailbox_import_flag_change(importer, change);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (!dsync_mailbox_import_want_change(importer, change, &result))
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher save = p_new(importer->pool, struct dsync_mail_change, 1);
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek dsync_mail_change_dup(importer->pool, change, save);
8359bf07a2e6c0181251ce8d5d9160dc57546c55Stephen Gallagher /* this is a new mail. its UID may or may not conflict with
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek an existing local mail, we'll figure it out later. */
530ba03ecabb472f17d5d1ab546aec9390492de1Jakub Hrozek i_assert(change->uid > importer->last_common_uid);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* the local mail is expunged. we'll decide later if we want
8a07521b413a3b5879f824e1872c5770c92ee5c0Stephen Gallagher to save this mail locally or expunge it form remote. */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(change->uid > importer->last_common_uid);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher array_append(&importer->maybe_saves, &save, 1);
59744cff6edb106ae799b2321cb8731edadf409aStephen Gallagherdsync_mailbox_import_expunge(struct dsync_mailbox_importer *importer,
59744cff6edb106ae799b2321cb8731edadf409aStephen Gallagher /* expunge the message, unless its GUID unexpectedly doesn't
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(change->uid <= importer->last_common_uid);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (dsync_import_set_mail(importer, change))
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* already expunged locally, we can ignore this.
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnik uid=last_common_uid if we managed to verify from
42ec8af02ecf1937e4db9b1ecc6216022634f0f9Michal Zidek transaction log that the GUIDs match */
42ec8af02ecf1937e4db9b1ecc6216022634f0f9Michal Zidek i_assert(change->uid >= importer->last_common_uid);
42ec8af02ecf1937e4db9b1ecc6216022634f0f9Michal Zidek } else if (change->uid == importer->last_common_uid) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* already verified that the GUID matches */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(importer->cur_mail->uid == change->uid);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (dsync_check_cur_guid(importer, change))
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnik /* we don't know yet if we should expunge this
654757bcead49427baaeb1b368c0e3433b67c51aJan Engelhardt message or not. queue it until we do. */
42ec8af02ecf1937e4db9b1ecc6216022634f0f9Michal Zidek i_assert(change->uid > importer->last_common_uid);
42ec8af02ecf1937e4db9b1ecc6216022634f0f9Michal Zidek seq_range_array_add(&importer->maybe_expunge_uids, change->uid);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherdsync_mailbox_rewind_search(struct dsync_mailbox_importer *importer)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* If there are local mails after last_common_uid which we skipped
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher while trying to match the next message, we need to now go back */
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnik importer->cur_mail->uid <= importer->last_common_uid+1)
a9eff330a7fbd231e8cc28a6828a1e5014ddb0d2Michal Zidek (void)mailbox_search_deinit(&importer->search_ctx);
2c0a971010596c122d7a0c0d76c8eb85f16f6d06Jakub Hrozekdsync_mailbox_common_uid_found(struct dsync_mailbox_importer *importer)
42ec8af02ecf1937e4db9b1ecc6216022634f0f9Michal Zidek unsigned int n, i, count;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher imap_write_seq_range(expunges, &importer->maybe_expunge_uids);
2c0a971010596c122d7a0c0d76c8eb85f16f6d06Jakub Hrozek imp_debug(importer, "Last common UID=%u. Delayed expunges=%s",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher importer->last_common_uid, str_c(expunges));
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* expunge the messages whose expunge-decision we delayed previously */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher seq_range_array_iter_init(&iter, &importer->maybe_expunge_uids); n = 0;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher while (seq_range_array_iter_nth(&iter, n++, &uid)) {
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnik /* we expunge messages only up to last_common_uid,
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnik ignore the rest */
543676afec3c08fdc0a5a794976adc8dfdca974bJakub Hrozek /* handle pending saves */
654757bcead49427baaeb1b368c0e3433b67c51aJan Engelhardt saves = array_get(&importer->maybe_saves, &count);
c737e1444fb186e349e59bfa9dac4995b720b4b1Jan Zeleny for (i = 0; i < count; i++) {
f1828234a850dd28465425248a83a993f262918fPavel Březina if (saves[i]->uid > importer->last_common_uid) {
f1828234a850dd28465425248a83a993f262918fPavel Březina imp_debug(importer, "Delayed save UID=%u: Save",
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnik imp_debug(importer, "Delayed save UID=%u: Ignore",
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnikdsync_mailbox_import_match_msg(struct dsync_mailbox_importer *importer,
1746e8b8399da2a7a8da4aace186f66055ccfec1Jakub Hrozek const char **result_r)
1746e8b8399da2a7a8da4aace186f66055ccfec1Jakub Hrozek if (*change->guid != '\0' && *importer->cur_guid != '\0') {
1746e8b8399da2a7a8da4aace186f66055ccfec1Jakub Hrozek /* we have GUIDs, verify them */
1746e8b8399da2a7a8da4aace186f66055ccfec1Jakub Hrozek if (dsync_mail_change_guid_equals(importer, change,
23fb01bf67a6058fb508da6d81515e8b18634bebPavel Březina *result_r = t_strdup_printf("GUIDs don't match (%s vs %s)",
b69cb1787209e85cc246eb9a944242689bfe0c46Pavel Březina /* verify hdr_hash if it exists */
b69cb1787209e85cc246eb9a944242689bfe0c46Pavel Březina if (change->type == DSYNC_MAIL_CHANGE_TYPE_EXPUNGE) {
b69cb1787209e85cc246eb9a944242689bfe0c46Pavel Březina /* the message was already expunged, so we don't know
e157b9f6cb370e1b94bcac2044d26ad66d640fbaPavel Březina its header. return "unknown". */
e157b9f6cb370e1b94bcac2044d26ad66d640fbaPavel Březina "sync with header hashes instead",
e157b9f6cb370e1b94bcac2044d26ad66d640fbaPavel Březina if (dsync_mail_get_hdr_hash(importer->cur_mail,
e157b9f6cb370e1b94bcac2044d26ad66d640fbaPavel Březina dsync_mail_error(importer, importer->cur_mail, "hdr-stream");
f8c829e72968b574e1c9bda96f4d5f206622358fPavel Březina (dsync_mail_hdr_hash_is_empty(change->hdr_hash) ||
42870c7ac3608ffc58f2c9524ad3dfc1401bc1aaPavel Březina *result_r = "Empty headers found with workaround enabled - assuming a match";
70e59ed31c5a9c9ed02d9065ddf92be87c887efbJakub Hrozek } else if (strcmp(change->hdr_hash, hdr_hash) == 0) {
f8c829e72968b574e1c9bda96f4d5f206622358fPavel Březina *result_r = t_strdup_printf("Headers hashes don't match (%s vs %s)",
558998ce664055a75595371118f818084d8f2b23Jan Cholastadsync_mailbox_find_common_expunged_uid(struct dsync_mailbox_importer *importer,
9a3e40dc49c1e38bf58e45be5adff37615f3910bJan Cholasta /* remote doesn't support GUIDs, can't verify expunge */
9a3e40dc49c1e38bf58e45be5adff37615f3910bJan Cholasta *result_r = "GUIDs not supported, can't verify expunge";
558998ce664055a75595371118f818084d8f2b23Jan Cholasta /* local message is expunged. see if we can find its GUID from
558998ce664055a75595371118f818084d8f2b23Jan Cholasta transaction log and check if the GUIDs match. The GUID in
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher log is a 128bit GUID, so we may need to convert the remote's
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher GUID string to 128bit GUID first. */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher local_change = hash_table_lookup(importer->local_changes,
62b20154899f847e760d6dfbae6a32fb45b448deLukas Slebodnik if (local_change == NULL || local_change->guid == NULL) {
cbff3fcdce5b0377a62fbe74f32e476efbf7ca9cNikolai Kondrashov *result_r = "Expunged local mail's GUID not found";
87d3b47abba6a40fcf809c85a2b138bc1013d9c5Jakub Hrozek i_assert(local_change->type == DSYNC_MAIL_CHANGE_TYPE_EXPUNGE);
21f28bdbab10881b9fb0b890dfa15af429326606Sumit Bose if (dsync_mail_change_guid_equals(importer, local_change,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher *result_r = "Expunged local mail's GUID matches remote";
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher } else if (change->type != DSYNC_MAIL_CHANGE_TYPE_EXPUNGE) {
d65f692d7b7639ed8ba0f5cffa4f88b68056739aLukas Slebodnik *result_r = "Expunged local mail's GUID doesn't match remote GUID";
d65f692d7b7639ed8ba0f5cffa4f88b68056739aLukas Slebodnik /* GUID mismatch for two expunged mails. dsync can't update
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher GUIDs for already expunged messages, so we can't immediately
221619d8e8d7cf269c55482e5f466f6511ed35adLukas Slebodnik determine that the rest of the messages are a mismatch. so
25c394fc9d09aa7f58700e67b942aba86505934aLukas Slebodnik for now we'll just skip over this pair. */
af820c9fc6aa1768e2e6b0df78fb489dbb1b28d0Pavel Březina *result_r = "Expunged mails' GUIDs don't match - delaying decision";
af820c9fc6aa1768e2e6b0df78fb489dbb1b28d0Pavel Březina /* NOTE: the return value here doesn't matter, because the only
af820c9fc6aa1768e2e6b0df78fb489dbb1b28d0Pavel Březina caller that checks for it never reaches this code path */
f74d7744f1b12fe0492eadfc8cf30afcb4092e40Lukas Slebodnikdsync_mailbox_revert_missing(struct dsync_mailbox_importer *importer,
a801d42c4637bbdf9664d0d8b913ffcab81b904eLukas Slebodnik /* mail exists on remote, but not locally. we'll need to
1d1a0a019d8d4d9ab0f51ada03604cd2cada287eSumit Bose insert this mail back, which means deleting the whole
1d1a0a019d8d4d9ab0f51ada03604cd2cada287eSumit Bose mailbox and resyncing. */
1d1a0a019d8d4d9ab0f51ada03604cd2cada287eSumit Bose i_warning("Deleting mailbox '%s': UID=%u GUID=%s is missing locally",
36ccdecd053a9ad88dce86b8c84770dc2aa11d21Simo Sorcedsync_mailbox_find_common_uid(struct dsync_mailbox_importer *importer,
36ccdecd053a9ad88dce86b8c84770dc2aa11d21Simo Sorce const char **result_r)
36ccdecd053a9ad88dce86b8c84770dc2aa11d21Simo Sorce i_assert(change->type == DSYNC_MAIL_CHANGE_TYPE_EXPUNGE ||
36ccdecd053a9ad88dce86b8c84770dc2aa11d21Simo Sorce (change->virtual_size != (uoff_t)-1 || importer->sync_max_size == 0)));
36ccdecd053a9ad88dce86b8c84770dc2aa11d21Simo Sorce /* try to find the matching local mail */
f28b09f887870c10c8c611beee3c17eaa9ef74f3Lukas Slebodnik if (!importer_next_mail(importer, change->uid)) {
f28b09f887870c10c8c611beee3c17eaa9ef74f3Lukas Slebodnik /* no more local mails. we can still try to match
f28b09f887870c10c8c611beee3c17eaa9ef74f3Lukas Slebodnik expunged mails though. */
f28b09f887870c10c8c611beee3c17eaa9ef74f3Lukas Slebodnik if (change->type == DSYNC_MAIL_CHANGE_TYPE_EXPUNGE) {
f28b09f887870c10c8c611beee3c17eaa9ef74f3Lukas Slebodnik /* mail doesn't exist remotely either, don't bother
f28b09f887870c10c8c611beee3c17eaa9ef74f3Lukas Slebodnik looking it up locally. */
f28b09f887870c10c8c611beee3c17eaa9ef74f3Lukas Slebodnik *result_r = "Expunged mail not found locally";
a801d42c4637bbdf9664d0d8b913ffcab81b904eLukas Slebodnik if (!dsync_mailbox_import_want_change(importer, change, result_r))
a801d42c4637bbdf9664d0d8b913ffcab81b904eLukas Slebodnik else if (importer->local_uid_next <= change->uid) {
a801d42c4637bbdf9664d0d8b913ffcab81b904eLukas Slebodnik *result_r = "Mail's UID is above local UIDNEXT";
a801d42c4637bbdf9664d0d8b913ffcab81b904eLukas Slebodnik } else if (importer->revert_local_changes) {
a801d42c4637bbdf9664d0d8b913ffcab81b904eLukas Slebodnik dsync_mailbox_revert_missing(importer, change);
a801d42c4637bbdf9664d0d8b913ffcab81b904eLukas Slebodnik *result_r = "Reverting local change by deleting mailbox";
36ccdecd053a9ad88dce86b8c84770dc2aa11d21Simo Sorce } else if (!dsync_mailbox_find_common_expunged_uid(importer, change, result_r)) {
36ccdecd053a9ad88dce86b8c84770dc2aa11d21Simo Sorce /* it's unknown if this mail existed locally and was
36ccdecd053a9ad88dce86b8c84770dc2aa11d21Simo Sorce expunged. since we don't want to lose any mails,
36ccdecd053a9ad88dce86b8c84770dc2aa11d21Simo Sorce assume that we need to preserve the mail. use the
36ccdecd053a9ad88dce86b8c84770dc2aa11d21Simo Sorce last message with a matching GUID as the last common
36ccdecd053a9ad88dce86b8c84770dc2aa11d21Simo Sorce *result_r = t_strdup_printf("%s - No more local mails found", *result_r);
4b39208286ca0351ee76d4e64e077e7ad5ca8568Jakub Hrozek /* we can't know if this UID matches */
4b39208286ca0351ee76d4e64e077e7ad5ca8568Jakub Hrozek i_assert(change->type == DSYNC_MAIL_CHANGE_TYPE_EXPUNGE);
4b39208286ca0351ee76d4e64e077e7ad5ca8568Jakub Hrozek *result_r = "Expunged mail has no GUID, can't verify it";
4b39208286ca0351ee76d4e64e077e7ad5ca8568Jakub Hrozek /* we have a matching local UID. check GUID to see if it's
4b39208286ca0351ee76d4e64e077e7ad5ca8568Jakub Hrozek really the same mail or not */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if ((ret = dsync_mailbox_import_match_msg(importer, change, result_r)) < 0) {
16c351625346b3193e1762027e5215ab76042127Sumit Bose /* unknown */
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek /* mismatch - found the first non-common UID */
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek /* mismatch and we want to revert local changes -
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnik need to delete the mailbox. */
25f8fac2489fd209d603acb2b494f7c72968e9bbMichal Zidek dsync_mailbox_revert_existing_uid(importer, change->uid, *result_r);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* mail exists remotely, but doesn't exist locally. */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (!dsync_mailbox_import_want_change(importer, change, result_r))
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher change->type != DSYNC_MAIL_CHANGE_TYPE_EXPUNGE) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher dsync_mailbox_revert_missing(importer, change);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher *result_r = "Reverting local change by deleting mailbox";
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher (void)dsync_mailbox_find_common_expunged_uid(importer, change, result_r);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher *result_r = t_strdup_printf("%s (next local mail UID=%u)",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher *result_r, importer->cur_mail == NULL ? 0 : importer->cur_mail->uid);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherint dsync_mailbox_import_change(struct dsync_mailbox_importer *importer,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher dsync_mailbox_find_common_uid(importer, change, &result);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher imp_debug(importer, "Import change type=%s GUID=%s UID=%u hdr_hash=%s result=%s",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher dsync_mail_change_type_names[change->type],
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher change->guid != NULL ? change->guid : "<unknown>", change->uid,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher change->hdr_hash != NULL ? change->hdr_hash : "", result);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* a) uid <= last_common_uid for flag changes and expunges.
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher this happens only when last_common_uid was originally given
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher as parameter to importer.
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher when we're finding the last_common_uid ourself,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher uid>last_common_uid always in here, because
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher last_common_uid_found=TRUE only after we find the first
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher b) uid > last_common_uid for i) new messages, ii) expunges
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher that were sent "just in case" */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (change->uid <= importer->last_common_uid) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(change->type != DSYNC_MAIL_CHANGE_TYPE_SAVE);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher } else if (change->type == DSYNC_MAIL_CHANGE_TYPE_EXPUNGE) {
9d7d4458d94d0aac0a7edf999368eb18f89cb76aJakub Hrozek /* ignore */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(change->type == DSYNC_MAIL_CHANGE_TYPE_SAVE);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* a) uid < last_common_uid can never happen */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(change->uid >= importer->last_common_uid);
22d381367c27910fe82f476a76b9f4ede555e35aLukas Slebodnik /* b) uid = last_common_uid if we've verified that the
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnik messages' GUIDs match so far.
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher c) uid > last_common_uid: i) TYPE_EXPUNGE change has
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher GUID=NULL, so we couldn't verify yet if it matches our
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher local message, ii) local message is expunged and we couldn't
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher find its GUID */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (change->uid > importer->last_common_uid) {
2de495aed26bf75a750a76ca73b9f85d341fe1c5Pavel Březina i_assert(change->type == DSYNC_MAIL_CHANGE_TYPE_EXPUNGE ||
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher dsync_mailbox_import_save(importer, change);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher dsync_mailbox_import_expunge(importer, change);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(importer->last_common_uid_found);
e3c06950bdb0bee6df603b101b30b75ef38439a4Lukas Slebodnik dsync_mailbox_import_flag_change(importer, change);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherimporter_new_mail_final_uid_cmp(struct importer_new_mail *const *newmail1,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct importer_new_mail *const *newmail2)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if ((*newmail1)->final_uid < (*newmail2)->final_uid)
e3c06950bdb0bee6df603b101b30b75ef38439a4Lukas Slebodnik if ((*newmail1)->final_uid > (*newmail2)->final_uid)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherdsync_mailbox_import_assign_new_uids(struct dsync_mailbox_importer *importer)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct importer_new_mail *newmail, *const *newmailp;
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher common_uid_next = I_MAX(importer->local_uid_next,
9d7d4458d94d0aac0a7edf999368eb18f89cb76aJakub Hrozek array_foreach_modifiable(&importer->newmails, newmailp) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* already assigned */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* figure out what UID to use for the mail */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* keep the UID */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* we can use the linked message's UID and expunge
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher i_assert(!importer->revert_local_changes);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher imp_debug(importer, "UID %u isn't usable, assigning new UID %u",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (newmail->link != NULL && newmail->link != newmail) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* skip processing the linked mail */
f7ea0b1d46197275c87bdc73a6e38a6fd7f855eePavel Březina /* Sort the newmails by their final_uid. This is used for tracking
9e6f8d1c66b4b3543bab67d807bd26f1d6256c75Pavel Březina whether an intermediate commit is allowed. */
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina array_sort(&importer->newmails, importer_new_mail_final_uid_cmp);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherdsync_mailbox_import_local_uid(struct dsync_mailbox_importer *importer,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher struct mail *mail, uint32_t uid, const char *guid,
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher /* NOTE: Errors are logged, but they don't cause the entire import
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (dsync_mail_fill(mail, TRUE, dmail_r, &error_field) < 0) {
f7ea0b1d46197275c87bdc73a6e38a6fd7f855eePavel Březina errstr = mailbox_get_last_internal_error(mail->box, &error);
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher i_error("Mailbox %s: Can't lookup %s for UID=%u: %s",
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher if (*guid != '\0' && strcmp(guid, dmail_r->guid) != 0) {
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher dsync_import_unexpected_state(importer, t_strdup_printf(
effcbdb12c7ef892f1fd92a745cb33a08ca4ba30Stephen Gallagher "Unexpected GUID mismatch (3) for UID=%u: %s != %s",
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagherdsync_mailbox_import_saved_uid(struct dsync_mailbox_importer *importer,
b9d8c6172e48a2633ebe196b2e88bebdf9523c20Stef Walterdsync_mailbox_import_update_first_saved(struct dsync_mailbox_importer *importer)
b9d8c6172e48a2633ebe196b2e88bebdf9523c20Stef Walter unsigned int count;
b9d8c6172e48a2633ebe196b2e88bebdf9523c20Stef Walter newmails = array_get(&importer->newmails, &count);
fe60346714a73ac3987f786731389320633dd245Pavel Březina if (!newmails[importer->first_unsaved_idx]->saved)
fe60346714a73ac3987f786731389320633dd245Pavel Březinadsync_mailbox_import_saved_newmail(struct dsync_mailbox_importer *importer,
fe60346714a73ac3987f786731389320633dd245Pavel Březina dsync_mailbox_import_saved_uid(importer, newmail->final_uid);
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek dsync_mailbox_import_update_first_saved(importer);
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek /* we can commit only if all the upcoming mails will have UIDs that
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek are larger than we're committing.
8f61739e0de45ce2ee3be436fc91ef12a1a1c4f3Lukas Slebodnik Note that if any existing UIDs have been changed, the new UID is
8f61739e0de45ce2ee3be436fc91ef12a1a1c4f3Lukas Slebodnik usually higher than anything that is being saved so we can't do
8f61739e0de45ce2ee3be436fc91ef12a1a1c4f3Lukas Slebodnik an intermediate commit. It's too much extra work to try to handle
8f61739e0de45ce2ee3be436fc91ef12a1a1c4f3Lukas Slebodnik that situation. So here this never happens, because then
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek array_count(wanted_uids) is always higher than first_unsaved_idx. */
69aaef8719c5cf33ed1c4090fa313ba281bf8a02Jakub Hrozek if (importer->saves_since_commit >= importer->commit_msgs_interval &&
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher importer->first_unsaved_idx == array_count(&importer->wanted_uids)) {
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagher if (dsync_mailbox_import_commit(importer, FALSE) < 0)
4dd615c01357b8715711aad6820ba9595d3ad377Stephen Gallagherdsync_msg_change_uid(struct dsync_mailbox_importer *importer,
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bose save_ctx = mailbox_save_alloc(importer->ext_trans);
a6098862048d4bb469130b9ff21be3020d6f2c54Sumit Bose mailbox_save_copy_flags(save_ctx, importer->mail);
2d257ccf620ce1b611f89cec8f0a94c88c2f2881Sumit Bose dsync_mailbox_import_saved_uid(importer, new_uid);
83a79d93035c2d75a1941f3b54426119174044a0Pavel Březinadsync_mailbox_import_change_uid(struct dsync_mailbox_importer *importer,
2d257ccf620ce1b611f89cec8f0a94c88c2f2881Sumit Bose unsigned int count, n;
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnik /* optimize by first trying to use the latest UID */
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (dsync_msg_change_uid(importer, range[count-1].seq2, wanted_uid)) {
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher seq_range_array_remove(unwanted_uids, range[count-1].seq2);
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher if (mailbox_get_last_mail_error(importer->box) == MAIL_ERROR_EXPUNGED)
551aa6c36797ed720487f5974dcadabf19e6ff9fStephen Gallagher seq_range_array_remove(unwanted_uids, range[count-1].seq2);
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek /* now try to use any of them by iterating through them. (would be
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek easier&faster to just iterate backwards, but probably too much
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek trouble to add such API) */
45aeb924ec3ac448bb8d174a5cc061ed98b147c7Jakub Hrozek n = 0; seq_range_array_iter_init(&iter, unwanted_uids);
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek while (seq_range_array_iter_nth(&iter, n++, &uid)) {
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek if (dsync_msg_change_uid(importer, uid, wanted_uid)) {
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek if (mailbox_get_last_mail_error(importer->box) == MAIL_ERROR_EXPUNGED)
f232789430a080384188d5da89b19d874cf17513Jakub Hrozekdsync_mailbox_import_try_local(struct dsync_mailbox_importer *importer,
f232789430a080384188d5da89b19d874cf17513Jakub Hrozek ARRAY_TYPE(seq_range) assigned_uids, unwanted_uids;
f5e47e1d65f80ffdb1893feab18583a74d661214Stef Walter seq_range_array_iter_init(&local_iter, local_uids);
f5e47e1d65f80ffdb1893feab18583a74d661214Stef Walter seq_range_array_iter_init(&wanted_iter, wanted_uids);
f5e47e1d65f80ffdb1893feab18583a74d661214Stef Walter /* wanted_uids contains UIDs that need to exist at the end. those that
f5e47e1d65f80ffdb1893feab18583a74d661214Stef Walter don't already exist in local_uids have a higher UID than any
f5e47e1d65f80ffdb1893feab18583a74d661214Stef Walter existing local UID */
f5e47e1d65f80ffdb1893feab18583a74d661214Stef Walter t_array_init(&assigned_uids, array_count(wanted_uids));
7ac503a73a26abe49f9f7d175c74df705380898dPavel Březina while (seq_range_array_iter_nth(&local_iter, local_n++, &local_uid)) {
7ac503a73a26abe49f9f7d175c74df705380898dPavel Březina if (seq_range_array_iter_nth(&wanted_iter, wanted_n,
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter /* we have exactly the UID we want. keep it. */
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter seq_range_array_add(&assigned_uids, wanted_uid);
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek /* we no longer want this local UID. */
4bd20c075f0f187db0181dc53d00ab6cd47fdb4dJakub Hrozek seq_range_array_add(&unwanted_uids, local_uid);
80314a6f3ea8d81abe73d501d5b953a256cb2167Pavel Březina /* reuse as many existing messages as possible by changing their UIDs */
80314a6f3ea8d81abe73d501d5b953a256cb2167Pavel Březina while (seq_range_array_iter_nth(&wanted_iter, wanted_n, &wanted_uid)) {
80314a6f3ea8d81abe73d501d5b953a256cb2167Pavel Březina if (!dsync_mailbox_import_change_uid(importer, &unwanted_uids,
80314a6f3ea8d81abe73d501d5b953a256cb2167Pavel Březina seq_range_array_add(&assigned_uids, wanted_uid);
80314a6f3ea8d81abe73d501d5b953a256cb2167Pavel Březina /* expunge all unwanted messages */
80314a6f3ea8d81abe73d501d5b953a256cb2167Pavel Březina local_n = 0; seq_range_array_iter_init(&local_iter, &unwanted_uids);
80314a6f3ea8d81abe73d501d5b953a256cb2167Pavel Březina while (seq_range_array_iter_nth(&local_iter, local_n++, &local_uid)) {
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek /* mark mails whose UIDs we got to be skipped over later */
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek for (mail = all_newmails; mail != NULL; mail = mail->next) {
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek seq_range_exists(&assigned_uids, mail->final_uid))
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina if (!seq_range_array_iter_nth(&wanted_iter, wanted_n, &wanted_uid)) {
83a79d93035c2d75a1941f3b54426119174044a0Pavel Březina /* we've assigned all wanted UIDs */
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek /* try to find one existing message that we can use to copy to the
dc70b11ddc2dfc6ed99cd895f020cd3429278968Pavel Březina other instances */
5dbf360f2d6b0281c32f1bba6ebf5cc834c1716eSimo Sorce local_n = 0; seq_range_array_iter_init(&local_iter, local_uids);
dc70b11ddc2dfc6ed99cd895f020cd3429278968Pavel Březina while (seq_range_array_iter_nth(&local_iter, local_n++, &local_uid)) {
dc70b11ddc2dfc6ed99cd895f020cd3429278968Pavel Březina if (dsync_mailbox_import_local_uid(importer, importer->mail,
dc70b11ddc2dfc6ed99cd895f020cd3429278968Pavel Březina if (dsync_mailbox_save_newmails(importer, &dmail,
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozekdsync_mailbox_import_try_virtual_all(struct dsync_mailbox_importer *importer,
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek if (dsync_mailbox_import_local_uid(importer, importer->virtual_mail,
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek if (dsync_mailbox_save_newmails(importer, &dmail,
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozekdsync_mailbox_import_handle_mail(struct dsync_mailbox_importer *importer,
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek /* get the list of the current local UIDs and the wanted UIDs.
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek find the first remote instance that we can request in case there are
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek no local instances */
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek for (mail = all_newmails; mail != NULL; mail = mail->next) {
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek seq_range_array_add(&local_uids, mail->local_uid);
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek seq_range_array_add(&wanted_uids, mail->final_uid);
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek if (!dsync_mailbox_import_try_local(importer, all_newmails,
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek !dsync_mailbox_import_try_virtual_all(importer, all_newmails)) {
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek /* no local instance. request from remote */
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek request = array_append_space(&importer->mail_requests);
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek /* successfully handled all the mails locally */
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozekdsync_mailbox_import_find_virtual_uids(struct dsync_mailbox_importer *importer)
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek const char *guid;
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek if (mailbox_sync(importer->virtual_all_box, 0) < 0) {
7caf7ed4f2eae1ec1c0717b4ee6ce78bdacd5926Jakub Hrozek mailbox_get_last_internal_error(importer->virtual_all_box, NULL));
0161a3c5637a0c0092bf54c436bb3d6508d7df26Jakub Hrozek mailbox_transaction_begin(importer->virtual_all_box,
0161a3c5637a0c0092bf54c436bb3d6508d7df26Jakub Hrozek search_ctx = mailbox_search_init(importer->virtual_trans, search_args,
0161a3c5637a0c0092bf54c436bb3d6508d7df26Jakub Hrozek while (mailbox_search_next(search_ctx, &mail)) {
0161a3c5637a0c0092bf54c436bb3d6508d7df26Jakub Hrozek if (mail_get_special(mail, MAIL_FETCH_GUID, &guid) < 0) {
0161a3c5637a0c0092bf54c436bb3d6508d7df26Jakub Hrozek /* ignore errors */
0161a3c5637a0c0092bf54c436bb3d6508d7df26Jakub Hrozek newmail = hash_table_lookup(importer->import_guids, guid);
0161a3c5637a0c0092bf54c436bb3d6508d7df26Jakub Hrozek if (newmail != NULL && newmail->virtual_all_uid == 0)
a65a64aee968bd2ac18156ced15a1e2509a8acbaAbhishek Singh if (mailbox_search_deinit(&search_ctx) < 0) {
a65a64aee968bd2ac18156ced15a1e2509a8acbaAbhishek Singh i_error("Couldn't search \\All mailbox '%s': %s",
a65a64aee968bd2ac18156ced15a1e2509a8acbaAbhishek Singh mailbox_get_vname(importer->virtual_all_box),
a65a64aee968bd2ac18156ced15a1e2509a8acbaAbhishek Singh mailbox_get_last_internal_error(importer->virtual_all_box, NULL));
a65a64aee968bd2ac18156ced15a1e2509a8acbaAbhishek Singh importer->virtual_mail = mail_alloc(importer->virtual_trans, 0, NULL);
a65a64aee968bd2ac18156ced15a1e2509a8acbaAbhishek Singhdsync_mailbox_import_handle_local_mails(struct dsync_mailbox_importer *importer)
b49a7d90708e816120ff88ce5a88fa62b35ff795Simo Sorce const char *key;
25255e4d0e1517a5d443e8fee22e91862e255702Abhishek Singh hash_table_count(importer->import_guids) > 0) {
25255e4d0e1517a5d443e8fee22e91862e255702Abhishek Singh /* find UIDs in \All mailbox for all wanted GUIDs. */
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh dsync_mailbox_import_find_virtual_uids(importer);
ae6c1596225c65bec2a2dabff9eee4e3e0691181Abhishek Singh iter = hash_table_iterate_init(importer->import_guids);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek while (hash_table_iterate(iter, importer->import_guids, &key, &mail)) {
d00ffd2cb4e2f17c75b466178bb645b5c9317909Pallavi Jha if (dsync_mailbox_import_handle_mail(importer, mail))
d00ffd2cb4e2f17c75b466178bb645b5c9317909Pallavi Jha iter = hash_table_iterate_init(importer->import_uids);
d00ffd2cb4e2f17c75b466178bb645b5c9317909Pallavi Jha while (hash_table_iterate(iter, importer->import_uids, &key2, &mail)) {
d00ffd2cb4e2f17c75b466178bb645b5c9317909Pallavi Jha if (dsync_mailbox_import_handle_mail(importer, mail))
d00ffd2cb4e2f17c75b466178bb645b5c9317909Pallavi Jhaint dsync_mailbox_import_changes_finish(struct dsync_mailbox_importer *importer)
461da2984c747708e8badd27fa55ef879f40e712Pallavi Jha /* handle pending expunges and flag updates */
461da2984c747708e8badd27fa55ef879f40e712Pallavi Jha /* skip common local mails */
80b5dbe123ec94c5a8fcb99f9a4953c1513deb58Sumit Bose (void)importer_next_mail(importer, importer->last_common_uid+1);
461da2984c747708e8badd27fa55ef879f40e712Pallavi Jha /* if there are any local mails left, add them to newmails list */
461da2984c747708e8badd27fa55ef879f40e712Pallavi Jha while (importer->cur_mail != NULL && !importer->failed)
80b5dbe123ec94c5a8fcb99f9a4953c1513deb58Sumit Bose if (mailbox_search_deinit(&importer->search_ctx) < 0) {
d65f692d7b7639ed8ba0f5cffa4f88b68056739aLukas Slebodnik importer->import_count = hash_table_count(importer->import_guids) +
f28b09f887870c10c8c611beee3c17eaa9ef74f3Lukas Slebodnik dsync_mailbox_import_assign_new_uids(importer);
d65f692d7b7639ed8ba0f5cffa4f88b68056739aLukas Slebodnik /* save mails from local sources where possible,
16c351625346b3193e1762027e5215ab76042127Sumit Bose request the rest from remote */
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek dsync_mailbox_import_handle_local_mails(importer);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozekdsync_mailbox_import_next_request(struct dsync_mailbox_importer *importer)
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek unsigned int count;
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek requests = array_get(&importer->mail_requests, &count);
9cb46bc62f22e0104f1b41a423b014c281ef5fc2Jakub Hrozek return &requests[importer->mail_request_idx++];
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnikstatic const char *const *
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnikdsync_mailbox_get_final_keywords(const struct dsync_mail_change *change)
777374243e15c53e7b0a7345e190c1018920be18Jakub Hrozek const char *const *changes;
777374243e15c53e7b0a7345e190c1018920be18Jakub Hrozek unsigned int i, count;
777374243e15c53e7b0a7345e190c1018920be18Jakub Hrozek if (!array_is_created(&change->keyword_changes))
577ba99b3150404533bd3d859522a2c994b17e76Lukas Slebodnik changes = array_get(&change->keyword_changes, &count);
777374243e15c53e7b0a7345e190c1018920be18Jakub Hrozek for (i = 0; i < count; i++) {
3432a503c714732407ea18b2dd32f4f432a6c545Jakub Hrozek changes[i][0] == KEYWORD_CHANGE_ADD_AND_FINAL) {
3432a503c714732407ea18b2dd32f4f432a6c545Jakub Hrozekdsync_mailbox_save_set_metadata(struct dsync_mailbox_importer *importer,
3432a503c714732407ea18b2dd32f4f432a6c545Jakub Hrozek const char *const *keyword_names;
3432a503c714732407ea18b2dd32f4f432a6c545Jakub Hrozek keyword_names = dsync_mailbox_get_final_keywords(change);
d064fef06dcbcb5f6c1be03e286b1a3433d6dfd7Sumit Bose mailbox_save_set_flags(save_ctx, change->final_flags, keywords);
d064fef06dcbcb5f6c1be03e286b1a3433d6dfd7Sumit Bose (void)mailbox_enable(importer->box, MAILBOX_FEATURE_CONDSTORE);
f69f3581658351003a6d9245045e41d0efb85022Sumit Bose mailbox_save_set_min_modseq(save_ctx, change->modseq);
f69f3581658351003a6d9245045e41d0efb85022Sumit Bose /* FIXME: if there already are private flags, they get lost because
f69f3581658351003a6d9245045e41d0efb85022Sumit Bose saving can't handle updating private index. they get added on the
f69f3581658351003a6d9245045e41d0efb85022Sumit Bose next sync though. if this is fixed here, set min_pvt_modseq also. */
f69f3581658351003a6d9245045e41d0efb85022Sumit Bosedsync_msg_try_copy(struct dsync_mailbox_importer *importer,
d064fef06dcbcb5f6c1be03e286b1a3433d6dfd7Sumit Bose for (inst = *all_newmails_forcopy; inst != NULL; inst = inst->next) {
939246537b0b9a4af6862c513d3919501ad57d92Sumit Bose if (mailbox_copy(save_ctx_p, importer->mail) < 0) {
cebdc563a094d305b91da5b5af4d95d8e3a1bf27Pavel Reichldsync_mailbox_save_set_nonminimal(struct mail_save_context *save_ctx,
cebdc563a094d305b91da5b5af4d95d8e3a1bf27Pavel Reichl if (mail->pop3_uidl != NULL && *mail->pop3_uidl != '\0')
802909e59daa52c734dbe7f8fa13b0ee23e3e576Lukas Slebodnik mailbox_save_set_pop3_uidl(save_ctx, mail->pop3_uidl);
cebdc563a094d305b91da5b5af4d95d8e3a1bf27Pavel Reichl mailbox_save_set_pop3_order(save_ctx, mail->pop3_order);
802909e59daa52c734dbe7f8fa13b0ee23e3e576Lukas Slebodnik mailbox_save_set_received_date(save_ctx, mail->received_date, 0);
50b8a36b0932a510e825ed1ad8103f81ead2b7d8Pavel Reichldsync_mailbox_save_init(struct dsync_mailbox_importer *importer,
802909e59daa52c734dbe7f8fa13b0ee23e3e576Lukas Slebodnik save_ctx = mailbox_save_alloc(importer->ext_trans);
50b8a36b0932a510e825ed1ad8103f81ead2b7d8Pavel Reichl mailbox_save_set_uid(save_ctx, newmail->final_uid);
802909e59daa52c734dbe7f8fa13b0ee23e3e576Lukas Slebodnik mailbox_save_set_guid(save_ctx, mail->guid);
50b8a36b0932a510e825ed1ad8103f81ead2b7d8Pavel Reichl mailbox_save_set_save_date(save_ctx, mail->saved_date);
338af078fcc18126df939f20182acea7a646b7c8Michal Zidek dsync_mailbox_save_set_metadata(importer, save_ctx, newmail->change);
338af078fcc18126df939f20182acea7a646b7c8Michal Zidek dsync_mailbox_save_set_nonminimal(save_ctx, mail);
338af078fcc18126df939f20182acea7a646b7c8Michal Zidekdsync_mailbox_save_body(struct dsync_mailbox_importer *importer,
338af078fcc18126df939f20182acea7a646b7c8Michal Zidek struct importer_new_mail **all_newmails_forcopy,
50b8a36b0932a510e825ed1ad8103f81ead2b7d8Pavel Reichl /* try to save the mail by copying an existing mail */
802909e59daa52c734dbe7f8fa13b0ee23e3e576Lukas Slebodnik save_ctx = dsync_mailbox_save_init(importer, mail, newmail);
50b8a36b0932a510e825ed1ad8103f81ead2b7d8Pavel Reichl if ((ret = dsync_msg_try_copy(importer, &save_ctx, all_newmails_forcopy)) < 0) {
802909e59daa52c734dbe7f8fa13b0ee23e3e576Lukas Slebodnik save_ctx = dsync_mailbox_save_init(importer, mail, newmail);
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek /* copy using the source mail */
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek i_assert(mail->input_mail->uid == mail->input_mail_uid);
1ce58f139699dd26b8888f4131c996263b6a80a5Jakub Hrozek if (mailbox_copy(&save_ctx, mail->input_mail) == 0)
802909e59daa52c734dbe7f8fa13b0ee23e3e576Lukas Slebodnik save_ctx = dsync_mailbox_save_init(importer, mail, newmail);
802909e59daa52c734dbe7f8fa13b0ee23e3e576Lukas Slebodnik dsync_mailbox_import_saved_newmail(importer, newmail);
0352c371e743d8dae996123f658b5d32c677614eYassir Elley /* fallback to saving from remote stream */
0352c371e743d8dae996123f658b5d32c677614eYassir Elley /* the mail isn't remote yet. we were just trying to copy a
0352c371e743d8dae996123f658b5d32c677614eYassir Elley local mail to avoid downloading the remote mail. */
a801d42c4637bbdf9664d0d8b913ffcab81b904eLukas Slebodnik if (dsync_mail_fill_nonminimal(mail->input_mail, &mail2,
802909e59daa52c734dbe7f8fa13b0ee23e3e576Lukas Slebodnik i_error("Mailbox %s: Failed to read mail %s uid=%u: %s",
63b8e826f62d2e8930c872de7d4cc8b5bc15d4a4Sumit Bose dsync_mailbox_save_set_nonminimal(save_ctx, &mail2);
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek /* it was just expunged in remote, skip it */
72ae534f5aef6d2e5d3f2f51299aede5abf9687eJakub Hrozek if (mailbox_save_begin(&save_ctx, input) < 0) {
51b5e1475b3e0b7acac34ed382cfaca8411883a4Jakub Hrozek while ((ret = i_stream_read(input)) > 0 || ret == -2) {
90afedb00608547ae1f32aa7aafd552c4b306909Jakub Hrozek i_error("Mailbox %s: read(msg input) failed: %s",
e592d5f157be869151983bd1b46d6f4f7a29daafJakub Hrozek dsync_mailbox_import_saved_newmail(importer, newmail);
e592d5f157be869151983bd1b46d6f4f7a29daafJakub Hrozekstatic bool dsync_mailbox_save_newmails(struct dsync_mailbox_importer *importer,
e592d5f157be869151983bd1b46d6f4f7a29daafJakub Hrozek struct importer_new_mail *newmail, *all_newmails_forcopy;
e592d5f157be869151983bd1b46d6f4f7a29daafJakub Hrozek /* if all_newmails list is large, avoid scanning through the
e592d5f157be869151983bd1b46d6f4f7a29daafJakub Hrozek uninteresting ones for each newmail */
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek /* save all instances of the message */
2dcf7b9b65df21f2aee6cdf051a7fbdef6dfe034Jakub Hrozek for (newmail = all_newmails; newmail != NULL && ret; newmail = newmail->next) {
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozek if (!dsync_mailbox_save_body(importer, mail, newmail,
f92ace4a52602e8c38a34f2392bec3deeac2ddddJakub Hrozekint dsync_mailbox_import_mail(struct dsync_mailbox_importer *importer,
f43c6a9ae2aea13b7a83fd932139f9352efbfcadPavel Březina i_assert(mail->input == NULL || mail->input->seekable);
f43c6a9ae2aea13b7a83fd932139f9352efbfcadPavel Březina imp_debug(importer, "Import mail body for GUID=%s UID=%u",
f43c6a9ae2aea13b7a83fd932139f9352efbfcadPavel Březina hash_table_lookup(importer->import_guids, mail->guid) :
f43c6a9ae2aea13b7a83fd932139f9352efbfcadPavel Březina hash_table_lookup(importer->import_uids, POINTER_CAST(mail->uid));
f43c6a9ae2aea13b7a83fd932139f9352efbfcadPavel Březina i_error("Mailbox %s: Remote sent unwanted message body for "
efa6c1f75c4c18bcc148d6e7efd429c2d56499adPavel Březina "GUID=%s UID=%u",
150b76e13b7c4f3ccf1d709bf517ca2af6b2c9a2Jakub Hrozek imp_debug(importer, "Skip unwanted mail body for "
6ea6662287147308b81b9c9f2f1f3c992d01bc50Jakub Hrozek hash_table_remove(importer->import_guids, mail->guid);
6ea6662287147308b81b9c9f2f1f3c992d01bc50Jakub Hrozek if (!dsync_mailbox_save_newmails(importer, mail, all_newmails, TRUE))
d36f4db9bb5efc63b94190cca25adb08ee56971cJakub Hrozekreassign_uids_in_seq_range(struct dsync_mailbox_importer *importer,
d36f4db9bb5efc63b94190cca25adb08ee56971cJakub Hrozek const enum mailbox_transaction_flags trans_flags =
d36f4db9bb5efc63b94190cca25adb08ee56971cJakub Hrozek unsigned int renumber_count = 0;
526a15438525417cd701f837d7085b7f8c8a6325Jakub Hrozek imp_debug(importer, "Reassign UIDs: %s", str_c(str));
526a15438525417cd701f837d7085b7f8c8a6325Jakub Hrozek arg = mail_search_build_add(search_args, SEARCH_UIDSET);
526a15438525417cd701f837d7085b7f8c8a6325Jakub Hrozek p_array_init(&arg->value.seqset, search_args->pool,
27a7dedb0ee4d4b51ca4c196aa894ad30cb3e821Petr Cech array_append_array(&arg->value.seqset, unwanted_uids);
27a7dedb0ee4d4b51ca4c196aa894ad30cb3e821Petr Cech trans = mailbox_transaction_begin(box, trans_flags);
27a7dedb0ee4d4b51ca4c196aa894ad30cb3e821Petr Cech search_ctx = mailbox_search_init(trans, search_args, NULL, 0, NULL);
27a7dedb0ee4d4b51ca4c196aa894ad30cb3e821Petr Cech i_error("Mailbox %s: Couldn't move mail within mailbox: %s",
27a7dedb0ee4d4b51ca4c196aa894ad30cb3e821Petr Cech mailbox_get_last_internal_error(box, &importer->mail_error));
27a7dedb0ee4d4b51ca4c196aa894ad30cb3e821Petr Cech } else if (ret > 0) {
1d93029624d708119bbf803e6647a2cbb271f001Sumit Bose mailbox_get_last_internal_error(box, &importer->mail_error));
1d93029624d708119bbf803e6647a2cbb271f001Sumit Bose i_error("Mailbox %s: UID reassign commit failed: %s",
1d93029624d708119bbf803e6647a2cbb271f001Sumit Bose mailbox_get_last_internal_error(box, &importer->mail_error));
3b99f7a97553a0a357d50abe507d4f0060c4eceaPavel Březina imp_debug(importer, "Mailbox %s: Change during sync: "
a5623363d6042290fe652a1ca5ce5a85a821236fPavel Březina "Renumbered %u of %u unwanted UIDs",
a5623363d6042290fe652a1ca5ce5a85a821236fPavel Březinareassign_unwanted_uids(struct dsync_mailbox_importer *importer,
802385896dc1c4e7b8bbd40dcfe3cd131f68e696Sumit Bose wanted_uids = array_get(&importer->wanted_uids, &wanted_count);
802385896dc1c4e7b8bbd40dcfe3cd131f68e696Sumit Bose saved_uids = array_get(&importer->saved_uids, &saved_count);
802385896dc1c4e7b8bbd40dcfe3cd131f68e696Sumit Bose /* wanted_uids contains the UIDs we tried to save mails with.
802385896dc1c4e7b8bbd40dcfe3cd131f68e696Sumit Bose if nothing changed during dsync, we should have the expected UIDs
802385896dc1c4e7b8bbd40dcfe3cd131f68e696Sumit Bose (saved_uids) and all is well.
802385896dc1c4e7b8bbd40dcfe3cd131f68e696Sumit Bose if any new messages got inserted during dsync, we'll need to fix up
802385896dc1c4e7b8bbd40dcfe3cd131f68e696Sumit Bose the UIDs and let the next dsync fix up the other side. for example:
a0ab15ceb80290db80c2052520830a95390de385Sumit Bose remote uids = 5,7,9 = wanted_uids
b1a822a16e3ef97e31d167f9e97efec06fc121dcJakub Hrozek remote uidnext = 12
a0ab15ceb80290db80c2052520830a95390de385Sumit Bose locally added new uid=5 ->
a0ab15ceb80290db80c2052520830a95390de385Sumit Bose saved_uids = 10,7,9
a0ab15ceb80290db80c2052520830a95390de385Sumit Bose we'll now need to reassign UIDs 5 and 10. to be fully future-proof
a0ab15ceb80290db80c2052520830a95390de385Sumit Bose we'll reassign all UIDs between [original local uidnext .. highest
a0ab15ceb80290db80c2052520830a95390de385Sumit Bose UID we think we know] that aren't in saved_uids. */
a0ab15ceb80290db80c2052520830a95390de385Sumit Bose /* create uidset for the list of UIDs we don't want to exist */
a0ab15ceb80290db80c2052520830a95390de385Sumit Bose highest_seen_uid = I_MAX(importer->remote_uid_next-1,
a0ab15ceb80290db80c2052520830a95390de385Sumit Bose i_assert(importer->local_uid_next <= highest_seen_uid);
a0ab15ceb80290db80c2052520830a95390de385Sumit Bose for (i = 0; i < wanted_count; i++) {
fb3c5cdfcda069a5fbeb7b9d200c0881911364b8Jakub Hrozek seq_range_array_remove(&unwanted_uids, saved_uids[i]);
e00c2b5ac4963de9521599c88597b7fb97339d0eJakub Hrozek ret = reassign_uids_in_seq_range(importer, &unwanted_uids);
e00c2b5ac4963de9521599c88597b7fb97339d0eJakub Hrozek "%u UIDs changed due to UID conflicts",
e00c2b5ac4963de9521599c88597b7fb97339d0eJakub Hrozek /* conflicting changes during sync, revert our last-common-uid
4d9db278db1197ae84fecb8f269e2de368a6be2aLukas Slebodnik back to a safe value. */
4d9db278db1197ae84fecb8f269e2de368a6be2aLukas Slebodnik importer->last_common_uid = importer->local_uid_next - 1;
e00c2b5ac4963de9521599c88597b7fb97339d0eJakub Hrozekdsync_mailbox_import_commit(struct dsync_mailbox_importer *importer, bool final)
e00c2b5ac4963de9521599c88597b7fb97339d0eJakub Hrozek struct mail_transaction_commit_changes changes;
44703b84feaafa4f0a4f8df11c5a503dcf48616eJakub Hrozek unsigned int n;
4d9db278db1197ae84fecb8f269e2de368a6be2aLukas Slebodnik /* commit saves */
e00c2b5ac4963de9521599c88597b7fb97339d0eJakub Hrozek if (mailbox_transaction_commit_get_changes(&importer->ext_trans,
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina mailbox_get_last_internal_error(importer->box, &importer->mail_error));
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina /* removed wanted_uids that weren't actually saved */
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina mailbox_transaction_rollback(&importer->trans);
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina /* remember the UIDs that were successfully saved */
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina imap_write_seq_range(str, &changes.saved_uids);
e5911e72198df96ec7cfe486ff66363c2297a5f7Simo Sorce imp_debug(importer, "Saved UIDs: %s", str_c(str));
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina seq_range_array_iter_init(&iter, &changes.saved_uids); n = 0;
360a4be4266d6a72be99dfd252623dc0527f5b84Pavel Březina while (seq_range_array_iter_nth(&iter, n++, &uid))
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina /* commit flag changes and expunges */
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina if (mailbox_transaction_commit(&importer->trans) < 0) {
3a8f6b575f4019f21c9425a26f1b346c08a197aePavel Březina mailbox_get_last_internal_error(importer->box,
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek dsync_mailbox_import_transaction_begin(importer);
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozekstatic int dsync_mailbox_import_finish(struct dsync_mailbox_importer *importer,
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek ret = dsync_mailbox_import_commit(importer, TRUE);
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek /* update mailbox metadata if we successfully saved
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek everything. */
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek update.min_next_uid = importer->remote_uid_next;
bf54fbed126ec3d459af40ea370ffadacd31c76dJakub Hrozek update.min_highest_modseq = importer->remote_highest_modseq;
8df69bbc58c2f4d3f0b34be9756d9ddf24b1db6dJakub Hrozek update.min_highest_pvt_modseq = importer->remote_highest_pvt_modseq;
8df69bbc58c2f4d3f0b34be9756d9ddf24b1db6dJakub Hrozek imp_debug(importer, "Finish update: min_next_uid=%u "
8df69bbc58c2f4d3f0b34be9756d9ddf24b1db6dJakub Hrozek "min_first_recent_uid=%u min_highest_modseq=%llu "
8df69bbc58c2f4d3f0b34be9756d9ddf24b1db6dJakub Hrozek "min_highest_pvt_modseq=%llu",
8df69bbc58c2f4d3f0b34be9756d9ddf24b1db6dJakub Hrozek update.min_next_uid, update.min_first_recent_uid,
8df69bbc58c2f4d3f0b34be9756d9ddf24b1db6dJakub Hrozek (unsigned long long)update.min_highest_pvt_modseq);
8df69bbc58c2f4d3f0b34be9756d9ddf24b1db6dJakub Hrozek if (mailbox_update(importer->box, &update) < 0) {
89ddc9ed474e9ac2b1e7bccb0a58610babf26cf8Jakub Hrozek /* sync mailbox to finish flag changes and expunges. */
89ddc9ed474e9ac2b1e7bccb0a58610babf26cf8Jakub Hrozek /* give new UIDs to messages that got saved with unwanted UIDs.
89ddc9ed474e9ac2b1e7bccb0a58610babf26cf8Jakub Hrozek do it only if the whole transaction succeeded. */
89ddc9ed474e9ac2b1e7bccb0a58610babf26cf8Jakub Hrozek if (reassign_unwanted_uids(importer, changes_during_sync_r) < 0)
f4025ea817b3467be1c2e6092014a11fe4547c0dJakub Hrozekdsync_mailbox_import_check_missing_guid_imports(struct dsync_mailbox_importer *importer)
f4025ea817b3467be1c2e6092014a11fe4547c0dJakub Hrozek const char *key;
676bf6dda60776d9db79dad1c2506c0e57bb5503Pavel Březina iter = hash_table_iterate_init(importer->import_guids);
f4025ea817b3467be1c2e6092014a11fe4547c0dJakub Hrozek while (hash_table_iterate(iter, importer->import_guids, &key, &mail)) {
f4025ea817b3467be1c2e6092014a11fe4547c0dJakub Hrozek i_error("Mailbox %s: Remote didn't send mail GUID=%s (UID=%u)",
f4025ea817b3467be1c2e6092014a11fe4547c0dJakub Hrozekdsync_mailbox_import_check_missing_uid_imports(struct dsync_mailbox_importer *importer)
f4025ea817b3467be1c2e6092014a11fe4547c0dJakub Hrozek iter = hash_table_iterate_init(importer->import_uids);
f4025ea817b3467be1c2e6092014a11fe4547c0dJakub Hrozek while (hash_table_iterate(iter, importer->import_uids, &key, &mail)) {
b590f44c06158485357d69cc5b24d5af05f1bb95Petr Cech i_error("Mailbox %s: Remote didn't send mail UID=%u",
b590f44c06158485357d69cc5b24d5af05f1bb95Petr Cechint dsync_mailbox_import_deinit(struct dsync_mailbox_importer **_importer,
01ec08efd0e166ac6f390f8627c6d08dcc63ccc4Jakub Hrozek struct dsync_mailbox_importer *importer = *_importer;
01ec08efd0e166ac6f390f8627c6d08dcc63ccc4Jakub Hrozek *require_full_resync_r = importer->require_full_resync;
bf01e8179cbb2be476805340636098deda7e1366Sumit Bose if ((!success || importer->require_full_resync) && !importer->failed) {
bf01e8179cbb2be476805340636098deda7e1366Sumit Bose if (!importer->new_uids_assigned && !importer->failed)
bf01e8179cbb2be476805340636098deda7e1366Sumit Bose dsync_mailbox_import_check_missing_guid_imports(importer);
bf01e8179cbb2be476805340636098deda7e1366Sumit Bose dsync_mailbox_import_check_missing_uid_imports(importer);
bf01e8179cbb2be476805340636098deda7e1366Sumit Bose if (mailbox_search_deinit(&importer->search_ctx) < 0) {
99c5f2f6ba0af6ce52be0d82ec2794bacc215742Jakub Hrozek if (dsync_mailbox_import_finish(importer, changes_during_sync_r) < 0)
99c5f2f6ba0af6ce52be0d82ec2794bacc215742Jakub Hrozek (void)mailbox_transaction_commit(&importer->virtual_trans);
71493344f59002272c2cc069daa3b6147e9cb0c3Lukas Slebodnik if (array_is_created(&importer->mail_requests))
b9d83e10cec267ae11fee64a30f42a12bbf7abe4Pavel Březina *last_common_uid_r = importer->last_common_uid;
b9d83e10cec267ae11fee64a30f42a12bbf7abe4Pavel Březina *last_common_modseq_r = importer->remote_highest_modseq;
b9d83e10cec267ae11fee64a30f42a12bbf7abe4Pavel Březina *last_common_pvt_modseq_r = importer->remote_highest_pvt_modseq;
b9d83e10cec267ae11fee64a30f42a12bbf7abe4Pavel Březina /* local changes occurred during dsync. we exported changes up
b9d83e10cec267ae11fee64a30f42a12bbf7abe4Pavel Březina to local_initial_highestmodseq, so all of the changes have
b9d83e10cec267ae11fee64a30f42a12bbf7abe4Pavel Březina happened after it. we want the next run to see those changes,
b9d83e10cec267ae11fee64a30f42a12bbf7abe4Pavel Březina so return it as the last common modseq */
b9d83e10cec267ae11fee64a30f42a12bbf7abe4Pavel Březina *last_common_modseq_r = importer->local_initial_highestmodseq;
b9d83e10cec267ae11fee64a30f42a12bbf7abe4Pavel Březina *last_common_pvt_modseq_r = importer->local_initial_highestpvtmodseq;
b9d83e10cec267ae11fee64a30f42a12bbf7abe4Pavel Březina mailbox_get_last_internal_error(importer->box,
49c467733ca65c9b77b9c33f38cdc223a99562e1Pavel Reichl mailbox_get_open_status(importer->box, STATUS_MESSAGES, &status);
49c467733ca65c9b77b9c33f38cdc223a99562e1Pavel Reichl i_assert(importer->failed == (importer->mail_error != 0));
49c467733ca65c9b77b9c33f38cdc223a99562e1Pavel Reichlconst char *dsync_mailbox_import_get_proctitle(struct dsync_mailbox_importer *importer)