maildir-sync-index.c revision 389e0ad41d4dd6acf50f855ecd5f0651082c9f31
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* Copyright (c) 2007-2008 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "ioloop.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "array.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "maildir-storage.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "index-sync-changes.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "maildir-uidlist.h"
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen#include "maildir-keywords.h"
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen#include "maildir-filename.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "maildir-sync.h"
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen#include <stdio.h>
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen#include <unistd.h>
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainenstruct maildir_index_sync_context {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen struct maildir_mailbox *mbox;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen struct maildir_sync_context *maildir_sync_ctx;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen struct mail_index_view *view;
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen struct mail_index_sync_ctx *sync_ctx;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen struct maildir_keywords_sync_ctx *keywords_sync_ctx;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen struct mail_index_transaction *trans;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct maildir_uidlist_sync_ctx *uidlist_sync_ctx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct index_sync_changes_context *sync_changes;
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen enum mail_flags flags;
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen ARRAY_TYPE(keyword_indexes) keywords;
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen uint32_t seq, uid;
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen bool changed;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen};
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainenstruct maildir_keywords_sync_ctx *
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenmaildir_sync_get_keywords_sync_ctx(struct maildir_index_sync_context *ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return ctx->keywords_sync_ctx;
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen}
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int maildir_expunge(struct maildir_mailbox *mbox, const char *path,
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen struct maildir_index_sync_context *ctx)
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen{
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen struct mailbox *box = &mbox->ibox.box;
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (unlink(path) == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (box->v.sync_notify != NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen box->v.sync_notify(box, ctx->uid,
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen MAILBOX_SYNC_TYPE_EXPUNGE);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainen mail_index_expunge(ctx->trans, ctx->seq);
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainen ctx->changed = TRUE;
ea546eaab672d441e180b7619d4750be813c08d8Timo Sirainen return 1;
ea546eaab672d441e180b7619d4750be813c08d8Timo Sirainen }
ea546eaab672d441e180b7619d4750be813c08d8Timo Sirainen if (errno == ENOENT)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "unlink(%s) failed: %m", path);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int maildir_sync_flags(struct maildir_mailbox *mbox, const char *path,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct maildir_index_sync_context *ctx)
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen{
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainen struct mailbox *box = &mbox->ibox.box;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen const char *dir, *fname, *newfname, *newpath;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen enum mail_index_sync_type sync_type;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen uint8_t flags8;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
5c1a8aee989af87bddefd71e2aa83aa2bd695155Timo Sirainen fname = strrchr(path, '/');
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainen i_assert(fname != NULL);
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainen fname++;
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainen dir = t_strdup_until(path, fname);
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainen
0add8c99ca65e56dbf613595fc37c41aafff3f7fTimo Sirainen /* get the current flags and keywords */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen maildir_filename_get_flags(ctx->keywords_sync_ctx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen fname, &ctx->flags, &ctx->keywords);
ec1e30ecc38f0deddaf655413cf02d5972ddbc70Timo Sirainen
ec1e30ecc38f0deddaf655413cf02d5972ddbc70Timo Sirainen /* apply changes */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen flags8 = ctx->flags;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen index_sync_changes_apply(ctx->sync_changes, NULL,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen &flags8, &ctx->keywords, &sync_type);
f99575e1d6cd251bd7b6d0654bd75b475e6a894cTimo Sirainen ctx->flags = flags8;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen /* and try renaming with the new name */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen newfname = maildir_filename_set_flags(ctx->keywords_sync_ctx, fname,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->flags, &ctx->keywords);
eaa36e8058dd6ca4f729f4d0667f8be9912ab473Timo Sirainen newpath = t_strconcat(dir, newfname, NULL);
eaa36e8058dd6ca4f729f4d0667f8be9912ab473Timo Sirainen if (rename(path, newpath) == 0) {
eaa36e8058dd6ca4f729f4d0667f8be9912ab473Timo Sirainen if (box->v.sync_notify != NULL) {
eaa36e8058dd6ca4f729f4d0667f8be9912ab473Timo Sirainen box->v.sync_notify(box, ctx->uid,
eaa36e8058dd6ca4f729f4d0667f8be9912ab473Timo Sirainen index_sync_type_convert(sync_type));
f99575e1d6cd251bd7b6d0654bd75b475e6a894cTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->changed = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (errno == ENOENT)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!ENOSPACE(errno) && errno != EACCES) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_storage_set_critical(box->storage,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "rename(%s, %s) failed: %m", path, newpath);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainen
93b29720c5141f787bd1861796867e4595c9d084Timo Sirainenstatic void maildir_handle_uid_insertion(struct maildir_index_sync_context *ctx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen enum maildir_uidlist_rec_flag uflags,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *filename, uint32_t uid)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int ret;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((uflags & MAILDIR_UIDLIST_REC_FLAG_NONSYNCED) != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* partial syncing */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* most likely a race condition: we read the maildir, then someone else
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen expunged messages and committed changes to index. so, this message
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen shouldn't actually exist. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((uflags & MAILDIR_UIDLIST_REC_FLAG_RACING) == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* mark it racy and check in next sync */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->mbox->maildir_hdr.cur_check_time = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen maildir_uidlist_add_flags(ctx->mbox->uidlist, filename,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen MAILDIR_UIDLIST_REC_FLAG_RACING);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen if (ctx->uidlist_sync_ctx == NULL) {
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen ret = maildir_uidlist_sync_init(ctx->mbox->uidlist,
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen MAILDIR_UIDLIST_SYNC_PARTIAL |
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen MAILDIR_UIDLIST_SYNC_KEEP_STATE,
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen &ctx->uidlist_sync_ctx);
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen i_assert(ret > 0);
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen }
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen uflags &= MAILDIR_UIDLIST_REC_FLAG_NEW_DIR;
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen maildir_uidlist_sync_remove(ctx->uidlist_sync_ctx, filename);
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen ret = maildir_uidlist_sync_next(ctx->uidlist_sync_ctx,
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen filename, uflags);
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen i_assert(ret > 0);
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen /* give the new UID to it immediately */
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen maildir_uidlist_sync_finish(ctx->uidlist_sync_ctx);
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen i_warning("Maildir %s: Expunged message reappeared, giving a new UID "
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen "(old uid=%u, file=%s)", ctx->mbox->path, uid, filename);
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen}
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainenint maildir_sync_index_begin(struct maildir_mailbox *mbox,
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen struct maildir_sync_context *maildir_sync_ctx,
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen struct maildir_index_sync_context **ctx_r)
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen{
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen struct maildir_index_sync_context *ctx;
bef8712387812fc5d9496b9958935c6d0c418777Timo Sirainen struct mail_index_sync_ctx *sync_ctx;
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen struct mail_index_view *view;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen struct mail_index_transaction *trans;
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen enum mail_index_sync_flags sync_flags;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen sync_flags = 0;
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen /* don't drop recent messages if we're saving messages */
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen if (!mbox->ibox.keep_recent && maildir_sync_ctx != NULL)
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen sync_flags |= MAIL_INDEX_SYNC_FLAG_DROP_RECENT;
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen
4c8b1c4aa0582c6ca43a4d1cbd210741e7fff952Timo Sirainen if (mail_index_sync_begin(mbox->ibox.index, &sync_ctx, &view, &trans,
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen sync_flags) < 0) {
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen mail_storage_set_index_error(&mbox->ibox);
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen return -1;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen }
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen ctx = i_new(struct maildir_index_sync_context, 1);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen ctx->mbox = mbox;
b20fb5b1df9d604a7541f5118fc5b4b466d211efTimo Sirainen ctx->maildir_sync_ctx = maildir_sync_ctx;
b20fb5b1df9d604a7541f5118fc5b4b466d211efTimo Sirainen ctx->sync_ctx = sync_ctx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->view = view;
b20fb5b1df9d604a7541f5118fc5b4b466d211efTimo Sirainen ctx->trans = trans;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->keywords_sync_ctx =
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen maildir_keywords_sync_init(mbox->keywords, mbox->ibox.index);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen ctx->sync_changes = index_sync_changes_init(&mbox->ibox, ctx->sync_ctx,
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen ctx->view, ctx->trans,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mbox->ibox.readonly);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen *ctx_r = ctx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 0;
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
f99575e1d6cd251bd7b6d0654bd75b475e6a894cTimo Sirainenint maildir_sync_index_finish(struct maildir_index_sync_context **_ctx,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen bool failed, bool cancel)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen struct maildir_index_sync_context *ctx = *_ctx;
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen struct maildir_mailbox *mbox = ctx->mbox;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int ret = failed ? -1 : 0;
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen *_ctx = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen if (ret < 0 || cancel)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_sync_rollback(&ctx->sync_ctx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else {
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen /* Set syncing_commit=TRUE so that if any sync callbacks try
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen to access mails which got lost (eg. expunge callback trying
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen to open the file which was just unlinked) we don't try to
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen start a second index sync and crash. */
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen mbox->syncing_commit = TRUE;
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen if (mail_index_sync_commit(&ctx->sync_ctx) < 0) {
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen mail_storage_set_index_error(&mbox->ibox);
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen ret = -1;
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen } else {
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen mbox->ibox.commit_log_file_seq = 0;
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen mbox->ibox.commit_log_file_offset = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mbox->syncing_commit = FALSE;
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen }
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen maildir_keywords_sync_deinit(&ctx->keywords_sync_ctx);
5529671faac3c5672a948be93091056736c7afffTimo Sirainen index_sync_changes_deinit(&ctx->sync_changes);
5529671faac3c5672a948be93091056736c7afffTimo Sirainen i_free(ctx);
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen return ret;
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen}
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainenstatic bool
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainenmaildir_index_header_has_changed(const struct maildir_index_header *old_hdr,
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen const struct maildir_index_header *new_hdr)
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#define DIR_DELAYED_REFRESH(hdr, name) \
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen ((hdr)->name ## _check_time <= \
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (hdr)->name ## _mtime + MAILDIR_SYNC_SECS)
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen if (old_hdr->new_mtime != new_hdr->new_mtime ||
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen old_hdr->cur_mtime != new_hdr->cur_mtime ||
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen old_hdr->new_mtime_nsecs != new_hdr->new_mtime_nsecs ||
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen old_hdr->cur_mtime_nsecs != new_hdr->cur_mtime_nsecs)
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen return TRUE;
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen return DIR_DELAYED_REFRESH(old_hdr, new) !=
8afec4d1a32b78f540257a27769b372aad753384Timo Sirainen DIR_DELAYED_REFRESH(new_hdr, new) ||
7c5b51bdf43a98e12c654ad437e0b258c5fffbc1Timo Sirainen DIR_DELAYED_REFRESH(old_hdr, cur) !=
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen DIR_DELAYED_REFRESH(new_hdr, cur);
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen}
b5ea11802f2bafbec06282a7b3b6704dc5fae584Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenmaildir_index_update_ext_header(struct maildir_mailbox *mbox,
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen struct mail_index_transaction *trans)
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const void *data;
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen size_t data_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
f99575e1d6cd251bd7b6d0654bd75b475e6a894cTimo Sirainen mail_index_get_header_ext(mbox->ibox.view, mbox->maildir_ext_id,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen &data, &data_size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (data_size != sizeof(mbox->maildir_hdr) ||
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen maildir_index_header_has_changed(data, &mbox->maildir_hdr)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_update_header_ext(trans, mbox->maildir_ext_id, 0,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen &mbox->maildir_hdr,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sizeof(mbox->maildir_hdr));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenint maildir_sync_index(struct maildir_index_sync_context *ctx,
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen bool partial)
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct maildir_mailbox *mbox = ctx->mbox;
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen struct mail_index_view *view = ctx->view;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen struct mail_index_view *view2;
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen struct maildir_uidlist_iter_ctx *iter;
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen struct mail_index_transaction *trans = ctx->trans;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const struct mail_index_header *hdr;
62950eeff28f00989a17b20eeade3af7e200c6bcTimo Sirainen struct mail_index_header empty_hdr;
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen const struct mail_index_record *rec;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uint32_t seq, seq2, uid, prev_uid;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen enum maildir_uidlist_rec_flag uflags;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *filename;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ARRAY_TYPE(keyword_indexes) idx_keywords;
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen uint32_t uid_validity, next_uid, hdr_next_uid, first_recent_uid;
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen unsigned int changes = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int ret = 0;
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen bool expunged, full_rescan = FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(!mbox->syncing_commit);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(maildir_uidlist_is_locked(mbox->uidlist));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen hdr = mail_index_get_header(view);
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen uid_validity = maildir_uidlist_get_uid_validity(mbox->uidlist);
62950eeff28f00989a17b20eeade3af7e200c6bcTimo Sirainen if (uid_validity != hdr->uid_validity &&
62950eeff28f00989a17b20eeade3af7e200c6bcTimo Sirainen uid_validity != 0 && hdr->uid_validity != 0) {
62950eeff28f00989a17b20eeade3af7e200c6bcTimo Sirainen /* uidvalidity changed and index isn't being synced for the
62950eeff28f00989a17b20eeade3af7e200c6bcTimo Sirainen first time, reset the index so we can add all messages as
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen new */
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen i_warning("Maildir %s: UIDVALIDITY changed (%u -> %u)",
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen mbox->path, hdr->uid_validity, uid_validity);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_reset(trans);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen maildir_uidlist_set_next_uid(mbox->uidlist, 1, TRUE);
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen memset(&empty_hdr, 0, sizeof(empty_hdr));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen empty_hdr.next_uid = 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen hdr = &empty_hdr;
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen hdr_next_uid = hdr->next_uid;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mbox->syncing_commit = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen seq = prev_uid = 0; first_recent_uid = hdr->first_recent_uid;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t_array_init(&ctx->keywords, MAILDIR_MAX_KEYWORDS);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t_array_init(&idx_keywords, MAILDIR_MAX_KEYWORDS);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen iter = maildir_uidlist_iter_init(mbox->uidlist);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen while (maildir_uidlist_iter_next(iter, &uid, &uflags, &filename)) {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen maildir_filename_get_flags(ctx->keywords_sync_ctx, filename,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen &ctx->flags, &ctx->keywords);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(uid > prev_uid);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen prev_uid = uid;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* the private flags are kept only in indexes. don't use them
f99575e1d6cd251bd7b6d0654bd75b475e6a894cTimo Sirainen at all even for newly seen mails */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->flags &= ~mbox->ibox.box.private_flags_mask;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen again:
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen ctx->seq = ++seq;
b0a446671b8f09a1d2ed1d8c86a47298309e989dTimo Sirainen ctx->uid = uid;
b0a446671b8f09a1d2ed1d8c86a47298309e989dTimo Sirainen
b0a446671b8f09a1d2ed1d8c86a47298309e989dTimo Sirainen if (seq > hdr->messages_count) {
b0a446671b8f09a1d2ed1d8c86a47298309e989dTimo Sirainen if (uid < hdr_next_uid) {
b0a446671b8f09a1d2ed1d8c86a47298309e989dTimo Sirainen maildir_handle_uid_insertion(ctx, uflags,
b0a446671b8f09a1d2ed1d8c86a47298309e989dTimo Sirainen filename, uid);
b0a446671b8f09a1d2ed1d8c86a47298309e989dTimo Sirainen seq--;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen continue;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen /* Trust uidlist recent flags only for newly added
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen messages. When saving/copying messages with flags
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen they're stored to cur/ and uidlist treats them
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen as non-recent. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((uflags & MAILDIR_UIDLIST_REC_FLAG_RECENT) != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (uid > first_recent_uid)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen first_recent_uid = uid;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (uid >= first_recent_uid)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen first_recent_uid = uid + 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen hdr_next_uid = uid + 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_append(trans, uid, &seq);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_update_flags(trans, seq, MODIFY_REPLACE,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->flags);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen if (array_count(&ctx->keywords) > 0) {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen struct mail_keywords *kw;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen kw = mail_index_keywords_create_from_indexes(
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mbox->ibox.index, &ctx->keywords);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_update_keywords(trans, seq,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen MODIFY_REPLACE, kw);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_keywords_free(&kw);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen continue;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
f99575e1d6cd251bd7b6d0654bd75b475e6a894cTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen rec = mail_index_lookup(view, seq);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (uid > rec->uid) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* expunged */
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen mail_index_expunge(trans, seq);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen goto again;
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen if (uid < rec->uid) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen maildir_handle_uid_insertion(ctx, uflags,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen filename, uid);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen seq--;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen continue;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen index_sync_changes_read(ctx->sync_changes, rec->uid, &expunged);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (expunged) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (maildir_file_do(mbox, ctx->uid,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen maildir_expunge, ctx) >= 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* successful expunge */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_index_expunge(trans, seq);
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen }
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen if ((++changes % MAILDIR_SLOW_MOVE_COUNT) == 0)
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen maildir_sync_notify(ctx->maildir_sync_ctx);
7e94cf9d70ce9fdeccb7a85ff400b899e6386f36Timo Sirainen continue;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* the private flags are stored only in indexes, keep them */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->flags |= rec->flags & mbox->ibox.box.private_flags_mask;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (index_sync_changes_have(ctx->sync_changes)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* apply flag changes to maildir */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (maildir_file_do(mbox, ctx->uid,
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen maildir_sync_flags, ctx) < 0)
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen ctx->flags |= MAIL_INDEX_MAIL_FLAG_DIRTY;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if ((++changes % MAILDIR_SLOW_MOVE_COUNT) == 0)
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen maildir_sync_notify(ctx->maildir_sync_ctx);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen }
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if ((uflags & MAILDIR_UIDLIST_REC_FLAG_NONSYNCED) != 0) {
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen /* partial syncing */
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if ((uflags & MAILDIR_UIDLIST_REC_FLAG_NEW_DIR) != 0) {
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen /* we last saw this mail in new/, but it's
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen not there anymore. possibly expunged,
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen make sure. */
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen full_rescan = TRUE;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen continue;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen }
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if ((rec->flags & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0) {
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen /* we haven't been able to update maildir with this
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen record's flag changes. don't sync them. */
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen continue;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen }
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if (ctx->flags != (rec->flags & MAIL_FLAGS_NONRECENT)) {
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen mail_index_update_flags(trans, seq, MODIFY_REPLACE,
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen ctx->flags);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen /* update keywords if they have changed */
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen mail_index_lookup_keywords(view, seq, &idx_keywords);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (!index_keyword_array_cmp(&ctx->keywords, &idx_keywords)) {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen struct mail_keywords *kw;
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen kw = mail_index_keywords_create_from_indexes(
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen mbox->ibox.index, &ctx->keywords);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen mail_index_update_keywords(trans, seq,
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen MODIFY_REPLACE, kw);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen mail_index_keywords_free(&kw);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen maildir_uidlist_iter_deinit(&iter);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen mbox->syncing_commit = FALSE;
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (!partial) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen /* expunge the rest */
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen for (seq++; seq <= hdr->messages_count; seq++)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen mail_index_expunge(trans, seq);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen }
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen /* add \Recent flags. use updated view so it contains newly
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen appended messages. */
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen view2 = mail_index_transaction_open_updated_view(trans);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (mail_index_lookup_seq_range(view2, first_recent_uid, (uint32_t)-1,
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen &seq, &seq2))
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen index_mailbox_set_recent_seq(&mbox->ibox, view2, seq, seq2);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen mail_index_view_close(&view2);
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen if (ctx->uidlist_sync_ctx != NULL) {
1b3bb8d39686ed24730cbc31cc9a33dc62c8c6c3Timo Sirainen if (maildir_uidlist_sync_deinit(&ctx->uidlist_sync_ctx) < 0)
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen ret = -1;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen }
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen if (mbox->ibox.box.v.sync_notify != NULL)
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen mbox->ibox.box.v.sync_notify(&mbox->ibox.box, 0, 0);
df4018ae2f0a95be602f724ca70df7e0e3bd6a7dTimo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen if (ctx->changed)
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen mbox->maildir_hdr.cur_mtime = time(NULL);
b20fb5b1df9d604a7541f5118fc5b4b466d211efTimo Sirainen maildir_index_update_ext_header(mbox, trans);
b20fb5b1df9d604a7541f5118fc5b4b466d211efTimo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen if (uid_validity == 0) {
b20fb5b1df9d604a7541f5118fc5b4b466d211efTimo Sirainen uid_validity = hdr->uid_validity != 0 ?
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen hdr->uid_validity : (uint32_t)ioloop_time;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen maildir_uidlist_set_uid_validity(mbox->uidlist, uid_validity);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen }
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen maildir_uidlist_set_next_uid(mbox->uidlist, hdr_next_uid, FALSE);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen if (uid_validity != hdr->uid_validity) {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen mail_index_update_header(trans,
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen offsetof(struct mail_index_header, uid_validity),
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen &uid_validity, sizeof(uid_validity), TRUE);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen }
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen next_uid = maildir_uidlist_get_next_uid(mbox->uidlist);
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen if (hdr_next_uid < next_uid) {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen mail_index_update_header(trans,
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen offsetof(struct mail_index_header, next_uid),
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen &next_uid, sizeof(next_uid), FALSE);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen }
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen i_assert(hdr->first_recent_uid <= first_recent_uid);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (hdr->first_recent_uid < first_recent_uid) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen mail_index_update_header(ctx->trans,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen offsetof(struct mail_index_header, first_recent_uid),
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen &first_recent_uid, sizeof(first_recent_uid), FALSE);
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return ret < 0 ? -1 : (full_rescan ? 0 : 1);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen}
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
bb2b91b4c5363348b737237893d414639510a561Timo Sirainenstatic unsigned int maildir_list_get_ext_id(struct maildir_storage *storage,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen struct mail_index_view *view)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen{
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (storage->maildir_list_ext_id == (uint32_t)-1) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen storage->maildir_list_ext_id =
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen mail_index_ext_register(mail_index_view_get_index(view),
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen "maildir", 0,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen sizeof(struct maildir_list_index_record),
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen sizeof(uint32_t));
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen }
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return storage->maildir_list_ext_id;
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen}
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainenint maildir_list_index_has_changed(struct mailbox *box,
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen struct mail_index_view *list_view,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen uint32_t seq)
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen{
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)box;
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen const struct maildir_list_index_record *rec;
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen const void *data;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen const char *root_dir, *new_dir, *cur_dir;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct stat st;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen uint32_t ext_id;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen bool expunged;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen ext_id = maildir_list_get_ext_id(mbox->storage, list_view);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen mail_index_lookup_ext(list_view, seq, ext_id, &data, &expunged);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen rec = data;
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen if (rec == NULL || expunged ||
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen rec->new_mtime == 0 || rec->cur_mtime == 0) {
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen /* doesn't exist, not synced or dirty-synced */
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return 1;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen root_dir = mailbox_list_get_path(mail_storage_get_list(box->storage),
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen box->name,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen MAILBOX_LIST_PATH_TYPE_MAILBOX);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* check if new/ changed */
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen new_dir = t_strconcat(root_dir, "/new", NULL);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if (stat(new_dir, &st) < 0) {
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen mail_storage_set_critical(box->storage,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen "stat(%s) failed: %m", new_dir);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return -1;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if ((time_t)rec->new_mtime != st.st_mtime)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return 1;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen /* check if cur/ changed */
bb2b91b4c5363348b737237893d414639510a561Timo Sirainen cur_dir = t_strconcat(root_dir, "/cur", NULL);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (stat(cur_dir, &st) < 0) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen mail_storage_set_critical(box->storage,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen "stat(%s) failed: %m", cur_dir);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return -1;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen if ((time_t)rec->cur_mtime != st.st_mtime)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return 1;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen return 0;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen}
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenint maildir_list_index_update_sync(struct mailbox *box,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen struct mail_index_transaction *trans,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen uint32_t seq)
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen{
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen struct maildir_mailbox *mbox = (struct maildir_mailbox *)box;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen struct mail_index_view *list_view;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen const struct maildir_index_header *mhdr = &mbox->maildir_hdr;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen const struct maildir_list_index_record *old_rec;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen struct maildir_list_index_record new_rec;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen const void *data;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen uint32_t ext_id;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen bool expunged;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen /* get the current record */
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen list_view = mail_index_transaction_get_view(trans);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen ext_id = maildir_list_get_ext_id(mbox->storage, list_view);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen mail_index_lookup_ext(list_view, seq, ext_id, &data, &expunged);
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen if (expunged)
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen return 0;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen old_rec = data;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen memset(&new_rec, 0, sizeof(new_rec));
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen if (mhdr->new_check_time <= mhdr->new_mtime + MAILDIR_SYNC_SECS ||
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen mhdr->cur_check_time <= mhdr->cur_mtime + MAILDIR_SYNC_SECS) {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen /* dirty, we need a refresh next time */
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen } else {
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen new_rec.new_mtime = mhdr->new_mtime;
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen new_rec.cur_mtime = mhdr->cur_mtime;
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen }
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen
24fc71a693331ffe77e2b6d81c70aca6fa055e47Timo Sirainen if (old_rec == NULL ||
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen memcmp(old_rec, &new_rec, sizeof(old_rec)) != 0) {
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen mail_index_update_ext(trans, seq,
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen mbox->storage->maildir_list_ext_id,
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen &new_rec, NULL);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen return 0;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen}
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen