maildir-sync-index.c revision 53cc097d3f8cd789f3c8fa0dfdd02bcda776230e
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen/* Copyright (c) 2007-2014 Dovecot authors, see the included COPYING file */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "lib.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "ioloop.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "array.h"
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen#include "maildir-storage.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "index-sync-changes.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "maildir-uidlist.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "maildir-keywords.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "maildir-filename-flags.h"
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen#include "maildir-sync.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include <stdio.h>
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include <stdlib.h>
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include <unistd.h>
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstruct maildir_index_sync_context {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct maildir_mailbox *mbox;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct maildir_sync_context *maildir_sync_ctx;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mail_index_view *view;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mail_index_sync_ctx *sync_ctx;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct maildir_keywords_sync_ctx *keywords_sync_ctx;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mail_index_transaction *trans;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct maildir_uidlist_sync_ctx *uidlist_sync_ctx;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct index_sync_changes_context *sync_changes;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen enum mail_flags flags;
4d4d6d4745682790c20d759ba93dbea46b812c5dTimo Sirainen ARRAY_TYPE(keyword_indexes) keywords, idx_keywords;
4d4d6d4745682790c20d759ba93dbea46b812c5dTimo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen uint32_t uid;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen bool update_maildir_hdr_cur;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen time_t start_time;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int flag_change_count, expunge_count, new_msgs_count;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen};
17fe695b985e9d6e9dc39c05b24e6b3c3b7e1ba1Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstruct maildir_keywords_sync_ctx *
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenmaildir_sync_get_keywords_sync_ctx(struct maildir_index_sync_context *ctx)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return ctx->keywords_sync_ctx;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid maildir_sync_set_new_msgs_count(struct maildir_index_sync_context *ctx,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int count)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->new_msgs_count = count;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic bool
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenmaildir_expunge_is_valid_guid(struct maildir_index_sync_context *ctx,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen uint32_t uid, const char *filename,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen guid_128_t expunged_guid_128)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen guid_128_t guid_128;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *guid;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (guid_128_is_empty(expunged_guid_128)) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* no GUID associated with expunge */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return TRUE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen T_BEGIN {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen guid = maildir_uidlist_lookup_ext(ctx->mbox->uidlist, uid,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen MAILDIR_UIDLIST_REC_EXT_GUID);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (guid == NULL)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen guid = t_strcut(filename, ':');
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_generate_guid_128_hash(guid, guid_128);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen } T_END;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen if (memcmp(guid_128, expunged_guid_128, sizeof(guid_128)) == 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return TRUE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_storage_set_critical(&ctx->mbox->storage->storage,
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen "Mailbox %s: Expunged GUID mismatch for UID %u: %s vs %s",
0c22bef8f5b35c645de8affd8746307fc53bd222Timo Sirainen ctx->mbox->box.vname, ctx->uid,
0c22bef8f5b35c645de8affd8746307fc53bd222Timo Sirainen guid_128_to_string(guid_128),
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen guid_128_to_string(expunged_guid_128));
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen return FALSE;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen}
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainenstatic int maildir_expunge(struct maildir_mailbox *mbox, const char *path,
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen struct maildir_index_sync_context *ctx)
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen{
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen struct mailbox *box = &mbox->box;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->expunge_count++;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (unlink(path) == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (box->v.sync_notify != NULL) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen box->v.sync_notify(box, ctx->uid,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen MAILBOX_SYNC_TYPE_EXPUNGE);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (errno == ENOENT)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (errno == EISDIR)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return maildir_lose_unexpected_dir(box->storage, path);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_storage_set_critical(&mbox->storage->storage,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen "unlink(%s) failed: %m", path);
01230de017cd273de41143d88e9c18df1243ae8aTimo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int maildir_sync_flags(struct maildir_mailbox *mbox, const char *path,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct maildir_index_sync_context *ctx)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct mailbox *box = &mbox->box;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct stat st;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *dir, *fname, *newfname, *newpath;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen enum mail_index_sync_type sync_type;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen uint8_t flags8;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen ctx->flag_change_count++;
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen fname = strrchr(path, '/');
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen i_assert(fname != NULL);
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen fname++;
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen dir = t_strdup_until(path, fname);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(*fname != '\0');
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* get the current flags and keywords */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen maildir_filename_flags_get(ctx->keywords_sync_ctx,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen fname, &ctx->flags, &ctx->keywords);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* apply changes */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen flags8 = ctx->flags;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen index_sync_changes_apply(ctx->sync_changes, NULL,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen &flags8, &ctx->keywords, &sync_type);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->flags = flags8;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* and try renaming with the new name */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen newfname = maildir_filename_flags_kw_set(ctx->keywords_sync_ctx, fname,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->flags, &ctx->keywords);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen newpath = t_strconcat(dir, newfname, NULL);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (strcmp(path, newpath) == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* just make sure that the file still exists. avoid rename()
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen here because it's slow on HFS. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (stat(path, &st) < 0) {
c6335901c67a4c9365319190a111a2168f3b06f5Timo Sirainen if (errno == ENOENT)
c6335901c67a4c9365319190a111a2168f3b06f5Timo Sirainen return 0;
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen mail_storage_set_critical(box->storage,
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen "stat(%s) failed: %m", path);
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen return -1;
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } else {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (rename(path, newpath) < 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (errno == ENOENT)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (!ENOSPACE(errno) && errno != EACCES) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_storage_set_critical(box->storage,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "rename(%s, %s) failed: %m",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen path, newpath);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (box->v.sync_notify != NULL) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen box->v.sync_notify(box, ctx->uid,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen index_sync_type_convert(sync_type));
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int maildir_handle_uid_insertion(struct maildir_index_sync_context *ctx,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen enum maildir_uidlist_rec_flag uflags,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *filename, uint32_t uid)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen int ret;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if ((uflags & MAILDIR_UIDLIST_REC_FLAG_NONSYNCED) != 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* partial syncing */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* most likely a race condition: we read the maildir, then someone else
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen expunged messages and committed changes to index. so, this message
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen shouldn't actually exist. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if ((uflags & MAILDIR_UIDLIST_REC_FLAG_RACING) == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* mark it racy and check in next sync */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ctx->mbox->maildir_hdr.cur_check_time = 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen maildir_sync_set_racing(ctx->maildir_sync_ctx);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen maildir_uidlist_add_flags(ctx->mbox->uidlist, filename,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen MAILDIR_UIDLIST_REC_FLAG_RACING);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (ctx->uidlist_sync_ctx == NULL) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen ret = maildir_uidlist_sync_init(ctx->mbox->uidlist,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen MAILDIR_UIDLIST_SYNC_PARTIAL |
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen MAILDIR_UIDLIST_SYNC_KEEP_STATE,
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen &ctx->uidlist_sync_ctx);
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen if (ret <= 0)
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen return -1;
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen }
17fe695b985e9d6e9dc39c05b24e6b3c3b7e1ba1Timo Sirainen
17fe695b985e9d6e9dc39c05b24e6b3c3b7e1ba1Timo Sirainen uflags &= MAILDIR_UIDLIST_REC_FLAG_NEW_DIR;
17fe695b985e9d6e9dc39c05b24e6b3c3b7e1ba1Timo Sirainen maildir_uidlist_sync_remove(ctx->uidlist_sync_ctx, filename);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = maildir_uidlist_sync_next(ctx->uidlist_sync_ctx,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen filename, uflags);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(ret > 0);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* give the new UID to it immediately */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen maildir_uidlist_sync_finish(ctx->uidlist_sync_ctx);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_warning("Maildir %s: Expunged message reappeared, giving a new UID "
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "(old uid=%u, file=%s)%s", mailbox_get_path(&ctx->mbox->box),
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen uid, filename, strncmp(filename, "msg.", 4) != 0 ? "" :
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen " (Your MDA is saving MH files into Maildir?)");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenint maildir_sync_index_begin(struct maildir_mailbox *mbox,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct maildir_sync_context *maildir_sync_ctx,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct maildir_index_sync_context **ctx_r)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct mailbox *_box = &mbox->box;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct maildir_index_sync_context *ctx;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct mail_index_sync_ctx *sync_ctx;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct mail_index_view *view;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct mail_index_transaction *trans;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen enum mail_index_sync_flags sync_flags;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen sync_flags = index_storage_get_sync_flags(&mbox->box);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* don't drop recent messages if we're saving messages */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (maildir_sync_ctx == NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen sync_flags &= ~MAIL_INDEX_SYNC_FLAG_DROP_RECENT;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (mail_index_sync_begin(_box->index, &sync_ctx, &view,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen &trans, sync_flags) < 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mailbox_set_index_error(_box);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ctx = i_new(struct maildir_index_sync_context, 1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ctx->mbox = mbox;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ctx->maildir_sync_ctx = maildir_sync_ctx;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ctx->sync_ctx = sync_ctx;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ctx->view = view;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ctx->trans = trans;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ctx->keywords_sync_ctx =
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen maildir_keywords_sync_init(mbox->keywords, _box->index);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ctx->sync_changes =
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen index_sync_changes_init(ctx->sync_ctx, ctx->view, ctx->trans,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen maildir_is_backend_readonly(mbox));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ctx->start_time = time(NULL);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen *ctx_r = ctx;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic bool
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenmaildir_index_header_has_changed(const struct maildir_index_header *old_hdr,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const struct maildir_index_header *new_hdr)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#define DIR_DELAYED_REFRESH(hdr, name) \
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ((hdr)->name ## _check_time <= \
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen (hdr)->name ## _mtime + MAILDIR_SYNC_SECS)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (old_hdr->new_mtime != new_hdr->new_mtime ||
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen old_hdr->new_mtime_nsecs != new_hdr->new_mtime_nsecs ||
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen old_hdr->cur_mtime != new_hdr->cur_mtime ||
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen old_hdr->cur_mtime_nsecs != new_hdr->cur_mtime_nsecs ||
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen old_hdr->uidlist_mtime != new_hdr->uidlist_mtime ||
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen old_hdr->uidlist_mtime_nsecs != new_hdr->uidlist_mtime_nsecs ||
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen old_hdr->uidlist_size != new_hdr->uidlist_size)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return DIR_DELAYED_REFRESH(old_hdr, new) !=
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen DIR_DELAYED_REFRESH(new_hdr, new) ||
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen DIR_DELAYED_REFRESH(old_hdr, cur) !=
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen DIR_DELAYED_REFRESH(new_hdr, cur);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenmaildir_sync_index_update_ext_header(struct maildir_index_sync_context *ctx)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct maildir_mailbox *mbox = ctx->mbox;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const char *cur_path;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const void *data;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen size_t data_size;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct stat st;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen cur_path = t_strconcat(mailbox_get_path(&mbox->box), "/cur", NULL);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (ctx->update_maildir_hdr_cur && stat(cur_path, &st) == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if ((time_t)mbox->maildir_hdr.cur_check_time < st.st_mtime)
9240d99920783c56405dda74a1f6c7ff1ebed8e6Timo Sirainen mbox->maildir_hdr.cur_check_time = st.st_mtime;
9240d99920783c56405dda74a1f6c7ff1ebed8e6Timo Sirainen mbox->maildir_hdr.cur_mtime = st.st_mtime;
9240d99920783c56405dda74a1f6c7ff1ebed8e6Timo Sirainen mbox->maildir_hdr.cur_mtime_nsecs = ST_MTIME_NSEC(st);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_index_get_header_ext(mbox->box.view, mbox->maildir_ext_id,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen &data, &data_size);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (data_size != sizeof(mbox->maildir_hdr) ||
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen maildir_index_header_has_changed(data, &mbox->maildir_hdr)) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_index_update_header_ext(ctx->trans, mbox->maildir_ext_id,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen 0, &mbox->maildir_hdr,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen sizeof(mbox->maildir_hdr));
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int maildir_sync_index_finish(struct maildir_index_sync_context *ctx,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen bool success)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct maildir_mailbox *mbox = ctx->mbox;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int time_diff;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen int ret = success ? 0 : -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
9240d99920783c56405dda74a1f6c7ff1ebed8e6Timo Sirainen time_diff = time(NULL) - ctx->start_time;
9240d99920783c56405dda74a1f6c7ff1ebed8e6Timo Sirainen if (time_diff >= MAILDIR_SYNC_TIME_WARN_SECS) {
9240d99920783c56405dda74a1f6c7ff1ebed8e6Timo Sirainen i_warning("Maildir %s: Synchronization took %u seconds "
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "(%u new msgs, %u flag change attempts, "
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "%u expunge attempts)",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mailbox_get_path(&ctx->mbox->box), time_diff,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ctx->new_msgs_count, ctx->flag_change_count,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ctx->expunge_count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (ret < 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_sync_rollback(&ctx->sync_ctx);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen else {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen maildir_sync_index_update_ext_header(ctx);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* Set syncing_commit=TRUE so that if any sync callbacks try
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen to access mails which got lost (eg. expunge callback trying
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen to open the file which was just unlinked) we don't try to
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen start a second index sync and crash. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mbox->syncing_commit = TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (mail_index_sync_commit(&ctx->sync_ctx) < 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mailbox_set_index_error(&mbox->box);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mbox->syncing_commit = FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen maildir_keywords_sync_deinit(&ctx->keywords_sync_ctx);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen index_sync_changes_deinit(&ctx->sync_changes);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_free(ctx);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return ret;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenint maildir_sync_index_commit(struct maildir_index_sync_context **_ctx)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct maildir_index_sync_context *ctx = *_ctx;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen *_ctx = NULL;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return maildir_sync_index_finish(ctx, TRUE);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid maildir_sync_index_rollback(struct maildir_index_sync_context **_ctx)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct maildir_index_sync_context *ctx = *_ctx;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen *_ctx = NULL;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (void)maildir_sync_index_finish(ctx, FALSE);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic int uint_cmp(const unsigned int *i1, const unsigned int *i2)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (*i1 < *i2)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return -1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen else if (*i1 > *i2)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return 1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen else
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen return 0;
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen}
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainenstatic void
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainenmaildir_sync_mail_keywords(struct maildir_index_sync_context *ctx, uint32_t seq)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct mailbox *box = &ctx->mbox->box;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mail_keywords *kw;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int i, j, old_count, new_count;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const unsigned int *old_indexes, *new_indexes;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen bool have_indexonly_keywords;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen int diff;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_index_lookup_keywords(ctx->view, seq, &ctx->idx_keywords);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (index_keyword_array_cmp(&ctx->keywords, &ctx->idx_keywords)) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* no changes - we should get here usually */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen /* sort the keywords */
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen array_sort(&ctx->idx_keywords, uint_cmp);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen array_sort(&ctx->keywords, uint_cmp);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen /* drop keywords that are in index-only. we don't want to touch them. */
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen old_indexes = array_get(&ctx->idx_keywords, &old_count);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen have_indexonly_keywords = FALSE;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen for (i = old_count; i > 0; i--) {
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen if (maildir_keywords_idx_char(ctx->keywords_sync_ctx,
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen old_indexes[i-1]) == '\0') {
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen have_indexonly_keywords = TRUE;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen array_delete(&ctx->idx_keywords, i-1, 1);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen }
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen }
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen if (!have_indexonly_keywords) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* no index-only keywords found, so something changed.
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen just replace them all. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen kw = mail_index_keywords_create_from_indexes(box->index,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen &ctx->keywords);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_update_keywords(ctx->trans, seq, MODIFY_REPLACE, kw);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_keywords_unref(&kw);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* check again if non-index-only keywords changed */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (index_keyword_array_cmp(&ctx->keywords, &ctx->idx_keywords))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* we can't reset all the keywords or we'd drop indexonly keywords too.
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen so first remove the unwanted keywords and then add back the wanted
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ones. we can get these lists easily by removing common elements
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen from old and new keywords. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen new_indexes = array_get(&ctx->keywords, &new_count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (i = j = 0; i < old_count && j < new_count; ) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen diff = (int)old_indexes[i] - (int)new_indexes[j];
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (diff == 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen array_delete(&ctx->keywords, j, 1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen array_delete(&ctx->idx_keywords, i, 1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen old_indexes = array_get(&ctx->idx_keywords, &old_count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen new_indexes = array_get(&ctx->keywords, &new_count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } else if (diff < 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i++;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } else {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen j++;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (array_count(&ctx->idx_keywords) > 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen kw = mail_index_keywords_create_from_indexes(box->index,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen &ctx->idx_keywords);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_index_update_keywords(ctx->trans, seq, MODIFY_REMOVE, kw);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen mail_index_keywords_unref(&kw);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (array_count(&ctx->keywords) > 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen kw = mail_index_keywords_create_from_indexes(box->index,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen &ctx->keywords);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_update_keywords(ctx->trans, seq, MODIFY_ADD, kw);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_keywords_unref(&kw);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainenint maildir_sync_index(struct maildir_index_sync_context *ctx,
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen bool partial)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen struct maildir_mailbox *mbox = ctx->mbox;
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen struct mail_index_view *view = ctx->view;
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen struct mail_index_view *view2;
c99fe55d4535d839a6ad0735c4719e076a1adb2cTimo Sirainen struct maildir_uidlist_iter_ctx *iter;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mail_index_transaction *trans = ctx->trans;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const struct mail_index_header *hdr;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct mail_index_header empty_hdr;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const struct mail_index_record *rec;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen uint32_t seq, seq2, uid, prev_uid;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen enum maildir_uidlist_rec_flag uflags;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *filename;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen uint32_t uid_validity, next_uid, hdr_next_uid, first_recent_uid;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen uint32_t first_uid;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int changes = 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen int ret = 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen time_t time_before_sync;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen guid_128_t expunged_guid_128;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen enum mail_flags private_flags_mask;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen bool expunged, full_rescan = FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(!mbox->syncing_commit);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen first_uid = 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen hdr = mail_index_get_header(view);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen uid_validity = maildir_uidlist_get_uid_validity(mbox->uidlist);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (uid_validity != hdr->uid_validity &&
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen uid_validity != 0 && hdr->uid_validity != 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* uidvalidity changed and index isn't being synced for the
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen first time, reset the index so we can add all messages as
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen new */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_warning("Maildir %s: UIDVALIDITY changed (%u -> %u)",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mailbox_get_path(&ctx->mbox->box),
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen hdr->uid_validity, uid_validity);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_reset(trans);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen index_mailbox_reset_uidvalidity(&mbox->box);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen first_uid = hdr->messages_count + 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen memset(&empty_hdr, 0, sizeof(empty_hdr));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen empty_hdr.next_uid = 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen hdr = &empty_hdr;
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen }
e4eb49e29197c6783ec93b868100394e189f4e0cTimo Sirainen hdr_next_uid = hdr->next_uid;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ctx->mbox->box.tmp_sync_view = view;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen private_flags_mask = mailbox_get_private_flags_mask(&mbox->box);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen time_before_sync = time(NULL);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mbox->syncing_commit = TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen seq = prev_uid = 0; first_recent_uid = I_MAX(hdr->first_recent_uid, 1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_array_init(&ctx->keywords, MAILDIR_MAX_KEYWORDS);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_array_init(&ctx->idx_keywords, MAILDIR_MAX_KEYWORDS);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen iter = maildir_uidlist_iter_init(mbox->uidlist);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen while (maildir_uidlist_iter_next(iter, &uid, &uflags, &filename)) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen maildir_filename_flags_get(ctx->keywords_sync_ctx, filename,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen &ctx->flags, &ctx->keywords);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(uid > prev_uid);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen prev_uid = uid;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* the private flags are kept only in indexes. don't use them
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen at all even for newly seen mails */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ctx->flags &= ~private_flags_mask;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen again:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen seq++;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ctx->uid = uid;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen if (seq > hdr->messages_count) {
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen if (uid < hdr_next_uid) {
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen if (maildir_handle_uid_insertion(ctx, uflags,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen filename,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen uid) < 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen seq--;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen continue;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* Trust uidlist recent flags only for newly added
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen messages. When saving/copying messages with flags
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen they're stored to cur/ and uidlist treats them
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen as non-recent. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if ((uflags & MAILDIR_UIDLIST_REC_FLAG_RECENT) == 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (uid >= first_recent_uid)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen first_recent_uid = uid + 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen hdr_next_uid = uid + 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_append(trans, uid, &seq);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_update_flags(trans, seq, MODIFY_REPLACE,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ctx->flags);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (array_count(&ctx->keywords) > 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct mail_keywords *kw;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen kw = mail_index_keywords_create_from_indexes(
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mbox->box.index, &ctx->keywords);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_update_keywords(trans, seq,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen MODIFY_REPLACE, kw);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_keywords_unref(&kw);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen continue;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen rec = mail_index_lookup(view, seq);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (uid > rec->uid) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* already expunged (no point in showing guid in the
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen expunge record anymore) */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_expunge(ctx->trans, seq);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen goto again;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (uid < rec->uid) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (maildir_handle_uid_insertion(ctx, uflags,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen filename, uid) < 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen seq--;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen continue;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen index_sync_changes_read(ctx->sync_changes, ctx->uid, &expunged,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen expunged_guid_128);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (expunged) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!maildir_expunge_is_valid_guid(ctx, ctx->uid,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen filename,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen expunged_guid_128))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen continue;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (maildir_file_do(mbox, ctx->uid,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen maildir_expunge, ctx) >= 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* successful expunge */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mail_index_expunge(ctx->trans, seq);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
if ((++changes % MAILDIR_SLOW_MOVE_COUNT) == 0)
maildir_sync_notify(ctx->maildir_sync_ctx);
continue;
}
/* the private flags are stored only in indexes, keep them */
ctx->flags |= rec->flags & private_flags_mask;
if (index_sync_changes_have(ctx->sync_changes)) {
/* apply flag changes to maildir */
if (maildir_file_do(mbox, ctx->uid,
maildir_sync_flags, ctx) < 0)
ctx->flags |= MAIL_INDEX_MAIL_FLAG_DIRTY;
if ((++changes % MAILDIR_SLOW_MOVE_COUNT) == 0)
maildir_sync_notify(ctx->maildir_sync_ctx);
}
if ((uflags & MAILDIR_UIDLIST_REC_FLAG_NONSYNCED) != 0) {
/* partial syncing */
if ((uflags & MAILDIR_UIDLIST_REC_FLAG_NEW_DIR) != 0) {
/* we last saw this mail in new/, but it's
not there anymore. possibly expunged,
make sure. */
full_rescan = TRUE;
}
continue;
}
if ((rec->flags & MAIL_INDEX_MAIL_FLAG_DIRTY) != 0) {
/* we haven't been able to update maildir with this
record's flag changes. don't sync them. */
continue;
}
if (ctx->flags != (rec->flags & MAIL_FLAGS_NONRECENT)) {
mail_index_update_flags(trans, seq, MODIFY_REPLACE,
ctx->flags);
}
maildir_sync_mail_keywords(ctx, seq);
}
maildir_uidlist_iter_deinit(&iter);
if (!partial) {
/* expunge the rest */
for (seq++; seq <= hdr->messages_count; seq++)
mail_index_expunge(ctx->trans, seq);
}
/* add \Recent flags. use updated view so it contains newly
appended messages. */
view2 = mail_index_transaction_open_updated_view(trans);
if (mail_index_lookup_seq_range(view2, first_recent_uid, (uint32_t)-1,
&seq, &seq2) && seq2 >= first_uid) {
if (seq < first_uid) {
/* UIDVALIDITY changed, skip over the old messages */
seq = first_uid;
}
index_mailbox_set_recent_seq(&mbox->box, view2, seq, seq2);
}
mail_index_view_close(&view2);
if (ctx->uidlist_sync_ctx != NULL) {
if (maildir_uidlist_sync_deinit(&ctx->uidlist_sync_ctx,
TRUE) < 0)
ret = -1;
}
if (mbox->box.v.sync_notify != NULL)
mbox->box.v.sync_notify(&mbox->box, 0, 0);
ctx->mbox->box.tmp_sync_view = NULL;
/* check cur/ mtime later. if we came here from saving messages they
could still be moved to cur/ directory. */
ctx->update_maildir_hdr_cur = TRUE;
mbox->maildir_hdr.cur_check_time = time_before_sync;
if (uid_validity == 0) {
uid_validity = hdr->uid_validity != 0 ? hdr->uid_validity :
maildir_get_uidvalidity_next(mbox->box.list);
maildir_uidlist_set_uid_validity(mbox->uidlist, uid_validity);
}
maildir_uidlist_set_next_uid(mbox->uidlist, hdr_next_uid, FALSE);
if (uid_validity != hdr->uid_validity) {
mail_index_update_header(trans,
offsetof(struct mail_index_header, uid_validity),
&uid_validity, sizeof(uid_validity), TRUE);
}
next_uid = maildir_uidlist_get_next_uid(mbox->uidlist);
if (hdr_next_uid < next_uid) {
mail_index_update_header(trans,
offsetof(struct mail_index_header, next_uid),
&next_uid, sizeof(next_uid), FALSE);
}
i_assert(hdr->first_recent_uid <= first_recent_uid);
if (hdr->first_recent_uid < first_recent_uid) {
mail_index_update_header(ctx->trans,
offsetof(struct mail_index_header, first_recent_uid),
&first_recent_uid, sizeof(first_recent_uid), FALSE);
}
array_free(&ctx->keywords);
array_free(&ctx->idx_keywords);
mbox->syncing_commit = FALSE;
return ret < 0 ? -1 : (full_rescan ? 0 : 1);
}
static unsigned int
maildir_list_get_ext_id(struct maildir_mailbox *mbox,
struct mail_index_view *view)
{
if (mbox->maildir_list_index_ext_id == (uint32_t)-1) {
mbox->maildir_list_index_ext_id =
mail_index_ext_register(mail_index_view_get_index(view),
"maildir", 0,
sizeof(struct maildir_list_index_record),
sizeof(uint32_t));
}
return mbox->maildir_list_index_ext_id;
}
int maildir_list_index_has_changed(struct mailbox *box,
struct mail_index_view *list_view,
uint32_t seq)
{
struct maildir_mailbox *mbox = (struct maildir_mailbox *)box;
const struct maildir_list_index_record *rec;
const void *data;
const char *root_dir, *new_dir, *cur_dir;
struct stat st;
uint32_t ext_id;
bool expunged;
int ret;
ret = index_storage_list_index_has_changed(box, list_view, seq);
if (ret != 0 || box->storage->set->mailbox_list_index_very_dirty_syncs)
return ret;
ext_id = maildir_list_get_ext_id(mbox, list_view);
mail_index_lookup_ext(list_view, seq, ext_id, &data, &expunged);
rec = data;
if (rec == NULL || expunged ||
rec->new_mtime == 0 || rec->cur_mtime == 0) {
/* doesn't exist, not synced or dirty-synced */
return 1;
}
ret = mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_MAILBOX,
&root_dir);
if (ret < 0)
return ret;
i_assert(ret > 0);
/* check if new/ changed */
new_dir = t_strconcat(root_dir, "/new", NULL);
if (stat(new_dir, &st) < 0) {
mail_storage_set_critical(box->storage,
"stat(%s) failed: %m", new_dir);
return -1;
}
if ((time_t)rec->new_mtime != st.st_mtime)
return 1;
/* check if cur/ changed */
cur_dir = t_strconcat(root_dir, "/cur", NULL);
if (stat(cur_dir, &st) < 0) {
mail_storage_set_critical(box->storage,
"stat(%s) failed: %m", cur_dir);
return -1;
}
if ((time_t)rec->cur_mtime != st.st_mtime)
return 1;
return 0;
}
void maildir_list_index_update_sync(struct mailbox *box,
struct mail_index_transaction *trans,
uint32_t seq)
{
struct maildir_mailbox *mbox = (struct maildir_mailbox *)box;
struct mail_index_view *list_view;
const struct maildir_index_header *mhdr = &mbox->maildir_hdr;
const struct maildir_list_index_record *old_rec;
struct maildir_list_index_record new_rec;
const void *data;
uint32_t ext_id;
bool expunged;
index_storage_list_index_update_sync(box, trans, seq);
if (mbox->storage->set->maildir_very_dirty_syncs)
return;
/* get the current record */
list_view = mail_index_transaction_get_view(trans);
ext_id = maildir_list_get_ext_id(mbox, list_view);
mail_index_lookup_ext(list_view, seq, ext_id, &data, &expunged);
if (expunged)
return;
old_rec = data;
memset(&new_rec, 0, sizeof(new_rec));
if (mhdr->new_check_time <= mhdr->new_mtime + MAILDIR_SYNC_SECS ||
mhdr->cur_check_time <= mhdr->cur_mtime + MAILDIR_SYNC_SECS) {
/* dirty, we need a refresh next time */
} else {
new_rec.new_mtime = mhdr->new_mtime;
new_rec.cur_mtime = mhdr->cur_mtime;
}
if (old_rec == NULL ||
memcmp(old_rec, &new_rec, sizeof(*old_rec)) != 0)
mail_index_update_ext(trans, seq, ext_id, &new_rec, NULL);
}