lazy-expunge-plugin.c revision 462a3d92adcde4bfa9a575875bd8ae740b89ce9e
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki/* Copyright (c) 2006-2018 Dovecot authors, see the included COPYING file */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki#include "lib.h"
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki#include "ioloop.h"
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki#include "array.h"
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki#include "str.h"
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki#include "hash.h"
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki#include "seq-range-array.h"
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki#include "mkdir-parents.h"
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki#include "mail-storage-private.h"
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki#include "mail-search-build.h"
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki#include "mailbox-list-private.h"
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki#include "mail-namespace.h"
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki#include "lazy-expunge-plugin.h"
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki#include <stdio.h>
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki#include <unistd.h>
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki#include <dirent.h>
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki#include <time.h>
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki#define LAZY_EXPUNGE_CONTEXT(obj) \
c659a04853561c3116d88e04931a181bc13559acMichael Bergknoff MODULE_CONTEXT(obj, lazy_expunge_mail_storage_module)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki#define LAZY_EXPUNGE_CONTEXT_REQUIRE(obj) \
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki MODULE_CONTEXT_REQUIRE(obj, lazy_expunge_mail_storage_module)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki#define LAZY_EXPUNGE_LIST_CONTEXT(obj) \
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki MODULE_CONTEXT(obj, lazy_expunge_mailbox_list_module)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki#define LAZY_EXPUNGE_USER_CONTEXT(obj) \
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki MODULE_CONTEXT(obj, lazy_expunge_mail_user_module)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki#define LAZY_EXPUNGE_MAIL_CONTEXT(obj) \
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki MODULE_CONTEXT(obj, lazy_expunge_mail_module)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistruct lazy_expunge_mail {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki union mail_module_context module_ctx;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki bool moving;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki bool recursing;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki};
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistruct lazy_expunge_mail_user {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki union mail_user_module_context module_ctx;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct mail_namespace *lazy_ns;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki const char *lazy_mailbox_vname;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki const char *env;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki bool copy_only_last_instance;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki};
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistruct lazy_expunge_mailbox_list {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki union mailbox_list_module_context module_ctx;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki bool allow_rename:1;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki bool internal_namespace:1;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki};
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistruct lazy_expunge_transaction {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki union mailbox_transaction_module_context module_ctx;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct mailbox *dest_box;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct mailbox_transaction_context *dest_trans;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki pool_t pool;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki HASH_TABLE(const char *, void *) guids;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki char *delayed_errstr;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki char *delayed_internal_errstr;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki enum mail_error delayed_error;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki bool copy_only_last_instance;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki};
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkiconst char *lazy_expunge_plugin_version = DOVECOT_ABI_VERSION;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic MODULE_CONTEXT_DEFINE_INIT(lazy_expunge_mail_storage_module,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki &mail_storage_module_register);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic MODULE_CONTEXT_DEFINE_INIT(lazy_expunge_mail_module,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki &mail_module_register);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic MODULE_CONTEXT_DEFINE_INIT(lazy_expunge_mailbox_list_module,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki &mailbox_list_module_register);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic MODULE_CONTEXT_DEFINE_INIT(lazy_expunge_mail_user_module,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki &mail_user_module_register);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic const char *
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkiget_dest_vname(struct mailbox_list *list, struct mailbox *src_box)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki{
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct lazy_expunge_mail_user *luser =
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki LAZY_EXPUNGE_USER_CONTEXT(list->ns->user);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki const char *name;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki char src_sep, dest_sep;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (luser->lazy_mailbox_vname != NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return luser->lazy_mailbox_vname;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /* use the (canonical / unaliased) storage name */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki name = src_box->name;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /* replace hierarchy separators with destination virtual separator */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki src_sep = mailbox_list_get_hierarchy_sep(src_box->list);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki dest_sep = mail_namespace_get_sep(list->ns);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (src_sep != dest_sep) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki string_t *str = t_str_new(128);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki unsigned int i;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki for (i = 0; name[i] != '\0'; i++) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (name[i] == src_sep)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki str_append_c(str, dest_sep);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki else
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki str_append_c(str, name[i]);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki name = str_c(str);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /* add expunge namespace prefix. the name is now a proper vname */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return t_strconcat(list->ns->prefix, name, NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki}
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic struct mailbox *
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkimailbox_open_or_create(struct mailbox_list *list, struct mailbox *src_box,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki const char **error_r)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki{
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct mailbox *box;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki enum mail_error error;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki const char *name;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki name = get_dest_vname(list, src_box);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki box = mailbox_alloc(list, name, MAILBOX_FLAG_NO_INDEX_FILES |
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki MAILBOX_FLAG_SAVEONLY | MAILBOX_FLAG_IGNORE_ACLS);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mailbox_set_reason(box, "lazy_expunge");
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (mailbox_open(box) == 0) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki *error_r = NULL;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return box;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki *error_r = mailbox_get_last_internal_error(box, &error);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (error != MAIL_ERROR_NOTFOUND) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki *error_r = t_strdup_printf("Failed to open mailbox %s: %s",
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki name, *error_r);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mailbox_free(&box);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return NULL;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /* try creating and re-opening it. */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (mailbox_create(box, NULL, FALSE) < 0 &&
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mailbox_get_last_mail_error(box) != MAIL_ERROR_EXISTS) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki *error_r = t_strdup_printf("Failed to create mailbox %s: %s", name,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mailbox_get_last_internal_error(box, NULL));
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mailbox_free(&box);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return NULL;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (mailbox_open(box) < 0) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki *error_r = t_strdup_printf("Failed to open created mailbox %s: %s", name,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mailbox_get_last_internal_error(box, NULL));
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mailbox_free(&box);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return NULL;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return box;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki}
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic unsigned int
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkilazy_expunge_count_in_transaction(struct lazy_expunge_transaction *lt,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki const char *guid)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki{
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki void *refcountp;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki unsigned int refcount;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (lt->pool == NULL) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki lt->pool = pool_alloconly_create("lazy expunge transaction",
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki 1024);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki hash_table_create(&lt->guids, lt->pool, 0, str_hash, strcmp);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki refcountp = hash_table_lookup(lt->guids, guid);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki refcount = POINTER_CAST_TO(refcountp, unsigned int) + 1;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki refcountp = POINTER_CAST(refcount);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (refcount == 1) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki guid = p_strdup(lt->pool, guid);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki hash_table_insert(lt->guids, guid, refcountp);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki } else {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki hash_table_update(lt->guids, guid, refcountp);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return refcount-1;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki}
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic int lazy_expunge_mail_is_last_instance(struct mail *_mail)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki{
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct lazy_expunge_transaction *lt =
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki LAZY_EXPUNGE_CONTEXT_REQUIRE(_mail->transaction);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki const char *value, *errstr;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki unsigned long refcount;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki enum mail_error error;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (mail_get_special(_mail, MAIL_FETCH_REFCOUNT, &value) < 0) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki errstr = mailbox_get_last_internal_error(_mail->box, &error);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (error == MAIL_ERROR_EXPUNGED) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /* already expunged - just ignore it */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return 0;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mail_set_critical(_mail,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki "lazy_expunge: Couldn't lookup message's refcount: %s",
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki errstr);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return -1;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (*value == '\0') {
193974072f41a843678abf5f61979c748687e66bSherry Moore /* refcounts not supported by backend. assume all mails are
193974072f41a843678abf5f61979c748687e66bSherry Moore the last instance. */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return 1;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (str_to_ulong(value, &refcount) < 0)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki i_panic("Invalid mail refcount number: %s", value);
193974072f41a843678abf5f61979c748687e66bSherry Moore if (refcount > 1) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /* this probably isn't the last instance of the mail, but
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki it's possible that the same mail was copied to this mailbox
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki multiple times and we're deleting more than one instance
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki within this transaction. in those cases each expunge will
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki see the same refcount, so we need to adjust the refcount
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki by tracking the expunged message GUIDs. */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (mail_get_special(_mail, MAIL_FETCH_GUID, &value) < 0) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki errstr = mailbox_get_last_internal_error(_mail->box, &error);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (error == MAIL_ERROR_EXPUNGED) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /* already expunged - just ignore it */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return 0;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mail_set_critical(_mail,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki "lazy_expunge: Couldn't lookup message's GUID: %s", errstr);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return -1;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (*value == '\0') {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /* GUIDs not supported by backend, but refcounts are?
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki not with our current backends. */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mail_set_critical(_mail,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki "lazy_expunge: Message unexpectedly has no GUID");
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return -1;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki refcount -= lazy_expunge_count_in_transaction(lt, value);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return refcount <= 1 ? 1 : 0;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki}
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic bool lazy_expunge_is_internal_mailbox(struct mailbox *box)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki{
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct mail_namespace *ns = box->list->ns;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct lazy_expunge_mail_user *luser =
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki LAZY_EXPUNGE_USER_CONTEXT(ns->user);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct lazy_expunge_mailbox_list *llist =
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki LAZY_EXPUNGE_LIST_CONTEXT(box->list);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (luser == NULL || llist == NULL) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /* lazy_expunge not enabled at all */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return FALSE;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (llist->internal_namespace) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /* lazy-expunge namespace */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return TRUE;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (luser->lazy_mailbox_vname != NULL &&
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki strcmp(luser->lazy_mailbox_vname, box->vname) == 0) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /* lazy-expunge mailbox */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return TRUE;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return FALSE;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki}
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic void lazy_expunge_set_error(struct lazy_expunge_transaction *lt,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct mail_storage *storage)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki{
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki const char *errstr;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki enum mail_error error;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki errstr = mail_storage_get_last_error(storage, &error);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (error == MAIL_ERROR_EXPUNGED) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /* expunging failed because the mail was already expunged.
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki we don't want to fail because of that. */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (lt->delayed_error != MAIL_ERROR_NONE)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki lt->delayed_error = error;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki lt->delayed_errstr = i_strdup(errstr);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki lt->delayed_internal_errstr =
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki i_strdup(mail_storage_get_last_internal_error(storage, NULL));
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki}
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic void lazy_expunge_mail_expunge(struct mail *_mail)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki{
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct mail_namespace *ns = _mail->box->list->ns;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct lazy_expunge_mail_user *luser =
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki LAZY_EXPUNGE_USER_CONTEXT(ns->user);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct mail_private *mail = (struct mail_private *)_mail;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct lazy_expunge_mail *mmail = LAZY_EXPUNGE_MAIL_CONTEXT(mail);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct lazy_expunge_transaction *lt =
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki LAZY_EXPUNGE_CONTEXT_REQUIRE(_mail->transaction);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct mail *real_mail;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct mail_save_context *save_ctx;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki const char *error;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki bool moving = mmail->moving;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki int ret;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki i_assert(luser != NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki i_assert(mmail != NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (lt->delayed_error != MAIL_ERROR_NONE)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (mmail->recursing) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mmail->module_ctx.super.expunge(_mail);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /* Clear this in case the mail is used for non-move later on. */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mmail->moving = FALSE;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /* don't copy the mail if we're expunging from lazy_expunge
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki namespace (even if it's via a virtual mailbox) */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (mail_get_backend_mail(_mail, &real_mail) < 0) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki lazy_expunge_set_error(lt, _mail->box->storage);
ece6eed9d93d19d2c26893d5ac4fd2f73b1633dcfw return;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (lazy_expunge_is_internal_mailbox(real_mail->box)) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mmail->module_ctx.super.expunge(_mail);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (lt->copy_only_last_instance) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /* we want to copy only the last instance of the mail to
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki lazy_expunge namespace. other instances will be expunged
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki immediately. */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (moving)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki ret = 0;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki else if ((ret = lazy_expunge_mail_is_last_instance(_mail)) < 0) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki lazy_expunge_set_error(lt, _mail->box->storage);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (ret == 0) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mmail->module_ctx.super.expunge(_mail);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (lt->dest_box == NULL) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki lt->dest_box = mailbox_open_or_create(luser->lazy_ns->list,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki _mail->box, &error);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (lt->dest_box == NULL) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mail_set_critical(_mail,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki "lazy_expunge: Couldn't open expunge mailbox: "
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki "%s", error);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki lazy_expunge_set_error(lt, _mail->box->storage);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (mailbox_sync(lt->dest_box, 0) < 0) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mail_set_critical(_mail,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki "lazy_expunge: Couldn't sync expunge mailbox");
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki lazy_expunge_set_error(lt, lt->dest_box->storage);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mailbox_free(&lt->dest_box);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki lt->dest_trans = mailbox_transaction_begin(lt->dest_box,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki MAILBOX_TRANSACTION_FLAG_EXTERNAL,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki __func__);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki save_ctx = mailbox_save_alloc(lt->dest_trans);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mailbox_save_copy_flags(save_ctx, _mail);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki save_ctx->data.flags &= ~MAIL_DELETED;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mmail->recursing = TRUE;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (mailbox_move(&save_ctx, _mail) < 0 && !_mail->expunged)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki lazy_expunge_set_error(lt, lt->dest_box->storage);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mmail->recursing = FALSE;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki}
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic int lazy_expunge_copy(struct mail_save_context *ctx, struct mail *_mail)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki{
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct mail_private *mail = (struct mail_private *)_mail;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki union mailbox_module_context *mbox =
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki LAZY_EXPUNGE_CONTEXT_REQUIRE(ctx->transaction->box);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct lazy_expunge_mail *mmail = LAZY_EXPUNGE_MAIL_CONTEXT(mail);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (mmail != NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mmail->moving = ctx->moving;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return mbox->super.copy(ctx, _mail);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki}
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic struct mailbox_transaction_context *
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkilazy_expunge_transaction_begin(struct mailbox *box,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki enum mailbox_transaction_flags flags,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki const char *reason)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki{
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct lazy_expunge_mail_user *luser =
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki LAZY_EXPUNGE_USER_CONTEXT(box->list->ns->user);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki union mailbox_module_context *mbox = LAZY_EXPUNGE_CONTEXT_REQUIRE(box);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct mailbox_transaction_context *t;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct lazy_expunge_transaction *lt;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki i_assert(luser != NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki t = mbox->super.transaction_begin(box, flags, reason);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki lt = i_new(struct lazy_expunge_transaction, 1);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki lt->copy_only_last_instance = luser->copy_only_last_instance;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki MODULE_CONTEXT_SET(t, lazy_expunge_mail_storage_module, lt);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return t;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki}
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic void lazy_expunge_transaction_free(struct lazy_expunge_transaction *lt)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki{
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (lt->dest_trans != NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mailbox_transaction_rollback(&lt->dest_trans);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (lt->dest_box != NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mailbox_free(&lt->dest_box);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (hash_table_is_created(lt->guids))
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki hash_table_destroy(&lt->guids);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki pool_unref(&lt->pool);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki i_free(lt->delayed_errstr);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki i_free(lt->delayed_internal_errstr);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki i_free(lt);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki}
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic int
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkilazy_expunge_transaction_commit(struct mailbox_transaction_context *ctx,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct mail_transaction_commit_changes *changes_r)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki{
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki union mailbox_module_context *mbox = LAZY_EXPUNGE_CONTEXT_REQUIRE(ctx->box);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct lazy_expunge_transaction *lt = LAZY_EXPUNGE_CONTEXT_REQUIRE(ctx);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki int ret;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (lt->dest_trans != NULL && lt->delayed_error == MAIL_ERROR_NONE) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (mailbox_transaction_commit(&lt->dest_trans) < 0) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki lazy_expunge_set_error(lt, ctx->box->storage);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (lt->delayed_error == MAIL_ERROR_NONE)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki ret = mbox->super.transaction_commit(ctx, changes_r);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki else if (lt->delayed_error != MAIL_ERROR_TEMP) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mail_storage_set_error(ctx->box->storage, lt->delayed_error,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki lt->delayed_errstr);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mbox->super.transaction_rollback(ctx);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki ret = -1;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki } else {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mailbox_set_critical(ctx->box,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki "Lazy-expunge transaction failed: %s",
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki lt->delayed_internal_errstr);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mbox->super.transaction_rollback(ctx);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki ret = -1;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki lazy_expunge_transaction_free(lt);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return ret;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki}
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic void
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkilazy_expunge_transaction_rollback(struct mailbox_transaction_context *ctx)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki{
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki union mailbox_module_context *mbox = LAZY_EXPUNGE_CONTEXT_REQUIRE(ctx->box);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct lazy_expunge_transaction *lt = LAZY_EXPUNGE_CONTEXT_REQUIRE(ctx);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mbox->super.transaction_rollback(ctx);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki lazy_expunge_transaction_free(lt);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki}
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic void lazy_expunge_mail_allocated(struct mail *_mail)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki{
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct lazy_expunge_transaction *lt =
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki LAZY_EXPUNGE_CONTEXT(_mail->transaction);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct mail_private *mail = (struct mail_private *)_mail;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct mail_vfuncs *v = mail->vlast;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct lazy_expunge_mail *mmail;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (lt == NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mmail = p_new(mail->pool, struct lazy_expunge_mail, 1);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mmail->module_ctx.super = *v;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mail->vlast = &mmail->module_ctx.super;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki v->expunge = lazy_expunge_mail_expunge;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki MODULE_CONTEXT_SET(mail, lazy_expunge_mail_module, mmail);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki}
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic int
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkilazy_expunge_mailbox_rename(struct mailbox *src, struct mailbox *dest)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki{
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki union mailbox_module_context *lbox = LAZY_EXPUNGE_CONTEXT_REQUIRE(src);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct lazy_expunge_mailbox_list *src_llist =
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki LAZY_EXPUNGE_LIST_CONTEXT(src->list);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct lazy_expunge_mailbox_list *dest_llist =
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki LAZY_EXPUNGE_LIST_CONTEXT(dest->list);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki i_assert(src_llist != NULL && dest_llist != NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (!src_llist->allow_rename &&
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki (src_llist->internal_namespace ||
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki dest_llist->internal_namespace)) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mail_storage_set_error(src->storage, MAIL_ERROR_NOTPOSSIBLE,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki "Can't rename mailboxes to/from expunge namespace.");
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return -1;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return lbox->super.rename_box(src, dest);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki}
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic void lazy_expunge_mailbox_allocated(struct mailbox *box)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki{
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct lazy_expunge_mailbox_list *llist =
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki LAZY_EXPUNGE_LIST_CONTEXT(box->list);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki union mailbox_module_context *mbox;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct mailbox_vfuncs *v = box->vlast;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (llist == NULL || (box->flags & MAILBOX_FLAG_DELETE_UNSAFE) != 0)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mbox = p_new(box->pool, union mailbox_module_context, 1);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mbox->super = *v;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki box->vlast = &mbox->super;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki MODULE_CONTEXT_SET_SELF(box, lazy_expunge_mail_storage_module, mbox);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (!lazy_expunge_is_internal_mailbox(box)) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki v->copy = lazy_expunge_copy;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki v->transaction_begin = lazy_expunge_transaction_begin;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki v->transaction_commit = lazy_expunge_transaction_commit;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki v->transaction_rollback = lazy_expunge_transaction_rollback;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki v->rename_box = lazy_expunge_mailbox_rename;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki } else if (llist->internal_namespace) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki v->rename_box = lazy_expunge_mailbox_rename;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki } else {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /* internal mailbox in a non-internal namespace -
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki don't add any unnecessary restrictions to it. if it's not
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki wanted, just use the ACL plugin. */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki}
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic void lazy_expunge_mailbox_list_created(struct mailbox_list *list)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki{
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct lazy_expunge_mail_user *luser =
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki LAZY_EXPUNGE_USER_CONTEXT(list->ns->user);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct lazy_expunge_mailbox_list *llist;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (luser == NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /* if this is one of our internal namespaces, mark it as such before
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki quota plugin sees it */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (strcmp(list->ns->prefix, luser->env) == 0)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki list->ns->flags |= NAMESPACE_FLAG_NOQUOTA;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (list->ns->type == MAIL_NAMESPACE_TYPE_PRIVATE) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki llist = p_new(list->pool, struct lazy_expunge_mailbox_list, 1);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki MODULE_CONTEXT_SET(list, lazy_expunge_mailbox_list_module,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki llist);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki}
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic void
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkilazy_expunge_mail_namespaces_created(struct mail_namespace *namespaces)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki{
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct lazy_expunge_mail_user *luser =
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki LAZY_EXPUNGE_USER_CONTEXT(namespaces->user);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct lazy_expunge_mailbox_list *llist;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (luser == NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki return;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki luser->lazy_ns = mail_namespace_find_prefix(namespaces, luser->env);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (luser->lazy_ns != NULL) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /* we don't want to override this namespace's expunge operation. */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki llist = LAZY_EXPUNGE_LIST_CONTEXT(luser->lazy_ns->list);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki i_assert(llist != NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki llist->internal_namespace = TRUE;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki } else {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /* store the the expunged mails to the specified mailbox. */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki luser->lazy_ns = mail_namespace_find(namespaces, luser->env);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki luser->lazy_mailbox_vname = luser->env;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mail_namespace_ref(luser->lazy_ns);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki}
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic void lazy_expunge_user_deinit(struct mail_user *user)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki{
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct lazy_expunge_mail_user *luser = LAZY_EXPUNGE_USER_CONTEXT(user);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki i_assert(luser != NULL);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki /* mail_namespaces_created hook isn't necessarily ever called */
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (luser->lazy_ns != NULL)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mail_namespace_unref(&luser->lazy_ns);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki luser->module_ctx.super.deinit(user);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki}
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic void lazy_expunge_mail_user_created(struct mail_user *user)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki{
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct mail_user_vfuncs *v = user->vlast;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki struct lazy_expunge_mail_user *luser;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki const char *env;
ece6eed9d93d19d2c26893d5ac4fd2f73b1633dcfw
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki env = mail_user_plugin_getenv(user, "lazy_expunge");
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki if (env != NULL && env[0] != '\0') {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki luser = p_new(user->pool, struct lazy_expunge_mail_user, 1);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki luser->module_ctx.super = *v;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki user->vlast = &luser->module_ctx.super;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki v->deinit = lazy_expunge_user_deinit;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki luser->env = env;
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki luser->copy_only_last_instance =
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mail_user_plugin_getenv_bool(user, "lazy_expunge_only_last_instance");
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki MODULE_CONTEXT_SET(user, lazy_expunge_mail_user_module, luser);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki } else if (user->mail_debug) {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki i_debug("lazy_expunge: No lazy_expunge setting - "
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki "plugin disabled");
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki }
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki}
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkistatic struct mail_storage_hooks lazy_expunge_mail_storage_hooks = {
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki .mail_user_created = lazy_expunge_mail_user_created,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki .mail_namespaces_created = lazy_expunge_mail_namespaces_created,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki .mailbox_list_created = lazy_expunge_mailbox_list_created,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki .mailbox_allocated = lazy_expunge_mailbox_allocated,
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki .mail_allocated = lazy_expunge_mail_allocated
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki};
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkivoid lazy_expunge_plugin_init(struct module *module)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki{
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mail_storage_hooks_add(module, &lazy_expunge_mail_storage_hooks);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki}
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenkivoid lazy_expunge_plugin_deinit(void)
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki{
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki mail_storage_hooks_remove(&lazy_expunge_mail_storage_hooks);
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki}
0d63ce2b32a9e1cc8ed71d4d92536c44d66a530avenki