The autoexpunge functionality should be used instead.
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
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
- }
-}
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
SUBDIRS = \
acl \
imap-acl \
- expire \
fts \
fts-squat \
last-login \
+++ /dev/null
-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
+++ /dev/null
-/* 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<user>/<mailbox> */
- 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 <stamp> ...
- 2) or 2*(mailbox-pattern savedbefore <stamp> ...)
-
- mailbox-pattern can be:
-
- a) mailbox <name>
- b) or 2*(mailbox <name>)
- */
- 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;
-}
+++ /dev/null
-/* 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);
-}
+++ /dev/null
-#ifndef EXPIRE_PLUGIN_H
-#define EXPIRE_PLUGIN_H
-
-void expire_plugin_init(struct module *module);
-void expire_plugin_deinit(void);
-
-#endif
+++ /dev/null
-/* 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;
-}
+++ /dev/null
-#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