return index_mail_init_stream(mail, hdr_size, body_size, stream_r);
}
+static void maildir_mail_update_uid(struct mail *_mail, uint32_t new_uid)
+{
+ maildir_save_add_conflict(_mail->transaction, _mail->uid, new_uid);
+ index_mail_update_uid(_mail, new_uid);
+}
+
static void maildir_mail_set_cache_corrupted(struct mail *_mail,
enum mail_fetch_field field)
{
index_mail_update_flags,
index_mail_update_keywords,
index_mail_update_modseq,
- index_mail_update_uid,
+ maildir_mail_update_uid,
index_mail_expunge,
maildir_mail_set_cache_corrupted,
index_mail_get_index_mail
/* unsigned int keywords[]; */
};
+struct maildir_save_conflict {
+ uint32_t old_uid, new_uid;
+};
+
struct maildir_save_context {
struct mail_save_context ctx;
pool_t pool;
struct maildir_filename *files, **files_tail, *file_last;
unsigned int files_count;
+ ARRAY_DEFINE(conflicts, struct maildir_save_conflict);
+
buffer_t keywords_buffer;
ARRAY_TYPE(keyword_indexes) keywords_array;
(void)maildir_save_finish(_ctx);
}
+void maildir_save_add_conflict(struct mailbox_transaction_context *t,
+ uint32_t old_uid, uint32_t new_uid)
+{
+ struct maildir_save_context *save_ctx;
+ struct maildir_save_conflict *c;
+
+ save_ctx = (struct maildir_save_context *)maildir_save_alloc(t);
+
+ if (!array_is_created(&save_ctx->conflicts))
+ i_array_init(&save_ctx->conflicts, 64);
+
+ c = array_append_space(&save_ctx->conflicts);
+ c->old_uid = old_uid;
+ c->new_uid = new_uid;
+}
+
+static void maildir_sync_conflict(struct maildir_save_context *ctx,
+ const struct maildir_save_conflict *conflict)
+{
+ const char *filename;
+ enum maildir_uidlist_rec_flag flags;
+
+ if (maildir_uidlist_lookup(ctx->mbox->uidlist, conflict->old_uid,
+ &flags, &filename) <= 0) {
+ i_error("maildir %s: uid %u update failed: lost filename",
+ ctx->mbox->ibox.box.path, conflict->old_uid);
+ return;
+ }
+ maildir_uidlist_sync_remove(ctx->uidlist_sync_ctx, filename);
+ if (maildir_uidlist_sync_next_uid(ctx->uidlist_sync_ctx, filename,
+ conflict->new_uid, 0) < 0) {
+ i_error("maildir %s: uid %u update failed: sync failed",
+ ctx->mbox->ibox.box.path, conflict->old_uid);
+ }
+}
+
+static void maildir_sync_conflicts(struct maildir_save_context *ctx)
+{
+ const struct maildir_save_conflict *conflicts;
+ unsigned int i, count;
+
+ if (!array_is_created(&ctx->conflicts))
+ return;
+
+ conflicts = array_get(&ctx->conflicts, &count);
+ for (i = 0; i < count; i++)
+ maildir_sync_conflict(ctx, &conflicts[i]);
+}
+
static void
maildir_save_unlink_files(struct maildir_save_context *ctx)
{
(struct index_transaction_context *)ctx->ctx.transaction;
uint32_t seq;
+ if (ctx->seq == 0)
+ return;
+
for (seq = ctx->seq; seq >= ctx->first_seq; seq--)
mail_index_expunge(ctx->trans, seq);
i_assert(_ctx->output == NULL);
i_assert(ctx->last_save_finished);
+ if (ctx->files_count == 0 && !array_is_created(&ctx->conflicts))
+ return 0;
+
sync_flags = MAILDIR_UIDLIST_SYNC_PARTIAL |
MAILDIR_UIDLIST_SYNC_NOREFRESH;
maildir_transaction_save_rollback(_ctx);
return -1;
}
+ maildir_sync_conflicts(ctx);
} else if (ret == 0 &&
(sync_flags & MAILDIR_UIDLIST_SYNC_TRYLOCK) != 0) {
ctx->locked = FALSE;
if (ctx->locked)
maildir_uidlist_unlock(ctx->mbox->uidlist);
+ if (array_is_created(&ctx->conflicts))
+ array_free(&ctx->conflicts);
pool_unref(&ctx->pool);
}
if (ctx->mail != NULL)
mail_free(&ctx->mail);
+ if (array_is_created(&ctx->conflicts))
+ array_free(&ctx->conflicts);
pool_unref(&ctx->pool);
}