int index_storage_mailbox_update(struct mailbox *box, const struct mailbox_update *update) { const struct mail_index_header *hdr; struct mail_index_view *view; struct mail_index_transaction *trans; int ret; if (mailbox_open(box) < 0) return -1; /* make sure we get the latest index info */ mail_index_refresh(box->index); view = mail_index_view_open(box->index); hdr = mail_index_get_header(view); trans = mail_index_transaction_begin(view, MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL); if (update->uid_validity != 0 && hdr->uid_validity != update->uid_validity) { uint32_t uid_validity = update->uid_validity; if (hdr->uid_validity != 0) { /* UIDVALIDITY change requires index to be reset */ mail_index_reset(trans); } mail_index_update_header(trans, offsetof(struct mail_index_header, uid_validity), &uid_validity, sizeof(uid_validity), TRUE); }
static void imapc_sync_uid_validity(struct imapc_sync_context *ctx) { struct imapc_mailbox *mbox = ctx->mbox; const struct mail_index_header *hdr; hdr = mail_index_get_header(ctx->sync_view); if (hdr->uid_validity != mbox->sync_uid_validity && mbox->sync_uid_validity != 0) { if (hdr->uid_validity != 0) { /* uidvalidity changed, reset the entire mailbox */ mail_index_reset(ctx->trans); mbox->sync_fetch_first_uid = 1; } mail_index_update_header(ctx->trans, offsetof(struct mail_index_header, uid_validity), &mbox->sync_uid_validity, sizeof(mbox->sync_uid_validity), TRUE); } }
int maildir_sync_index(struct maildir_index_sync_context *ctx, bool partial) { struct maildir_mailbox *mbox = ctx->mbox; struct mail_index_view *view = ctx->view; struct mail_index_view *view2; struct maildir_uidlist_iter_ctx *iter; struct mail_index_transaction *trans = ctx->trans; const struct mail_index_header *hdr; struct mail_index_header empty_hdr; const struct mail_index_record *rec; uint32_t seq, seq2, uid, prev_uid; enum maildir_uidlist_rec_flag uflags; const char *filename; uint32_t uid_validity, next_uid, hdr_next_uid, first_recent_uid; uint32_t first_uid; unsigned int changes = 0; int ret = 0; time_t time_before_sync; guid_128_t expunged_guid_128; enum mail_flags private_flags_mask; bool expunged, full_rescan = FALSE; i_assert(!mbox->syncing_commit); first_uid = 1; hdr = mail_index_get_header(view); uid_validity = maildir_uidlist_get_uid_validity(mbox->uidlist); if (uid_validity != hdr->uid_validity && uid_validity != 0 && hdr->uid_validity != 0) { /* uidvalidity changed and index isn't being synced for the first time, reset the index so we can add all messages as new */ i_warning("Maildir %s: UIDVALIDITY changed (%u -> %u)", mailbox_get_path(&ctx->mbox->box), hdr->uid_validity, uid_validity); mail_index_reset(trans); mailbox_recent_flags_reset(&mbox->box); first_uid = hdr->messages_count + 1; memset(&empty_hdr, 0, sizeof(empty_hdr)); empty_hdr.next_uid = 1; hdr = &empty_hdr; } hdr_next_uid = hdr->next_uid; ctx->mbox->box.tmp_sync_view = view; private_flags_mask = mailbox_get_private_flags_mask(&mbox->box); time_before_sync = time(NULL); mbox->syncing_commit = TRUE; seq = prev_uid = 0; first_recent_uid = I_MAX(hdr->first_recent_uid, 1); i_array_init(&ctx->keywords, MAILDIR_MAX_KEYWORDS); i_array_init(&ctx->idx_keywords, MAILDIR_MAX_KEYWORDS); iter = maildir_uidlist_iter_init(mbox->uidlist); while (maildir_uidlist_iter_next(iter, &uid, &uflags, &filename)) { maildir_filename_flags_get(ctx->keywords_sync_ctx, filename, &ctx->flags, &ctx->keywords); i_assert(uid > prev_uid); prev_uid = uid; /* the private flags are kept only in indexes. don't use them at all even for newly seen mails */ ctx->flags &= ~private_flags_mask; again: seq++; ctx->uid = uid; if (seq > hdr->messages_count) { if (uid < hdr_next_uid) { if (maildir_handle_uid_insertion(ctx, uflags, filename, uid) < 0) ret = -1; seq--; continue; } /* Trust uidlist recent flags only for newly added messages. When saving/copying messages with flags they're stored to cur/ and uidlist treats them as non-recent. */ if ((uflags & MAILDIR_UIDLIST_REC_FLAG_RECENT) == 0) { if (uid >= first_recent_uid) first_recent_uid = uid + 1; } hdr_next_uid = uid + 1; mail_index_append(trans, uid, &seq); mail_index_update_flags(trans, seq, MODIFY_REPLACE, ctx->flags); if (array_count(&ctx->keywords) > 0) { struct mail_keywords *kw; kw = mail_index_keywords_create_from_indexes( mbox->box.index, &ctx->keywords); mail_index_update_keywords(trans, seq, MODIFY_REPLACE, kw); mail_index_keywords_unref(&kw); } continue; } rec = mail_index_lookup(view, seq); if (uid > rec->uid) { /* already expunged (no point in showing guid in the expunge record anymore) */ mail_index_expunge(ctx->trans, seq); goto again; } if (uid < rec->uid) { if (maildir_handle_uid_insertion(ctx, uflags, filename, uid) < 0) ret = -1; seq--; continue; } index_sync_changes_read(ctx->sync_changes, ctx->uid, &expunged, expunged_guid_128); if (expunged) { if (!maildir_expunge_is_valid_guid(ctx, ctx->uid, filename, expunged_guid_128)) continue; if (maildir_file_do(mbox, ctx->uid, maildir_expunge, ctx) >= 0) { /* successful expunge */ mail_index_expunge(ctx->trans, seq); } 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; } mailbox_recent_flags_set_seqs(&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); }