Mercurial > dovecot > core-2.2
changeset 10485:b2f31df5f5da HEAD
lazy-expunge: Support a single-namespace configuration.
If a mailbox is deleted, its contents are merged with the existing expunged
messages.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Mon, 14 Dec 2009 14:40:16 -0500 |
parents | 43895027cab9 |
children | bef8da2e6b0c |
files | src/plugins/lazy-expunge/lazy-expunge-plugin.c |
diffstat | 1 files changed, 116 insertions(+), 18 deletions(-) [+] |
line wrap: on
line diff
--- 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 @@ 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_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,22 +288,98 @@ 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 lazy_expunge_mailbox_list_delete(struct mailbox_list *list, const char *name) { 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 @@ 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 @@ 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 @@ /* 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,12 +480,9 @@ 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); if (luser->lazy_ns[i] == NULL) @@ -399,6 +493,10 @@ 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)