void index_transaction_init(struct mailbox_transaction_context *t, struct mailbox *box, enum mailbox_transaction_flags flags) { enum mail_index_transaction_flags itrans_flags; i_assert(box->opened); itrans_flags = index_transaction_flags_get(flags); if ((flags & MAILBOX_TRANSACTION_FLAG_REFRESH) != 0) mail_index_refresh(box->index); t->box = box; t->itrans = mail_index_transaction_begin(box->view, itrans_flags); t->view = mail_index_transaction_open_updated_view(t->itrans); array_create(&t->module_contexts, default_pool, sizeof(void *), 5); t->cache_view = mail_cache_view_open(box->cache, t->view); t->cache_trans = mail_cache_get_transaction(t->cache_view, t->itrans); if ((flags & MAILBOX_TRANSACTION_FLAG_NO_CACHE_DEC) != 0) mail_cache_view_update_cache_decisions(t->cache_view, FALSE); /* set up after mail_cache_get_transaction(), so that we'll still have the cache_trans available in _index_commit() */ t->super = t->itrans->v; t->itrans->v.commit = index_transaction_index_commit; t->itrans->v.rollback = index_transaction_index_rollback; MODULE_CONTEXT_SET(t->itrans, mail_storage_mail_index_module, t); }
void index_transaction_init(struct index_transaction_context *it, struct mailbox *box, enum mailbox_transaction_flags flags) { struct mailbox_transaction_context *t = &it->mailbox_ctx; enum mail_index_transaction_flags trans_flags; i_assert(box->opened); trans_flags = MAIL_INDEX_TRANSACTION_FLAG_AVOID_FLAG_UPDATES; if ((flags & MAILBOX_TRANSACTION_FLAG_HIDE) != 0) trans_flags |= MAIL_INDEX_TRANSACTION_FLAG_HIDE; if ((flags & MAILBOX_TRANSACTION_FLAG_EXTERNAL) != 0) trans_flags |= MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL; if ((flags & MAILBOX_TRANSACTION_FLAG_REFRESH) != 0) (void)mail_index_refresh(box->index); t->box = box; t->itrans = mail_index_transaction_begin(box->view, trans_flags); t->view = mail_index_transaction_open_updated_view(t->itrans); array_create(&t->module_contexts, default_pool, sizeof(void *), 5); it->cache_view = mail_cache_view_open(box->cache, t->view); it->cache_trans = mail_cache_get_transaction(it->cache_view, t->itrans); /* set up after mail_cache_get_transaction(), so that we'll still have the cache_trans available in _index_commit() */ it->super = t->itrans->v; t->itrans->v.commit = index_transaction_index_commit; t->itrans->v.rollback = index_transaction_index_rollback; MODULE_CONTEXT_SET(t->itrans, mail_storage_mail_index_module, it); }
void index_transaction_init_pvt(struct mailbox_transaction_context *t) { enum mail_index_transaction_flags itrans_flags; if (t->box->view_pvt == NULL || t->itrans_pvt != NULL) return; itrans_flags = index_transaction_flags_get(t->flags); t->itrans_pvt = mail_index_transaction_begin(t->box->view_pvt, itrans_flags); t->view_pvt = mail_index_transaction_open_updated_view(t->itrans_pvt); }
static void imapc_mailbox_init_delayed_trans(struct imapc_mailbox *mbox) { if (mbox->delayed_sync_trans != NULL) return; i_assert(mbox->delayed_sync_cache_view == NULL); i_assert(mbox->delayed_sync_cache_trans == NULL); mbox->delayed_sync_trans = mail_index_transaction_begin(imapc_mailbox_get_sync_view(mbox), MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL); mbox->delayed_sync_view = mail_index_transaction_open_updated_view(mbox->delayed_sync_trans); mbox->delayed_sync_cache_view = mail_cache_view_open(mbox->box.cache, mbox->delayed_sync_view); mbox->delayed_sync_cache_trans = mail_cache_get_transaction(mbox->delayed_sync_cache_view, mbox->delayed_sync_trans); }
static void index_rebuild_header(struct index_rebuild_context *ctx, index_rebuild_generate_uidvalidity_t *gen_uidvalidity) { const struct mail_index_header *hdr, *backup_hdr, *trans_hdr; struct mail_index *index = mail_index_view_get_index(ctx->view); struct mail_index_modseq_header modseq_hdr; struct mail_index_view *trans_view; uint32_t uid_validity, next_uid; uint64_t modseq; hdr = mail_index_get_header(ctx->view); backup_hdr = ctx->backup_view == NULL ? NULL : mail_index_get_header(ctx->backup_view); trans_view = mail_index_transaction_open_updated_view(ctx->trans); trans_hdr = mail_index_get_header(trans_view); /* set uidvalidity */ if (hdr->uid_validity != 0) uid_validity = hdr->uid_validity; else if (backup_hdr != NULL && backup_hdr->uid_validity != 0) uid_validity = backup_hdr->uid_validity; else uid_validity = gen_uidvalidity(ctx->box->list); mail_index_update_header(ctx->trans, offsetof(struct mail_index_header, uid_validity), &uid_validity, sizeof(uid_validity), TRUE); /* set next-uid */ if (hdr->next_uid != 0) next_uid = hdr->next_uid; else if (backup_hdr != NULL && backup_hdr->next_uid != 0) next_uid = backup_hdr->next_uid; else next_uid = 1; if (next_uid > trans_hdr->next_uid) { mail_index_update_header(ctx->trans, offsetof(struct mail_index_header, next_uid), &next_uid, sizeof(next_uid), FALSE); }
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); }