maildir-sync-index.c revision f23ede27743c1aa03eacbfc634d6a10de9110c91
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (C) 2007 Timo Sirainen */
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen struct maildir_sync_context *maildir_sync_ctx;
72f5f2c5c6905b5d3f389b424313e2c450dfad96Timo Sirainen struct maildir_keywords_sync_ctx *keywords_sync_ctx;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen struct maildir_uidlist_sync_ctx *uidlist_sync_ctx;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen struct index_sync_changes_context *sync_changes;
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainenmaildir_sync_get_keywords_sync_ctx(struct maildir_index_sync_context *ctx)
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainenstatic int maildir_expunge(struct maildir_mailbox *mbox, const char *path,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen mail_storage_set_critical(&mbox->storage->storage,
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainenstatic int maildir_sync_flags(struct maildir_mailbox *mbox, const char *path,
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen /* get the current flags and keywords */
9f0f2de10e4ea0c99052bf4b2bef8179f2536228Timo Sirainen maildir_filename_get_flags(ctx->keywords_sync_ctx,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen /* apply changes */
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen index_sync_changes_apply(ctx->sync_changes, NULL,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen /* and try renaming with the new name */
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen newfname = maildir_filename_set_flags(ctx->keywords_sync_ctx, fname,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstatic void maildir_handle_uid_insertion(struct maildir_index_sync_context *ctx,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen if ((uflags & MAILDIR_UIDLIST_REC_FLAG_NONSYNCED) != 0) {
380dbb60ae291cbe39d1f710284562ca9167150bTimo Sirainen /* partial syncing */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* most likely a race condition: we read the maildir, then someone else
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen expunged messages and committed changes to index. so, this message
1b823b2b7790a1e1b7974fcf11a4c48a28e70f37Timo Sirainen shouldn't actually exist. */
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen if ((uflags & MAILDIR_UIDLIST_REC_FLAG_RACING) == 0) {
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen /* mark it racy and check in next sync */
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen maildir_uidlist_add_flags(ctx->mbox->uidlist, filename,
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen ret = maildir_uidlist_sync_init(ctx->mbox->uidlist,
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen maildir_uidlist_sync_remove(ctx->uidlist_sync_ctx, filename);
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen ret = maildir_uidlist_sync_next(ctx->uidlist_sync_ctx,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* give the new UID to it immediately */
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen maildir_uidlist_sync_finish(ctx->uidlist_sync_ctx);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_warning("Maildir %s: Expunged message reappeared, giving a new UID "
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen "(old uid=%u, file=%s)", ctx->mbox->path, uid, filename);
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainenint maildir_sync_index_begin(struct maildir_mailbox *mbox,
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen struct maildir_sync_context *maildir_sync_ctx,
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen /* don't drop recent messages if we're saving messages */
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen if (!mbox->ibox.keep_recent && maildir_sync_ctx != NULL)
7744586e3e0fd60158abfbb03a233d3bd8d6c48bTimo Sirainen sync_flags |= MAIL_INDEX_SYNC_FLAG_DROP_RECENT;
1b823b2b7790a1e1b7974fcf11a4c48a28e70f37Timo Sirainen if (mail_index_sync_begin(mbox->ibox.index, &sync_ctx, &view, &trans,
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen ctx = i_new(struct maildir_index_sync_context, 1);
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen maildir_keywords_sync_init(mbox->keywords, mbox->ibox.index);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen ctx->sync_changes = index_sync_changes_init(&mbox->ibox, ctx->sync_ctx,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenint maildir_sync_index_finish(struct maildir_index_sync_context **_ctx,
61618d4c58080570f689614fec204ae14e90cef2Timo Sirainen struct maildir_index_sync_context *ctx = *_ctx;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen /* Set syncing_commit=TRUE so that if any sync callbacks try
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen to access mails which got lost (eg. expunge callback trying
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen to open the file which was just unlinked) we don't try to
50e20db49f29917fe9adcf1b56b11badf28bd0e4Timo Sirainen start a second index sync and crash. */
a7f5035eebbd138a5436a2eb2ce1fa5fd3d269fbTimo Sirainen if (mail_index_sync_commit(&ctx->sync_ctx) < 0) {
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen maildir_keywords_sync_deinit(ctx->keywords_sync_ctx);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen index_sync_changes_deinit(&ctx->sync_changes);
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenmaildir_index_update_ext_header(struct maildir_mailbox *mbox,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen if (mail_index_get_header_ext(mbox->ibox.view, mbox->maildir_ext_id,
062ea54b7775d0c92ed67b9b1f4d93fa8ec80c84Timo Sirainen memcmp(data, &mbox->maildir_hdr, data_size) == 0) {
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen /* nothing changed */
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen mail_index_update_header_ext(trans, mbox->maildir_ext_id, 0,
a7f5035eebbd138a5436a2eb2ce1fa5fd3d269fbTimo Sirainenint maildir_sync_index(struct maildir_index_sync_context *ctx,
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen struct mail_index_transaction *trans = ctx->trans;
401b0787fff2dc986a5321ddb32acb1947ff66b0Timo Sirainen uint32_t uid_validity, next_uid, hdr_next_uid, last_nonrecent_uid;
1da01eaa962be13cee75771064e2256b1a82d90aTimo Sirainen unsigned int changes = 0;
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen i_assert(maildir_uidlist_is_locked(mbox->uidlist));
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen uid_validity = maildir_uidlist_get_uid_validity(mbox->uidlist);
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen uid_validity != 0 && hdr->uid_validity != 0) {
383d0e8c24451468d6bea17e4b55d74de744abe6Timo Sirainen /* uidvalidity changed and index isn't being synced for the
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen first time, reset the index so we can add all messages as
7bafda1813454621e03615e83d55bccfa7cc56bdTimo Sirainen i_warning("Maildir %s: UIDVALIDITY changed (%u -> %u)",
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen maildir_uidlist_set_next_uid(mbox->uidlist, 1, TRUE);
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen t_array_init(&ctx->keywords, MAILDIR_MAX_KEYWORDS);
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen t_array_init(&idx_keywords, MAILDIR_MAX_KEYWORDS);
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen iter = maildir_uidlist_iter_init(mbox->uidlist);
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen while (maildir_uidlist_iter_next(iter, &uid, &uflags, &filename)) {
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen maildir_filename_get_flags(ctx->keywords_sync_ctx, filename,
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen /* the private flags are kept only in indexes. don't use them
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen at all even for newly seen mails */
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen ctx->flags &= ~mbox->ibox.box.private_flags_mask;
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen if ((uflags & MAILDIR_UIDLIST_REC_FLAG_RECENT) == 0 &&
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen (uflags & MAILDIR_UIDLIST_REC_FLAG_NONSYNCED) == 0)
738cfeb96c4b9cd92aa3c791d77734c2745cdd1aTimo Sirainen recent = (uflags & MAILDIR_UIDLIST_REC_FLAG_RECENT) != 0 &&
f93c833d644ecff0b0f80bee4f1cdde3e697b5c8Timo Sirainen mail_index_update_flags(trans, seq, MODIFY_REPLACE,
4fc74bba3548987b7e8597491cd9fafc1f701be6Timo Sirainen index_mailbox_set_recent_uid(&mbox->ibox, uid);
7289c5600711b45f30fe289ab5b0293b51d87041Timo Sirainen /* expunged */
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen if (index_sync_changes_read(ctx->sync_changes, rec->uid,
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen /* successful expunge */
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen if ((++changes % MAILDIR_SLOW_MOVE_COUNT) == 0)
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen index_mailbox_set_recent_uid(&mbox->ibox, uid);
272aca0a772140d3a45a425a3fd67854ae2ccec2Timo Sirainen /* the private flags are stored only in indexes, keep them */
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen ctx->flags |= rec->flags & mbox->ibox.box.private_flags_mask;
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen if ((uflags & MAILDIR_UIDLIST_REC_FLAG_NONSYNCED) != 0) {
9dd1c256910f1fb42823116a641e7edb3ad11970Timo Sirainen /* partial syncing */
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen if ((uflags & MAILDIR_UIDLIST_REC_FLAG_NEW_DIR) != 0) {
d477acb83e14a776ece4ca94dcd1869e75d0c6eeTimo Sirainen /* we last saw this mail in new/, but it's
1d22eaac93de41319918a1fc6de42bb302e25c1aTimo Sirainen not there anymore. possibly expunged,
1d22eaac93de41319918a1fc6de42bb302e25c1aTimo Sirainen make sure. */
2024157e8de36edd31f5fd72f5ea7364a0955fa7Timo Sirainen if (index_sync_changes_have(ctx->sync_changes)) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* apply flag changes to maildir */
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen if ((++changes % MAILDIR_SLOW_MOVE_COUNT) == 0)
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen if ((rec->flags & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0) {
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen /* we haven't been able to update maildir with this
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen record's flag changes. don't sync them. */
b215a8a123623782554a83f3025ef4e771bd8f01Timo Sirainen if (ctx->flags != (rec->flags & MAIL_FLAGS_NONRECENT)) {
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen mail_index_update_flags(trans, seq, MODIFY_REPLACE,
5d60e31c7b701b606067a20bc88dcc8a6de7bbd6Timo Sirainen /* update keywords if they have changed */
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen if (mail_index_lookup_keywords(view, seq, &idx_keywords) < 0) {
if (!partial) {
if (uid_validity == 0) {