From: Josef 'Jeff' Sipek Date: Wed, 9 Dec 2020 14:42:19 +0000 (-0500) Subject: plugins: Remove expire plugin X-Git-Tag: 2.3.14.rc1~211 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=727f9adc5c8a100f20d1b94cadeae6858bfcc7fc;p=thirdparty%2Fdovecot%2Fcore.git plugins: Remove expire plugin The autoexpunge functionality should be used instead. --- diff --git a/configure.ac b/configure.ac index a55642e77a..6da8502ebb 100644 --- a/configure.ac +++ b/configure.ac @@ -889,7 +889,6 @@ src/util/Makefile src/plugins/Makefile src/plugins/acl/Makefile src/plugins/imap-acl/Makefile -src/plugins/expire/Makefile src/plugins/fs-compress/Makefile src/plugins/fts/Makefile src/plugins/fts-lucene/Makefile diff --git a/doc/example-config/dovecot-dict-sql.conf.ext b/doc/example-config/dovecot-dict-sql.conf.ext index a9a903f1ff..35aa107b91 100644 --- a/doc/example-config/dovecot-dict-sql.conf.ext +++ b/doc/example-config/dovecot-dict-sql.conf.ext @@ -21,21 +21,3 @@ map { username_field = username value_field = messages } - -# CREATE TABLE expires ( -# username varchar(100) not null, -# mailbox varchar(255) not null, -# expire_stamp integer not null, -# primary key (username, mailbox) -# ); - -map { - pattern = shared/expire/$user/$mailbox - table = expires - value_field = expire_stamp - - fields { - username = $user - mailbox = $mailbox - } -} diff --git a/doc/example-config/dovecot.conf b/doc/example-config/dovecot.conf index a99d8aa775..b67e9eb4a4 100644 --- a/doc/example-config/dovecot.conf +++ b/doc/example-config/dovecot.conf @@ -89,7 +89,6 @@ dict { #quota = mysql:/etc/dovecot/dovecot-dict-sql.conf.ext - #expire = sqlite:/etc/dovecot/dovecot-dict-sql.conf.ext } # Most of the actual configuration gets included below. The filenames are diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am index e88e3c425a..ab0b9d14f8 100644 --- a/src/plugins/Makefile.am +++ b/src/plugins/Makefile.am @@ -21,7 +21,6 @@ endif SUBDIRS = \ acl \ imap-acl \ - expire \ fts \ fts-squat \ last-login \ diff --git a/src/plugins/expire/Makefile.am b/src/plugins/expire/Makefile.am deleted file mode 100644 index 567772b98a..0000000000 --- a/src/plugins/expire/Makefile.am +++ /dev/null @@ -1,35 +0,0 @@ -doveadm_moduledir = $(moduledir)/doveadm - -AM_CPPFLAGS = \ - -I$(top_srcdir)/src/lib \ - -I$(top_srcdir)/src/lib-auth \ - -I$(top_srcdir)/src/lib-dict \ - -I$(top_srcdir)/src/lib-settings \ - -I$(top_srcdir)/src/lib-master \ - -I$(top_srcdir)/src/lib-mail \ - -I$(top_srcdir)/src/lib-imap \ - -I$(top_srcdir)/src/lib-index \ - -I$(top_srcdir)/src/lib-storage \ - -I$(top_srcdir)/src/lib-storage/index \ - -I$(top_srcdir)/src/doveadm - -NOPLUGIN_LDFLAGS = -lib10_doveadm_expire_plugin_la_LDFLAGS = -module -avoid-version -lib20_expire_plugin_la_LDFLAGS = -module -avoid-version - -module_LTLIBRARIES = \ - lib20_expire_plugin.la - -lib20_expire_plugin_la_SOURCES = \ - expire-set.c \ - expire-plugin.c - -noinst_HEADERS = \ - expire-set.h \ - expire-plugin.h - -doveadm_module_LTLIBRARIES = \ - lib10_doveadm_expire_plugin.la - -lib10_doveadm_expire_plugin_la_SOURCES = \ - doveadm-expire.c diff --git a/src/plugins/expire/doveadm-expire.c b/src/plugins/expire/doveadm-expire.c deleted file mode 100644 index 492f305823..0000000000 --- a/src/plugins/expire/doveadm-expire.c +++ /dev/null @@ -1,458 +0,0 @@ -/* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */ - -#include "lib.h" -#include "module-dir.h" -#include "str.h" -#include "hash.h" -#include "dict.h" -#include "imap-match.h" -#include "expire-set.h" -#include "mail-search.h" -#include "doveadm-settings.h" -#include "doveadm-mail.h" - -#define DOVEADM_EXPIRE_MAIL_CMD_CONTEXT(obj) \ - MODULE_CONTEXT_REQUIRE(obj, doveadm_expire_mail_cmd_module) - -enum expire_user_state { - EXPIRE_USER_STATE_NONEXISTENT = 0, - EXPIRE_USER_STATE_EXISTS = 1, - EXPIRE_USER_STATE_SEEN = 2 -}; - -struct expire_query { - const char *mailbox; - struct imap_match_glob *glob; - time_t before_time; -}; - -struct doveadm_expire_mail_cmd_context { - union doveadm_mail_cmd_module_context module_ctx; - - struct dict *dict; - struct dict_transaction_context *trans; - struct dict_iterate_context *iter; - - /* username => enum expire_user_state */ - HASH_TABLE(char *, void *) user_states; - ARRAY(struct expire_query) queries; - time_t oldest_before_time; - bool delete_nonexistent_users; -}; - -const char *doveadm_expire_plugin_version = DOVECOT_ABI_VERSION; - -void doveadm_expire_plugin_init(struct module *module); -void doveadm_expire_plugin_deinit(void); - -static MODULE_CONTEXT_DEFINE_INIT(doveadm_expire_mail_cmd_module, - &doveadm_mail_cmd_module_register); -static void (*next_hook_doveadm_mail_init)(struct doveadm_mail_cmd_context *ctx); - -static bool -doveadm_expire_mail_match_mailbox(struct doveadm_expire_mail_cmd_context *ectx, - const char *mailbox, time_t oldest_savedate) -{ - const struct expire_query *query; - - array_foreach(&ectx->queries, query) { - if (oldest_savedate >= query->before_time) - continue; - - if (query->glob == NULL) { - if (strcmp(query->mailbox, mailbox) == 0) - return TRUE; - } else { - if (imap_match(query->glob, mailbox) == IMAP_MATCH_YES) - return TRUE; - } - } - return FALSE; -} - -static int -doveadm_expire_mail_want(struct doveadm_mail_cmd_context *ctx, - const char *dict_key, time_t oldest_savedate, - const char **username_r) -{ - struct doveadm_expire_mail_cmd_context *ectx = - DOVEADM_EXPIRE_MAIL_CMD_CONTEXT(ctx); - const char *username, *mailbox; - enum expire_user_state state; - char *orig_username; - void *value; - - /* dict_key = DICT_EXPIRE_PREFIX/ */ - username = dict_key + strlen(DICT_EXPIRE_PREFIX); - mailbox = strchr(username, '/'); - if (mailbox == NULL) { - /* invalid record, ignore */ - i_error("expire: Invalid key: %s", dict_key); - return -1; - } - username = t_strdup_until(username, mailbox++); - - if (!hash_table_lookup_full(ectx->user_states, username, - &orig_username, &value)) { - /* user no longer exists, delete the record */ - return -1; - } - state = POINTER_CAST_TO(value, enum expire_user_state); - switch (state) { - case EXPIRE_USER_STATE_NONEXISTENT: - i_unreached(); - case EXPIRE_USER_STATE_EXISTS: - break; - case EXPIRE_USER_STATE_SEEN: - /* seen this user already, skip the record */ - return 0; - } - - if (!doveadm_expire_mail_match_mailbox(ectx, mailbox, - oldest_savedate)) { - /* this mailbox doesn't have any matching messages */ - return 0; - } - state = EXPIRE_USER_STATE_SEEN; - hash_table_update(ectx->user_states, orig_username, - POINTER_CAST(state)); - *username_r = orig_username; - return 1; -} - -static int -doveadm_expire_mail_cmd_get_next_user(struct doveadm_mail_cmd_context *ctx, - const char **username_r) -{ - struct doveadm_expire_mail_cmd_context *ectx = - DOVEADM_EXPIRE_MAIL_CMD_CONTEXT(ctx); - const char *key, *value, *error; - unsigned long oldest_savedate; - int ret; - - while (dict_iterate(ectx->iter, &key, &value)) { - if (str_to_ulong(value, &oldest_savedate) < 0) { - /* invalid record */ - i_error("expire: Invalid timestamp: %s", value); - continue; - } - if ((time_t)oldest_savedate > ectx->oldest_before_time) { - if (doveadm_debug) { - i_debug("expire: Stopping iteration on key %s " - "(%lu > %"PRIdTIME_T")", - key, oldest_savedate, - ectx->oldest_before_time); - } - break; - } - - T_BEGIN { - ret = doveadm_expire_mail_want(ctx, key, - oldest_savedate, - username_r); - } T_END; - if (ret > 0) - return 1; - if (ret < 0 && ectx->delete_nonexistent_users) { - /* user has been deleted */ - dict_unset(ectx->trans, key); - } - } - - /* finished */ - if (dict_iterate_deinit(&ectx->iter, &error) < 0) { - i_error("Dictionary iteration failed: %s", error); - return -1; - } - return 0; -} - -static const char *const *doveadm_expire_get_patterns(void) -{ - ARRAY_TYPE(const_string) patterns; - const char *str; - char set_name[6 + MAX_INT_STRLEN]; - unsigned int i; - - t_array_init(&patterns, 16); - str = doveadm_plugin_getenv("expire"); - for (i = 2; str != NULL; i++) { - array_push_back(&patterns, &str); - - if (i_snprintf(set_name, sizeof(set_name), "expire%u", i) < 0) - i_unreached(); - str = doveadm_plugin_getenv(set_name); - } - array_append_zero(&patterns); - return array_front(&patterns); -} - -static bool -doveadm_expire_get_or_mailboxes(struct doveadm_mail_cmd_context *ctx, - const struct mail_search_arg *args, - struct expire_query query) -{ - struct doveadm_expire_mail_cmd_context *ectx = - DOVEADM_EXPIRE_MAIL_CMD_CONTEXT(ctx); - const struct mail_search_arg *arg; - unsigned int query_count; - - query.mailbox = NULL; - query_count = array_count(&ectx->queries); - for (arg = args; arg != NULL; arg = arg->next) { - switch (arg->type) { - case SEARCH_MAILBOX_GLOB: - query.glob = imap_match_init(ctx->pool, arg->value.str, - TRUE, '/'); - /* fall through */ - case SEARCH_MAILBOX: - /* require mailbox to be in expire patterns */ - query.mailbox = p_strdup(ctx->pool, arg->value.str); - array_push_back(&ectx->queries, &query); - break; - default: - /* there are something else besides mailboxes, - can't optimize this. */ - array_delete(&ectx->queries, query_count, - array_count(&ectx->queries) - query_count); - return FALSE; - } - } - return query.mailbox != NULL; -} - -static bool -doveadm_expire_analyze_and_query(struct doveadm_mail_cmd_context *ctx, - const struct mail_search_arg *args) -{ - struct doveadm_expire_mail_cmd_context *ectx = - DOVEADM_EXPIRE_MAIL_CMD_CONTEXT(ctx); - const struct mail_search_arg *arg; - struct expire_query query; - bool have_or = FALSE; - - i_zero(&query); - query.before_time = (time_t)-1; - - for (arg = args; arg != NULL; arg = arg->next) { - switch (arg->type) { - case SEARCH_OR: - have_or = TRUE; - break; - case SEARCH_MAILBOX_GLOB: - query.glob = imap_match_init(ctx->pool, arg->value.str, - TRUE, '/'); - /* fall through */ - case SEARCH_MAILBOX: - /* require mailbox to be in expire patterns */ - query.mailbox = p_strdup(ctx->pool, arg->value.str); - break; - case SEARCH_BEFORE: - if (arg->value.date_type != MAIL_SEARCH_DATE_TYPE_SAVED) - break; - if ((arg->value.search_flags & - MAIL_SEARCH_ARG_FLAG_UTC_TIMES) == 0) - break; - query.before_time = arg->value.time; - break; - default: - break; - } - } - - if (query.before_time == (time_t)-1) { - /* no SAVEDBEFORE, can't optimize */ - return FALSE; - } - - if (query.mailbox != NULL) { - /* one mailbox */ - array_push_back(&ectx->queries, &query); - return TRUE; - } - - /* no MAILBOX, but check if one of the ORs lists mailboxes */ - if (!have_or) - return FALSE; - - for (arg = args; arg != NULL; arg = arg->next) { - if (arg->type == SEARCH_OR && - doveadm_expire_get_or_mailboxes(ctx, arg->value.subargs, - query)) - return TRUE; - } - return FALSE; -} - -static bool -doveadm_expire_analyze_or_query(struct doveadm_mail_cmd_context *ctx, - const struct mail_search_arg *args) -{ - const struct mail_search_arg *arg; - - /* all of the subqueries must have mailbox and savedbefore */ - for (arg = args; arg != NULL; arg = arg->next) { - if (arg->type != SEARCH_SUB) - return FALSE; - - if (!doveadm_expire_analyze_and_query(ctx, arg->value.subargs)) - return FALSE; - } - return TRUE; -} - -static bool doveadm_expire_analyze_query(struct doveadm_mail_cmd_context *ctx) -{ - struct doveadm_expire_mail_cmd_context *ectx = - DOVEADM_EXPIRE_MAIL_CMD_CONTEXT(ctx); - struct mail_search_arg *args = ctx->search_args->args; - struct expire_set *set; - const struct expire_query *queries; - unsigned int i, count; - - i_assert(args != NULL); - - /* we support two kinds of queries: - - 1) mailbox-pattern savedbefore ... - 2) or 2*(mailbox-pattern savedbefore ...) - - mailbox-pattern can be: - - a) mailbox - b) or 2*(mailbox ) - */ - p_array_init(&ectx->queries, ctx->pool, 8); - if (!doveadm_expire_analyze_and_query(ctx, args) && - (args->type != SEARCH_OR || args->next != NULL || - !doveadm_expire_analyze_or_query(ctx, args->value.subargs))) { - if (doveadm_debug) - i_debug("expire: Couldn't optimize search query"); - return FALSE; - } - - /* make sure all mailboxes match expire patterns */ - set = expire_set_init(doveadm_expire_get_patterns()); - queries = array_get(&ectx->queries, &count); - for (i = 0; i < count; i++) { - if (!expire_set_lookup(set, queries[i].mailbox)) { - if (doveadm_debug) { - i_debug("expire: Couldn't optimize search query: " - "mailbox %s not in expire database", - queries[i].mailbox); - } - break; - } - } - expire_set_deinit(&set); - - return i == count; -} - -static void doveadm_expire_mail_cmd_deinit(struct doveadm_mail_cmd_context *ctx) -{ - struct doveadm_expire_mail_cmd_context *ectx = - DOVEADM_EXPIRE_MAIL_CMD_CONTEXT(ctx); - const char *error; - - if (ectx->iter != NULL) { - if (dict_iterate_deinit(&ectx->iter, &error) < 0) - i_error("expire: Dictionary iteration failed: %s", error); - } - if (dict_transaction_commit(&ectx->trans, &error) < 0) - i_error("expire: Dictionary commit failed: %s", error); - dict_deinit(&ectx->dict); - hash_table_destroy(&ectx->user_states); - - ectx->module_ctx.super.deinit(ctx); -} - -static void doveadm_expire_mail_init(struct doveadm_mail_cmd_context *ctx) -{ - struct doveadm_expire_mail_cmd_context *ectx; - struct dict_settings dict_set; - struct dict *dict; - const struct expire_query *query; - const char *expire_dict, *username, *value, *error; - char *username_dup; - enum expire_user_state state; - - if (ctx->search_args == NULL) - return; - - expire_dict = doveadm_plugin_getenv("expire_dict"); - if (expire_dict == NULL) - return; - - /* doveadm proxying uses expire database only locally. the remote - doveadm handles each user one at a time (even though - iterate_single_user=FALSE) */ - if (ctx->iterate_single_user || ctx->proxying) { - if (doveadm_debug) { - i_debug("expire: Iterating only a single user, " - "ignoring expire database"); - } - return; - } - - ectx = p_new(ctx->pool, struct doveadm_expire_mail_cmd_context, 1); - ectx->module_ctx.super = ctx->v; - value = doveadm_plugin_getenv("expire_keep_nonexistent_users"); - ectx->delete_nonexistent_users = - value == NULL || strcmp(value, "yes") != 0; - MODULE_CONTEXT_SET(ctx, doveadm_expire_mail_cmd_module, ectx); - - /* we can potentially optimize this query. see if the search args - are valid for optimization. */ - if (!doveadm_expire_analyze_query(ctx)) - return; - - if (doveadm_debug) - i_debug("expire: Searching only users listed in expire database"); - - i_zero(&dict_set); - dict_set.value_type = DICT_DATA_TYPE_UINT32; - dict_set.username = ""; - dict_set.base_dir = doveadm_settings->base_dir; - if (dict_init(expire_dict, &dict_set, &dict, &error) < 0) { - i_error("dict_init(%s) failed, not using it: %s", - expire_dict, error); - return; - } - - ectx->oldest_before_time = (time_t)-1; - array_foreach(&ectx->queries, query) { - if (ectx->oldest_before_time > query->before_time || - ectx->oldest_before_time == (time_t)-1) - ectx->oldest_before_time = query->before_time; - } - - ctx->v.deinit = doveadm_expire_mail_cmd_deinit; - ctx->v.get_next_user = doveadm_expire_mail_cmd_get_next_user; - - hash_table_create(&ectx->user_states, ctx->pool, 0, str_hash, strcmp); - while (mail_storage_service_all_next(ctx->storage_service, &username) > 0) { - username_dup = p_strdup(ctx->pool, username); - state = EXPIRE_USER_STATE_EXISTS; - hash_table_insert(ectx->user_states, username_dup, - POINTER_CAST(state)); - } - - ectx->dict = dict; - ectx->trans = dict_transaction_begin(dict); - ectx->iter = dict_iterate_init(dict, DICT_EXPIRE_PREFIX, - DICT_ITERATE_FLAG_RECURSE | - DICT_ITERATE_FLAG_SORT_BY_VALUE); -} - -void doveadm_expire_plugin_init(struct module *module ATTR_UNUSED) -{ - next_hook_doveadm_mail_init = hook_doveadm_mail_init; - hook_doveadm_mail_init = doveadm_expire_mail_init; -} - -void doveadm_expire_plugin_deinit(void) -{ - i_assert(hook_doveadm_mail_init == doveadm_expire_mail_init); - hook_doveadm_mail_init = next_hook_doveadm_mail_init; -} diff --git a/src/plugins/expire/expire-plugin.c b/src/plugins/expire/expire-plugin.c deleted file mode 100644 index 0a245ad517..0000000000 --- a/src/plugins/expire/expire-plugin.c +++ /dev/null @@ -1,455 +0,0 @@ -/* Copyright (c) 2006-2018 Dovecot authors, see the included COPYING file */ - -/* There are several race conditions in this plugin, but they should be - happening pretty rarely and usually it's not a big problem if the results - are temporarily wrong. Fixing the races would likely be a lot of work, - so it's not really worth it. */ - -#include "lib.h" -#include "ioloop.h" -#include "array.h" -#include "str.h" -#include "master-service.h" -#include "dict.h" -#include "mail-namespace.h" -#include "index-mail.h" -#include "index-storage.h" -#include "expire-set.h" -#include "expire-plugin.h" - - -#define EXPIRE_CONTEXT(obj) \ - MODULE_CONTEXT(obj, expire_storage_module) -#define EXPIRE_CONTEXT_REQUIRE(obj) \ - MODULE_CONTEXT_REQUIRE(obj, expire_storage_module) -#define EXPIRE_MAIL_CONTEXT(obj) \ - MODULE_CONTEXT_REQUIRE(obj, expire_mail_module) -#define EXPIRE_USER_CONTEXT(obj) \ - MODULE_CONTEXT_REQUIRE(obj, expire_mail_user_module) - -struct expire_mail_index_header { - uint32_t timestamp; -}; - -struct expire_mail_user { - union mail_user_module_context module_ctx; - - struct dict *db; - struct expire_set *set; - bool expire_cache; -}; - -struct expire_mailbox { - union mailbox_module_context module_ctx; - uint32_t expire_ext_id; -}; - -struct expire_transaction_context { - union mailbox_transaction_module_context module_ctx; - - bool saves:1; - bool first_expunged:1; -}; - -const char *expire_plugin_version = DOVECOT_ABI_VERSION; - -static MODULE_CONTEXT_DEFINE_INIT(expire_storage_module, - &mail_storage_module_register); -static MODULE_CONTEXT_DEFINE_INIT(expire_mail_module, &mail_module_register); -static MODULE_CONTEXT_DEFINE_INIT(expire_mail_user_module, - &mail_user_module_register); - -static struct mailbox_transaction_context * -expire_mailbox_transaction_begin(struct mailbox *box, - enum mailbox_transaction_flags flags, - const char *reason) -{ - struct expire_mailbox *xpr_box = EXPIRE_CONTEXT_REQUIRE(box); - struct mailbox_transaction_context *t; - struct expire_transaction_context *xt; - - t = xpr_box->module_ctx.super.transaction_begin(box, flags, reason); - xt = i_new(struct expire_transaction_context, 1); - - MODULE_CONTEXT_SET(t, expire_storage_module, xt); - return t; -} - -static void first_save_timestamp(struct mailbox *box, time_t *stamp_r) -{ - struct mailbox_transaction_context *t; - const struct mail_index_header *hdr; - struct mail *mail; - - *stamp_r = ioloop_time; - - t = mailbox_transaction_begin(box, 0, __func__); - mail = mail_alloc(t, 0, NULL); - - /* find the first non-expunged mail. we're here because the first - mail was expunged, so don't bother checking it. */ - hdr = mail_index_get_header(box->view); - if (hdr->messages_count > 0) { - mail_set_seq(mail, 1); - (void)mail_get_save_date(mail, stamp_r); - } - mail_free(&mail); - (void)mailbox_transaction_commit(&t); -} - -static uint32_t expire_get_ext_id(struct mailbox *box) -{ - struct expire_mailbox *xpr_box = EXPIRE_CONTEXT_REQUIRE(box); - - if (xpr_box->expire_ext_id != (uint32_t)-1) - return xpr_box->expire_ext_id; - - xpr_box->expire_ext_id = - mail_index_ext_register(box->index, "expire", - sizeof(struct expire_mail_index_header), 0, 0); - return xpr_box->expire_ext_id; -} - -static int expire_lookup(struct mailbox *box, const char *key, - time_t *new_stamp_r) -{ - struct expire_mail_user *euser = - EXPIRE_USER_CONTEXT(box->storage->user); - const struct expire_mail_index_header *hdr; - const void *data; - size_t data_size; - const char *value, *error; - int ret; - - /* default to ioloop_time for newly saved mails. it may not be exactly - the first message's save time, but a few seconds difference doesn't - matter */ - *new_stamp_r = ioloop_time; - - if (euser->expire_cache) { - mail_index_get_header_ext(box->view, expire_get_ext_id(box), - &data, &data_size); - if (data_size == sizeof(*hdr)) { - hdr = data; - if (hdr->timestamp == 0) - return 0; - /* preserve the original timestamp */ - *new_stamp_r = hdr->timestamp; - return 1; - } - /* cache doesn't exist yet */ - } - - ret = dict_lookup(euser->db, pool_datastack_create(), - key, &value, &error); - if (ret <= 0) { - if (ret < 0) { - i_error("expire: dict_lookup(%s) failed: %s", key, error); - return -1; - } - first_save_timestamp(box, new_stamp_r); - return 0; - } - return strcmp(value, "0") != 0 ? 1 : 0; -} - -static void -expire_update(struct mailbox *box, const char *key, time_t timestamp) -{ - struct expire_mail_user *euser = - EXPIRE_USER_CONTEXT(box->storage->user); - struct dict_transaction_context *dctx; - struct mail_index_transaction *trans; - struct expire_mail_index_header hdr; - const char *error; - - dctx = dict_transaction_begin(euser->db); - dict_set(dctx, key, dec2str(timestamp)); - if (dict_transaction_commit(&dctx, &error) < 0) - i_error("expire: dict commit failed: %s", error); - else if (euser->expire_cache) { - i_zero(&hdr); - hdr.timestamp = timestamp; - - trans = mail_index_transaction_begin(box->view, - MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL); - mail_index_update_header_ext(trans, expire_get_ext_id(box), - 0, &hdr, sizeof(hdr)); - if (mail_index_transaction_commit(&trans) < 0) - i_error("expire: index transaction commit failed"); - } -} - -static void first_nonexpunged_timestamp(struct mailbox_transaction_context *t, - time_t *stamp_r) -{ - struct mail_index_view *view = t->view; - const struct mail_index_header *hdr; - struct mail *mail; - uint32_t seq; - - mail = mail_alloc(t, 0, NULL); - - /* find the first non-expunged mail. we're here because the first - mail was expunged, so don't bother checking it. */ - hdr = mail_index_get_header(view); - for (seq = 2; seq <= hdr->messages_count; seq++) { - if (!mail_index_is_expunged(view, seq)) { - mail_set_seq(mail, seq); - if (mail_get_save_date(mail, stamp_r) >= 0) - break; - } - } - mail_free(&mail); - - if (seq > hdr->messages_count) { - /* everything expunged */ - *stamp_r = 0; - } -} - -static int -expire_mailbox_transaction_commit(struct mailbox_transaction_context *t, - struct mail_transaction_commit_changes *changes_r) -{ - struct expire_mailbox *xpr_box = EXPIRE_CONTEXT_REQUIRE(t->box); - struct expire_transaction_context *xt = EXPIRE_CONTEXT_REQUIRE(t); - struct mailbox *box = t->box; - time_t new_stamp = 0; - bool update_dict = FALSE; - int ret; - - if (xt->first_expunged) { - /* first mail expunged. dict needs updating. */ - first_nonexpunged_timestamp(t, &new_stamp); - if (new_stamp == 0 && xt->saves) { - /* everything was expunged, but also within this - transaction a new message was saved */ - new_stamp = ioloop_time; - } - e_debug(box->event, "expire: Expunging first message, " - "updating timestamp to %ld", (long)new_stamp); - update_dict = TRUE; - } - - if (xpr_box->module_ctx.super.transaction_commit(t, changes_r) < 0) { - i_free(xt); - return -1; - } - /* transaction is freed now */ - t = NULL; - - if (xt->first_expunged || xt->saves) T_BEGIN { - const char *key; - - key = t_strconcat(DICT_EXPIRE_PREFIX, - box->storage->user->username, "/", - mailbox_get_vname(box), NULL); - if (xt->first_expunged) { - /* new_stamp is already set */ - } else { - i_assert(xt->saves); - /* saved new mails. dict needs to be updated only if - this is the first mail in the database */ - ret = expire_lookup(box, key, &new_stamp); - if (ret <= 0) { - /* first time saving here with expire enabled. - also handle lookup errors by just assuming - it didn't exist */ - if (ret < 0) { - i_warning("expire: dict lookup failed, " - "assuming update is needed"); - } - update_dict = TRUE; - } else { - /* already exists */ - } - if (update_dict) { - e_debug(box->event, "expire: Saving first message, " - "updating timestamp to %ld", (long)new_stamp); - } - } - - if (update_dict) - expire_update(box, key, new_stamp); - } T_END; - i_free(xt); - return 0; -} - -static void -expire_mailbox_transaction_rollback(struct mailbox_transaction_context *t) -{ - struct expire_mailbox *xpr_box = EXPIRE_CONTEXT_REQUIRE(t->box); - struct expire_transaction_context *xt = EXPIRE_CONTEXT_REQUIRE(t); - - xpr_box->module_ctx.super.transaction_rollback(t); - i_free(xt); -} - -static void expire_mail_expunge(struct mail *_mail) -{ - struct mail_private *mail = (struct mail_private *)_mail; - union mail_module_context *xpr_mail = EXPIRE_MAIL_CONTEXT(mail); - struct expire_transaction_context *xt = - EXPIRE_CONTEXT_REQUIRE(_mail->transaction); - - if (_mail->seq == 1) { - /* first mail expunged, database needs to be updated */ - xt->first_expunged = TRUE; - } - xpr_mail->super.expunge(_mail); -} - -static void expire_mail_allocated(struct mail *_mail) -{ - struct expire_mailbox *xpr_box = EXPIRE_CONTEXT(_mail->box); - struct mail_private *mail = (struct mail_private *)_mail; - struct mail_vfuncs *v = mail->vlast; - union mail_module_context *xpr_mail; - - if (xpr_box == NULL) - return; - - xpr_mail = p_new(mail->pool, union mail_module_context, 1); - xpr_mail->super = *v; - mail->vlast = &xpr_mail->super; - - v->expunge = expire_mail_expunge; - MODULE_CONTEXT_SET_SELF(mail, expire_mail_module, xpr_mail); -} - -static int expire_save_finish(struct mail_save_context *ctx) -{ - struct expire_transaction_context *xt = - EXPIRE_CONTEXT_REQUIRE(ctx->transaction); - struct expire_mailbox *xpr_box = EXPIRE_CONTEXT_REQUIRE(ctx->transaction->box); - - xt->saves = TRUE; - return xpr_box->module_ctx.super.save_finish(ctx); -} - -static int -expire_copy(struct mail_save_context *ctx, struct mail *mail) -{ - struct expire_transaction_context *xt = - EXPIRE_CONTEXT_REQUIRE(ctx->transaction); - struct expire_mailbox *xpr_box = EXPIRE_CONTEXT_REQUIRE(ctx->transaction->box); - - xt->saves = TRUE; - return xpr_box->module_ctx.super.copy(ctx, mail); -} - -static void expire_mailbox_allocate_init(struct mailbox *box) -{ - struct mailbox_vfuncs *v = box->vlast; - struct expire_mailbox *xpr_box; - - xpr_box = p_new(box->pool, struct expire_mailbox, 1); - xpr_box->module_ctx.super = *v; - box->vlast = &xpr_box->module_ctx.super; - xpr_box->expire_ext_id = (uint32_t)-1; - - v->transaction_begin = expire_mailbox_transaction_begin; - v->transaction_commit = expire_mailbox_transaction_commit; - v->transaction_rollback = expire_mailbox_transaction_rollback; - v->save_finish = expire_save_finish; - v->copy = expire_copy; - - MODULE_CONTEXT_SET(box, expire_storage_module, xpr_box); -} - -static void expire_mailbox_allocated(struct mailbox *box) -{ - struct expire_mail_user *euser = - EXPIRE_USER_CONTEXT(box->storage->user); - - if (euser != NULL && expire_set_lookup(euser->set, box->vname)) - expire_mailbox_allocate_init(box); -} - -static void expire_mail_user_deinit(struct mail_user *user) -{ - struct expire_mail_user *euser = EXPIRE_USER_CONTEXT(user); - - dict_deinit(&euser->db); - expire_set_deinit(&euser->set); - - euser->module_ctx.super.deinit(user); -} - -static const char *const *expire_get_patterns(struct mail_user *user) -{ - ARRAY_TYPE(const_string) patterns; - const char *str; - char set_name[6 + MAX_INT_STRLEN]; - unsigned int i; - - t_array_init(&patterns, 16); - str = mail_user_set_plugin_getenv(user->set, "expire"); - for (i = 2; str != NULL; i++) { - array_push_back(&patterns, &str); - - if (i_snprintf(set_name, sizeof(set_name), "expire%u", i) < 0) - i_unreached(); - str = mail_user_set_plugin_getenv(user->set, set_name); - } - array_append_zero(&patterns); - return array_front(&patterns); -} - -static void expire_mail_user_created(struct mail_user *user) -{ - struct mail_user_vfuncs *v = user->vlast; - struct expire_mail_user *euser; - struct dict_settings dict_set; - struct dict *db; - const char *dict_uri, *error; - - if (!mail_user_plugin_getenv_bool(user, "expire")) { - e_debug(user->event, "expire: No expire setting - plugin disabled"); - return; - } - - dict_uri = mail_user_plugin_getenv(user, "expire_dict"); - if (dict_uri == NULL) { - i_error("expire plugin: expire_dict setting missing"); - return; - } - /* we're using only shared dictionary, the username doesn't matter. */ - i_zero(&dict_set); - dict_set.value_type = DICT_DATA_TYPE_UINT32; - dict_set.username = ""; - dict_set.base_dir = user->set->base_dir; - if (dict_init(dict_uri, &dict_set, &db, &error) < 0) { - i_error("expire plugin: dict_init(%s) failed: %s", - dict_uri, error); - return; - } - - euser = p_new(user->pool, struct expire_mail_user, 1); - euser->module_ctx.super = *v; - user->vlast = &euser->module_ctx.super; - v->deinit = expire_mail_user_deinit; - - euser->db = db; - euser->set = expire_set_init(expire_get_patterns(user)); - euser->expire_cache = mail_user_plugin_getenv_bool(user, "expire_cache"); - MODULE_CONTEXT_SET(user, expire_mail_user_module, euser); -} - -static struct mail_storage_hooks expire_mail_storage_hooks = { - .mail_user_created = expire_mail_user_created, - .mailbox_allocated = expire_mailbox_allocated, - .mail_allocated = expire_mail_allocated -}; - -void expire_plugin_init(struct module *module) -{ - mail_storage_hooks_add(module, &expire_mail_storage_hooks); -} - -void expire_plugin_deinit(void) -{ - mail_storage_hooks_remove(&expire_mail_storage_hooks); -} diff --git a/src/plugins/expire/expire-plugin.h b/src/plugins/expire/expire-plugin.h deleted file mode 100644 index 9f46c0ac89..0000000000 --- a/src/plugins/expire/expire-plugin.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef EXPIRE_PLUGIN_H -#define EXPIRE_PLUGIN_H - -void expire_plugin_init(struct module *module); -void expire_plugin_deinit(void); - -#endif diff --git a/src/plugins/expire/expire-set.c b/src/plugins/expire/expire-set.c deleted file mode 100644 index f210c09379..0000000000 --- a/src/plugins/expire/expire-set.c +++ /dev/null @@ -1,50 +0,0 @@ -/* Copyright (c) 2006-2018 Dovecot authors, see the included COPYING file */ - -#include "lib.h" -#include "array.h" -#include "imap-match.h" -#include "expire-set.h" - - -struct expire_set { - pool_t pool; - ARRAY(struct imap_match_glob *) globs; -}; - -struct expire_set *expire_set_init(const char *const *patterns) -{ - struct expire_set *set; - struct imap_match_glob *glob; - const char *const *pattern; - pool_t pool; - - pool = pool_alloconly_create("Expire pool", 512); - set = p_new(pool, struct expire_set, 1); - set->pool = pool; - p_array_init(&set->globs, set->pool, 16); - - for (pattern = patterns; *pattern != NULL; pattern++) { - glob = imap_match_init(set->pool, *pattern, TRUE, '/'); - array_push_back(&set->globs, &glob); - } - return set; -} - -void expire_set_deinit(struct expire_set **_set) -{ - struct expire_set *set = *_set; - - *_set = NULL; - pool_unref(&set->pool); -} - -bool expire_set_lookup(struct expire_set *set, const char *mailbox) -{ - struct imap_match_glob *const *globp; - - array_foreach(&set->globs, globp) { - if (imap_match(*globp, mailbox) == IMAP_MATCH_YES) - return TRUE; - } - return FALSE; -} diff --git a/src/plugins/expire/expire-set.h b/src/plugins/expire/expire-set.h deleted file mode 100644 index 70f241bbf7..0000000000 --- a/src/plugins/expire/expire-set.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef EXPIRE_SET_H -#define EXPIRE_SET_H - -#define DICT_EXPIRE_PREFIX DICT_PATH_SHARED"expire/" - -struct expire_set *expire_set_init(const char *const *patterns); -void expire_set_deinit(struct expire_set **set); - -bool expire_set_lookup(struct expire_set *set, const char *mailbox); - -#endif