dovecot-1.2: lazy-expunge: Support a single-namespace configurat...
dovecot at dovecot.org
dovecot at dovecot.org
Mon Dec 14 22:12:32 EET 2009
details: http://hg.dovecot.org/dovecot-1.2/rev/09bed694c6ca
changeset: 9506:09bed694c6ca
user: Timo Sirainen <tss at iki.fi>
date: Mon Dec 14 15:12:18 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(+), 17 deletions(-)
src/plugins/lazy-expunge/lazy-expunge-plugin.c | 133 ++++++++++++++++++++----
diffs (209 lines):
diff -r 5e2206e3c750 -r 09bed694c6ca src/plugins/lazy-expunge/lazy-expunge-plugin.c
--- a/src/plugins/lazy-expunge/lazy-expunge-plugin.c Thu Dec 10 13:28:02 2009 -0500
+++ b/src/plugins/lazy-expunge/lazy-expunge-plugin.c Mon Dec 14 15:12:18 2009 -0500
@@ -8,6 +8,7 @@
#include "mkdir-parents.h"
#include "maildir-storage.h"
#include "mail-namespace.h"
+#include "mail-search-build.h"
#include "lazy-expunge-plugin.h"
#include <stdio.h>
@@ -41,6 +42,7 @@ struct lazy_expunge_mailbox_list {
union mailbox_list_module_context module_ctx;
struct mail_storage *storage;
+ bool deleting;
};
struct lazy_expunge_mail_storage {
@@ -465,6 +467,86 @@ mailbox_move(struct mailbox_list *src_li
}
static int
+mailbox_move_all_mails(struct mailbox_list *list,
+ const char *src_name, const char *dest_name)
+{
+ struct mail_storage *storage = list->ns->storage;
+ 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;
+ struct mail_keywords *keywords;
+ const char *const *keywords_list;
+ const char *errstr;
+ enum mail_error error;
+ int ret;
+
+ dest_box = mailbox_open(&storage, dest_name, NULL, 0);
+ if (dest_box == NULL) {
+ errstr = mail_storage_get_last_error(storage, &error);
+ i_error("lazy_expunge: Couldn't open DELETE dest mailbox "
+ "%s: %s", dest_name, errstr);
+ return -1;
+ }
+
+ src_box = mailbox_open(&storage, src_name, NULL,
+ MAILBOX_OPEN_KEEP_LOCKED);
+ if (src_box == NULL) {
+ errstr = mail_storage_get_last_error(storage, &error);
+ 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) {
+ keywords_list = mail_get_keywords(mail);
+ keywords = str_array_length(keywords_list) == 0 ? NULL :
+ mailbox_keywords_create_valid(dest_box, keywords_list);
+
+ save_ctx = mailbox_save_alloc(dest_trans);
+ mailbox_save_set_flags(save_ctx,
+ mail_get_flags(mail) & ~MAIL_DELETED,
+ keywords);
+ ret = mailbox_copy(&save_ctx, mail);
+ mailbox_keywords_free(dest_box, &keywords);
+
+ if (ret < 0 && !mail->expunged)
+ 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
lazy_expunge_mailbox_list_delete(struct mailbox_list *list, const char *name)
{
struct lazy_expunge_mail_user *luser =
@@ -472,14 +554,14 @@ lazy_expunge_mailbox_list_delete(struct
struct lazy_expunge_mailbox_list *llist =
LAZY_EXPUNGE_LIST_CONTEXT(list);
struct lazy_expunge_mail_storage *lstorage;
- struct mailbox_list *dest_list;
+ struct mailbox_list *dest_list, *expunge_list;
enum mailbox_name_status status;
const char *destname;
struct tm *tm;
char timestamp[256];
int ret;
- if (llist->storage == NULL) {
+ if (llist->storage == NULL || llist->deleting) {
/* not a maildir storage */
return llist->module_ctx.super.delete_mailbox(list, name);
}
@@ -503,14 +585,25 @@ 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_list = luser->lazy_ns[LAZY_NAMESPACE_EXPUNGE]->storage->list;
+ dest_list = luser->lazy_ns[LAZY_NAMESPACE_DELETE]->storage->list;
+
+ if (expunge_list == dest_list) {
+ /* 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_list = luser->lazy_ns[LAZY_NAMESPACE_DELETE]->storage->list;
if ((ret = mailbox_move(list, name, dest_list, &destname)) < 0)
return -1;
if (ret == 0) {
@@ -519,11 +612,16 @@ lazy_expunge_mailbox_list_delete(struct
return -1;
}
+ if (expunge_list == dest_list && strcmp(destname, name) != 0) {
+ llist->deleting = TRUE;
+ (void)mailbox_move_all_mails(dest_list, destname, name);
+ llist->deleting = FALSE;
+ }
+
/* next move the expunged messages mailbox, if it exists */
- list = luser->lazy_ns[LAZY_NAMESPACE_EXPUNGE]->storage->list;
- dest_list =
- luser->lazy_ns[LAZY_NAMESPACE_DELETE_EXPUNGE]->storage->list;
- (void)mailbox_move(list, name, dest_list, &destname);
+ dest_list = luser->lazy_ns[LAZY_NAMESPACE_DELETE_EXPUNGE]->storage->list;
+ if (expunge_list != dest_list)
+ (void)mailbox_move(expunge_list, name, dest_list, &destname);
return 0;
}
@@ -538,7 +636,7 @@ static void lazy_expunge_mail_storage_in
/* if this is one of our internal storages, mark it as such before
quota plugin sees it */
p = t_strsplit_spaces(getenv("LAZY_EXPUNGE"), " ");
- for (i = 0; i < LAZY_NAMESPACE_COUNT; i++, p++) {
+ for (i = 0; i < LAZY_NAMESPACE_COUNT && *p != NULL; i++, p++) {
if (strcmp(storage->ns->prefix, *p) == 0) {
storage->ns->flags |= NAMESPACE_FLAG_NOQUOTA;
break;
@@ -588,11 +686,8 @@ lazy_expunge_hook_mail_namespaces_create
int i;
p = t_strsplit_spaces(getenv("LAZY_EXPUNGE"), " ");
- 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);
@@ -608,6 +703,10 @@ lazy_expunge_hook_mail_namespaces_create
lstorage = LAZY_EXPUNGE_CONTEXT(luser->lazy_ns[i]->storage);
lstorage->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];
if (lazy_expunge_next_hook_mail_namespaces_created != NULL)
lazy_expunge_next_hook_mail_namespaces_created(namespaces);
More information about the dovecot-cvs
mailing list