changeset 21552:f48743eb38c6

lib-lda: Implement %{storage_id} correctly
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Mon, 13 Feb 2017 20:49:12 +0200
parents 8351a4c497cc
children 4a2884480ddc
files src/lib-lda/mail-deliver.c
diffstat 1 files changed, 57 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-lda/mail-deliver.c	Mon Feb 13 20:47:51 2017 +0200
+++ b/src/lib-lda/mail-deliver.c	Mon Feb 13 20:49:12 2017 +0200
@@ -24,6 +24,7 @@
 struct mail_deliver_user {
 	union mail_user_module_context module_ctx;
 	struct mail_deliver_context *deliver_ctx;
+	bool want_storage_id;
 };
 
 deliver_mail_func_t *deliver_mail = NULL;
@@ -453,6 +454,9 @@
 
 	i_assert(muser->deliver_ctx == NULL);
 
+	muser->want_storage_id =
+		var_has_key(ctx->set->deliver_log_format, '\0', "storage_id");
+
 	muser->deliver_ctx = ctx;
 	*storage_r = NULL;
 	if (deliver_mail == NULL)
@@ -530,6 +534,58 @@
 	return 0;
 }
 
+static void
+mail_deliver_cache_update_post_commit(struct mailbox *orig_box, uint32_t uid)
+{
+	struct mail_deliver_user *muser =
+		MAIL_DELIVER_USER_CONTEXT(orig_box->storage->user);
+	struct mailbox *box;
+	struct mailbox_transaction_context *t;
+	struct mail *mail;
+	const char *storage_id;
+
+	if (!muser->want_storage_id)
+		return;
+
+	/* getting storage_id requires a whole new mailbox view that is
+	   synced, so it'll contain the newly written mail. this is racy, so
+	   it's possible another process has already deleted the mail. */
+	box = mailbox_alloc(orig_box->list, orig_box->vname, 0);
+
+	mail = mail_deliver_open_mail(box, uid, MAIL_FETCH_STORAGE_ID, &t);
+	if (mail != NULL) {
+		if (mail_get_special(mail, MAIL_FETCH_STORAGE_ID, &storage_id) < 0 ||
+		    storage_id[0] == '\0')
+			storage_id = NULL;
+		muser->deliver_ctx->cache->storage_id =
+			p_strdup(muser->deliver_ctx->pool, storage_id);
+		mail_free(&mail);
+		(void)mailbox_transaction_commit(&t);
+	} else {
+		muser->deliver_ctx->cache->storage_id = NULL;
+	}
+	mailbox_free(&box);
+}
+
+static int
+mail_deliver_transaction_commit(struct mailbox_transaction_context *ctx,
+				struct mail_transaction_commit_changes *changes_r)
+{
+	struct mailbox *box = ctx->box;
+	union mailbox_module_context *mbox = MAIL_DELIVER_STORAGE_CONTEXT(box);
+
+	if (mbox->super.transaction_commit(ctx, changes_r) < 0)
+		return -1;
+
+	if (array_count(&changes_r->saved_uids) > 0) {
+		const struct seq_range *range =
+			array_idx(&changes_r->saved_uids, 0);
+
+		mail_deliver_cache_update_post_commit(box, range->seq1);
+	}
+	return 0;
+}
+
 static void mail_deliver_mail_user_created(struct mail_user *user)
 {
 	struct mail_deliver_user *muser;
@@ -548,6 +604,7 @@
 	box->vlast = &mbox->super;
 	v->save_finish = mail_deliver_save_finish;
 	v->copy = mail_deliver_copy;
+	v->transaction_commit = mail_deliver_transaction_commit;
 
 	MODULE_CONTEXT_SET_SELF(box, mail_deliver_storage_module, mbox);
  }