lazy-expunge-plugin.c revision 0b7a8f6c6d61d51d86adfbe56f0397dafd34960c
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte/* Copyright (c) 2006-2009 Dovecot authors, see the included COPYING file */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte MODULE_CONTEXT(obj, lazy_expunge_mail_storage_module)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte MODULE_CONTEXT(obj, lazy_expunge_mailbox_list_module)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte MODULE_CONTEXT(obj, lazy_expunge_mail_user_module)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte struct mail_namespace *lazy_ns[LAZY_NAMESPACE_COUNT];
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte const char *env;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte union mailbox_transaction_module_context module_ctx;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forteconst char *lazy_expunge_plugin_version = PACKAGE_VERSION;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic MODULE_CONTEXT_DEFINE_INIT(lazy_expunge_mail_storage_module,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic MODULE_CONTEXT_DEFINE_INIT(lazy_expunge_mail_module,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic MODULE_CONTEXT_DEFINE_INIT(lazy_expunge_mailbox_list_module,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic MODULE_CONTEXT_DEFINE_INIT(lazy_expunge_mail_user_module,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic struct mailbox *
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortemailbox_open_or_create(struct mailbox_list *list, const char *name,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte const char **error_r)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte box = mailbox_alloc(list, name, NULL, MAILBOX_FLAG_KEEP_RECENT |
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte *error_r = mail_storage_get_last_error(mailbox_get_storage(box),
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* try creating and re-opening it. */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte storage = mail_namespace_get_default_storage(list->ns);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte *error_r = mail_storage_get_last_error(mailbox_get_storage(box),
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic struct mail_namespace *
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forteget_lazy_ns(struct mail_user *user, enum lazy_namespace type)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte struct lazy_expunge_mail_user *luser = LAZY_EXPUNGE_USER_CONTEXT(user);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic void lazy_expunge_mail_expunge(struct mail *_mail)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte struct mail_namespace *ns = _mail->box->list->ns;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte struct mail_private *mail = (struct mail_private *)_mail;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte union mail_module_context *mmail = LAZY_EXPUNGE_MAIL_CONTEXT(mail);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte const char *error;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte dest_ns = get_lazy_ns(ns->user, LAZY_NAMESPACE_EXPUNGE);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte lt->dest_box = mailbox_open_or_create(dest_ns->list,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "lazy_expunge: Couldn't open expunge mailbox: "
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (mailbox_sync(lt->dest_box, 0, 0, NULL) < 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "lazy_expunge: Couldn't sync expunge mailbox");
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte lt->dest_trans = mailbox_transaction_begin(lt->dest_box,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (mailbox_copy(&save_ctx, _mail) < 0 && !_mail->expunged)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortelazy_expunge_transaction_begin(struct mailbox *box,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte union mailbox_module_context *mbox = LAZY_EXPUNGE_CONTEXT(box);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte MODULE_CONTEXT_SET(t, lazy_expunge_mail_storage_module, lt);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic void lazy_expunge_transaction_free(struct lazy_expunge_transaction *lt)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortelazy_expunge_transaction_commit(struct mailbox_transaction_context *ctx,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte struct mail_transaction_commit_changes *changes_r)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte union mailbox_module_context *mbox = LAZY_EXPUNGE_CONTEXT(ctx->box);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte struct lazy_expunge_transaction *lt = LAZY_EXPUNGE_CONTEXT(ctx);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (mailbox_transaction_commit(<->dest_trans) < 0)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte ret = mbox->super.transaction_commit(ctx, changes_r);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortelazy_expunge_transaction_rollback(struct mailbox_transaction_context *ctx)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte union mailbox_module_context *mbox = LAZY_EXPUNGE_CONTEXT(ctx->box);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte struct lazy_expunge_transaction *lt = LAZY_EXPUNGE_CONTEXT(ctx);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic struct mail *
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortelazy_expunge_mail_alloc(struct mailbox_transaction_context *t,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte struct mailbox_header_lookup_ctx *wanted_headers)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte union mailbox_module_context *mbox = LAZY_EXPUNGE_CONTEXT(t->box);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte _mail = mbox->super.mail_alloc(t, wanted_fields, wanted_headers);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte mmail = p_new(mail->pool, union mail_module_context, 1);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte MODULE_CONTEXT_SET_SELF(mail, lazy_expunge_mail_module, mmail);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic void lazy_expunge_mailbox_allocated(struct mailbox *box)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (llist != NULL && !llist->internal_namespace) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte mbox = p_new(box->pool, union mailbox_module_context, 1);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte box->v.transaction_begin = lazy_expunge_transaction_begin;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte box->v.transaction_commit = lazy_expunge_transaction_commit;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte box->v.transaction_rollback = lazy_expunge_transaction_rollback;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte MODULE_CONTEXT_SET_SELF(box, lazy_expunge_mail_storage_module,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortemailbox_move(struct mailbox_list *src_list, const char *src_name,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte struct mailbox_list *dest_list, const char **_dest_name)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte const char *dir, *origin, *dest_name = *_dest_name;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* make sure the destination root directory exists */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte mailbox_list_get_dir_permissions(dest_list, NULL, &mode, &gid, &origin);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte dir = mailbox_list_get_path(dest_list, NULL, MAILBOX_LIST_PATH_TYPE_DIR);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (mkdir_parents_chgrp(dir, mode, gid, origin) < 0 &&
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte while (mailbox_list_rename_mailbox(src_list, src_name,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* mailbox is being deleted multiple times per second.
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte update the filename. */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte dest_name = t_strdup_printf("%s-%04u", *_dest_name,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte struct mailbox_transaction_context *src_trans, *dest_trans;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte const char *errstr;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte dest_box = mailbox_alloc(list, dest_name, NULL, 0);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte errstr = mail_storage_get_last_error(dest_box->storage, &error);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte i_error("lazy_expunge: Couldn't open DELETE dest mailbox "
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte src_box = mailbox_alloc(list, src_name, NULL, MAILBOX_FLAG_KEEP_LOCKED);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte errstr = mail_storage_get_last_error(src_box->storage, &error);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte i_error("lazy_expunge: Couldn't open DELETE source mailbox "
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte src_trans = mailbox_transaction_begin(src_box, 0);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte search_ctx = mailbox_search_init(src_trans, search_args, NULL);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte while ((ret = mailbox_search_next(search_ctx, mail)) > 0) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte ret = mailbox_list_delete_mailbox(list, src_name);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortelazy_expunge_mailbox_list_delete(struct mailbox_list *list, const char *name)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (llist->internal_namespace || llist->deleting)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte return llist->module_ctx.super.delete_mailbox(list, name);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* first do the normal sanity checks */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte mailbox_list_set_error(list, MAIL_ERROR_NOTPOSSIBLE,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "INBOX can't be deleted.");
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (mailbox_list_get_mailbox_name_status(list, name, &status) < 0)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "Invalid mailbox name");
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte expunge_ns = get_lazy_ns(list->ns->user, LAZY_NAMESPACE_EXPUNGE);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte dest_ns = get_lazy_ns(list->ns->user, LAZY_NAMESPACE_DELETE);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* if there are no expunged messages in this mailbox,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte we can simply rename the mailbox to the destination name */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* destination mailbox name needs to contain a timestamp */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte destname = t_strconcat(name, "-", timestamp, NULL);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* first move the actual mailbox */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if ((ret = mailbox_move(list, name, dest_ns->list, &destname)) < 0)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte mailbox_list_set_error(list, MAIL_ERROR_NOTFOUND,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte (void)mailbox_move_all_mails(dest_ns->list, destname, name);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* next move the expunged messages mailbox, if it exists */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte dest_ns = get_lazy_ns(list->ns->user, LAZY_NAMESPACE_DELETE_EXPUNGE);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic void lazy_expunge_mail_namespace_storage_added(struct mail_namespace *ns)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte const char *const *p;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte unsigned int i;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* if this is one of our internal namespaces, mark it as such before
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte quota plugin sees it */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (i = 0; i < LAZY_NAMESPACE_COUNT && *p != NULL; i++, p++) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte if (luser != NULL && ns->type == NAMESPACE_PRIVATE) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte llist = p_new(list->pool, struct lazy_expunge_mailbox_list, 1);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte list->v.delete_mailbox = lazy_expunge_mailbox_list_delete;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte MODULE_CONTEXT_SET(list, lazy_expunge_mailbox_list_module,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortelazy_expunge_mail_namespaces_created(struct mail_namespace *namespaces)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte const char *const *p;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (i = 0; i < LAZY_NAMESPACE_COUNT && *p != NULL; i++, p++) {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte const char *name = *p;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte i_fatal("lazy_expunge: Unknown namespace: '%s'", name);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte /* we don't want to override these namespaces' expunge/delete
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte operations. */
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte llist = LAZY_EXPUNGE_LIST_CONTEXT(luser->lazy_ns[i]->list);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte for (; i < LAZY_NAMESPACE_COUNT; i++)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic void lazy_expunge_mail_user_created(struct mail_user *user)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte const char *env;
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte env = mail_user_plugin_getenv(user, "lazy_expunge");
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte luser = p_new(user->pool, struct lazy_expunge_mail_user, 1);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte MODULE_CONTEXT_SET(user, lazy_expunge_mail_user_module, luser);
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte i_debug("lazy_expunge: No lazy_expunge setting - "
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte "plugin disabled");
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortestatic struct mail_storage_hooks lazy_expunge_mail_storage_hooks = {
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte .mail_user_created = lazy_expunge_mail_user_created,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte .mail_namespaces_created = lazy_expunge_mail_namespaces_created,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte .mail_namespace_storage_added = lazy_expunge_mail_namespace_storage_added,
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte .mailbox_allocated = lazy_expunge_mailbox_allocated
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Fortevoid lazy_expunge_plugin_init(struct module *module)
fcf3ce441efd61da9bb2884968af01cb7c1452ccJohn Forte mail_storage_hooks_add(module, &lazy_expunge_mail_storage_hooks);