dovecot-2.0: lazy-expunge: Support a single-namespace configurat...

dovecot at dovecot.org dovecot at dovecot.org
Mon Dec 14 21:40:22 EET 2009


details:   http://hg.dovecot.org/dovecot-2.0/rev/b2f31df5f5da
changeset: 10485:b2f31df5f5da
user:      Timo Sirainen <tss at iki.fi>
date:      Mon Dec 14 14:40:16 2009 -0500
description:
lazy-expunge: Support a single-namespace configuration.
If a mailbox is deleted, its contents are merged with the existing expunged
messages.

diffstat:

1 file changed, 116 insertions(+), 18 deletions(-)
src/plugins/lazy-expunge/lazy-expunge-plugin.c |  134 ++++++++++++++++++++----

diffs (222 lines):

diff -r 43895027cab9 -r b2f31df5f5da src/plugins/lazy-expunge/lazy-expunge-plugin.c
--- a/src/plugins/lazy-expunge/lazy-expunge-plugin.c	Mon Dec 14 14:32:01 2009 -0500
+++ b/src/plugins/lazy-expunge/lazy-expunge-plugin.c	Mon Dec 14 14:40:16 2009 -0500
@@ -7,6 +7,7 @@
 #include "seq-range-array.h"
 #include "mkdir-parents.h"
 #include "mail-storage-private.h"
+#include "mail-search-build.h"
 #include "mailbox-list-private.h"
 #include "mail-namespace.h"
 #include "lazy-expunge-plugin.h"
@@ -45,7 +46,9 @@ struct lazy_expunge_mailbox_list {
 	union mailbox_list_module_context module_ctx;
 
 	struct mailbox_list *expunge_list;
-	bool internal_namespace;
+
+	unsigned int internal_namespace:1;
+	unsigned int deleting:1;
 };
 
 struct lazy_expunge_transaction {
@@ -273,11 +276,11 @@ mailbox_move(struct mailbox_list *src_li
 		mailbox_list_get_last_error(src_list, &error);
 		switch (error) {
 		case MAIL_ERROR_EXISTS:
-			return -1;
+			break;
 		case MAIL_ERROR_NOTFOUND:
 			return 0;
 		default:
-			break;
+			return -1;
 		}
 
 		/* mailbox is being deleted multiple times per second.
@@ -285,7 +288,83 @@ mailbox_move(struct mailbox_list *src_li
 		dest_name = t_strdup_printf("%s-%04u", *_dest_name,
 					    (uint32_t)random());
 	}
+	*_dest_name = dest_name;
 	return 1;
+}
+
+static int
+mailbox_move_all_mails(struct mailbox_list *list,
+		       const char *src_name, const char *dest_name)
+{
+	struct mailbox *src_box, *dest_box;
+	struct mail_search_args *search_args;
+        struct mailbox_transaction_context *src_trans, *dest_trans;
+	struct mail_search_context *search_ctx;
+	struct mail_save_context *save_ctx;
+	struct mail *mail;
+	const char *errstr;
+	enum mail_error error;
+	int ret;
+
+	dest_box = mailbox_alloc(list, dest_name, NULL, 0);
+	if (mailbox_open(dest_box) < 0) {
+		errstr = mail_storage_get_last_error(dest_box->storage, &error);
+		i_error("lazy_expunge: Couldn't open DELETE dest mailbox "
+			"%s: %s", dest_name, errstr);
+		mailbox_close(&dest_box);
+		return -1;
+	}
+
+	src_box = mailbox_alloc(list, src_name, NULL, MAILBOX_FLAG_KEEP_LOCKED);
+	if (mailbox_open(src_box) < 0) {
+		errstr = mail_storage_get_last_error(src_box->storage, &error);
+		mailbox_close(&src_box);
+		mailbox_close(&dest_box);
+
+		if (error == MAIL_ERROR_NOTFOUND)
+			return 0;
+		i_error("lazy_expunge: Couldn't open DELETE source mailbox "
+			"%s: %s", src_name, errstr);
+		return -1;
+	}
+
+	src_trans = mailbox_transaction_begin(src_box, 0);
+	dest_trans = mailbox_transaction_begin(dest_box,
+					MAILBOX_TRANSACTION_FLAG_EXTERNAL);
+
+	search_args = mail_search_build_init();
+	mail_search_build_add_all(search_args);
+	search_ctx = mailbox_search_init(src_trans, search_args, NULL);
+	mail_search_args_unref(&search_args);
+
+	mail = mail_alloc(src_trans, 0, NULL);
+	while ((ret = mailbox_search_next(search_ctx, mail)) > 0) {
+		save_ctx = mailbox_save_alloc(dest_trans);
+		mailbox_save_copy_flags(save_ctx, mail);
+		if (mailbox_copy(&save_ctx, mail) < 0) {
+			if (!mail->expunged) {
+				ret = -1;
+				break;
+			}
+		}
+	}
+	mail_free(&mail);
+
+	if (mailbox_search_deinit(&search_ctx) < 0)
+		ret = -1;
+
+	(void)mailbox_transaction_commit(&src_trans);
+	if (ret == 0)
+		ret = mailbox_transaction_commit(&dest_trans);
+	else
+		mailbox_transaction_rollback(&dest_trans);
+
+	mailbox_close(&src_box);
+	mailbox_close(&dest_box);
+
+	if (ret == 0)
+		ret = mailbox_list_delete_mailbox(list, src_name);
+	return ret;
 }
 
 static int
@@ -293,14 +372,14 @@ lazy_expunge_mailbox_list_delete(struct 
 {
 	struct lazy_expunge_mailbox_list *llist =
 		LAZY_EXPUNGE_LIST_CONTEXT(list);
-	struct mail_namespace *src_ns, *dest_ns;
+	struct mail_namespace *expunge_ns, *dest_ns;
 	enum mailbox_name_status status;
 	const char *destname;
 	struct tm *tm;
 	char timestamp[256];
 	int ret;
 
-	if (llist->internal_namespace)
+	if (llist->internal_namespace || llist->deleting)
 		return llist->module_ctx.super.delete_mailbox(list, name);
 
 	/* first do the normal sanity checks */
@@ -318,14 +397,24 @@ lazy_expunge_mailbox_list_delete(struct 
 		return -1;
 	}
 
-	/* destination mailbox name needs to contain a timestamp */
-	tm = localtime(&ioloop_time);
-	if (strftime(timestamp, sizeof(timestamp), "%Y%m%d-%H%M%S", tm) == 0)
-		i_strocpy(timestamp, dec2str(ioloop_time), sizeof(timestamp));
-	destname = t_strconcat(name, "-", timestamp, NULL);
+	expunge_ns = get_lazy_ns(list->ns->user, LAZY_NAMESPACE_EXPUNGE);
+	dest_ns = get_lazy_ns(list->ns->user, LAZY_NAMESPACE_DELETE);
+	if (expunge_ns == dest_ns) {
+		/* if there are no expunged messages in this mailbox,
+		   we can simply rename the mailbox to the destination name */
+		destname = name;
+	} else {
+		/* destination mailbox name needs to contain a timestamp */
+		tm = localtime(&ioloop_time);
+		if (strftime(timestamp, sizeof(timestamp),
+			     "%Y%m%d-%H%M%S", tm) == 0) {
+			i_strocpy(timestamp, dec2str(ioloop_time),
+				  sizeof(timestamp));
+		}
+		destname = t_strconcat(name, "-", timestamp, NULL);
+	}
 
 	/* first move the actual mailbox */
-	dest_ns = get_lazy_ns(list->ns->user, LAZY_NAMESPACE_DELETE);
 	if ((ret = mailbox_move(list, name, dest_ns->list, &destname)) < 0)
 		return -1;
 	if (ret == 0) {
@@ -334,10 +423,18 @@ lazy_expunge_mailbox_list_delete(struct 
 		return -1;
 	}
 
+	if (expunge_ns == dest_ns) {
+		llist->deleting = TRUE;
+		(void)mailbox_move_all_mails(dest_ns->list, destname, name);
+		llist->deleting = FALSE;
+	}
+
 	/* next move the expunged messages mailbox, if it exists */
-	src_ns = get_lazy_ns(list->ns->user, LAZY_NAMESPACE_EXPUNGE);
 	dest_ns = get_lazy_ns(list->ns->user, LAZY_NAMESPACE_DELETE_EXPUNGE);
-	(void)mailbox_move(src_ns->list, name, dest_ns->list, &destname);
+	if (expunge_ns != dest_ns) {
+		(void)mailbox_move(expunge_ns->list, name,
+				   dest_ns->list, &destname);
+	}
 	return 0;
 }
 
@@ -353,7 +450,7 @@ static void lazy_expunge_mail_namespace_
 	/* if this is one of our internal namespaces, mark it as such before
 	   quota plugin sees it */
 	p = t_strsplit_spaces(luser->env, " ");
-	for (i = 0; i < LAZY_NAMESPACE_COUNT; i++, p++) {
+	for (i = 0; i < LAZY_NAMESPACE_COUNT && *p != NULL; i++, p++) {
 		if (strcmp(ns->prefix, *p) == 0) {
 			ns->flags |= NAMESPACE_FLAG_NOQUOTA;
 			break;
@@ -383,11 +480,8 @@ lazy_expunge_mail_namespaces_created(str
 		return;
 
 	p = t_strsplit_spaces(luser->env, " ");
-	for (i = 0; i < LAZY_NAMESPACE_COUNT; i++, p++) {
+	for (i = 0; i < LAZY_NAMESPACE_COUNT && *p != NULL; i++, p++) {
 		const char *name = *p;
-
-		if (name == NULL)
-			i_fatal("lazy_expunge: Missing namespace #%d", i + 1);
 
 		luser->lazy_ns[i] =
 			mail_namespace_find_prefix(namespaces, name);
@@ -399,6 +493,10 @@ lazy_expunge_mail_namespaces_created(str
 		llist = LAZY_EXPUNGE_LIST_CONTEXT(luser->lazy_ns[i]->list);
 		llist->internal_namespace = TRUE;
 	}
+	if (i == 0)
+		i_fatal("lazy_expunge: No namespaces defined");
+	for (; i < LAZY_NAMESPACE_COUNT; i++)
+		luser->lazy_ns[i] = luser->lazy_ns[i-1];
 }
 
 static void lazy_expunge_mail_user_created(struct mail_user *user)


More information about the dovecot-cvs mailing list