doveadm-expire.c revision b26a773eaa28e3f77c7b760cb4570aa18107a465
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen/* Copyright (c) 2005-2010 Dovecot authors, see the included COPYING file */
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen MODULE_CONTEXT(obj, doveadm_expire_mail_cmd_module)
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen union doveadm_mail_cmd_module_context module_ctx;
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainenconst char *doveadm_expire_plugin_version = DOVECOT_VERSION;
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainenvoid doveadm_expire_plugin_init(struct module *module);
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainenstatic MODULE_CONTEXT_DEFINE_INIT(doveadm_expire_mail_cmd_module,
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainenstatic void (*next_hook_doveadm_mail_init)(struct doveadm_mail_cmd_context *ctx);
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainendoveadm_expire_mail_match_mailbox(struct doveadm_expire_mail_cmd_context *ectx,
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen if (imap_match(query->glob, mailbox) == IMAP_MATCH_YES)
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainendoveadm_expire_mail_want(struct doveadm_mail_cmd_context *ctx,
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen const char *key, time_t stamp, const char **username_r)
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen struct doveadm_expire_mail_cmd_context *ectx =
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen /* key = DICT_EXPIRE_PREFIX<user>/<mailbox> */
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen /* invalid record, ignore */
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen username = t_strdup_until(username, mailbox++);
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen if (hash_table_lookup(ectx->seen_users, username) != NULL) {
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen /* seen this user already, skip the record */
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen if (!doveadm_expire_mail_match_mailbox(ectx, mailbox, stamp)) {
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen /* this mailbox doesn't have any matching messages */
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen hash_table_insert(ectx->seen_users, username_dup, username_dup);
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainendoveadm_expire_mail_cmd_get_next_user(struct doveadm_mail_cmd_context *ctx,
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen struct doveadm_expire_mail_cmd_context *ectx =
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen unsigned long stamp;
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen while (dict_iterate(ectx->iter, &key, &value)) {
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen /* invalid record */
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen ret = doveadm_expire_mail_want(ctx, key, stamp,
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen /* finished */
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainenstatic const char *const *doveadm_expire_get_patterns(void)
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen const char *str;
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen unsigned int i;
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen i_snprintf(set_name, sizeof(set_name), "expire%u", i);
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainendoveadm_expire_get_or_mailboxes(struct doveadm_mail_cmd_context *ctx,
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen struct doveadm_expire_mail_cmd_context *ectx =
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen for (arg = args; arg != NULL; arg = arg->next) {
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen query.glob = imap_match_init(ctx->pool, arg->value.str,
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen /* fall through */
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen /* require mailbox to be in expire patterns */
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen query.mailbox = p_strdup(ctx->pool, arg->value.str);
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen /* there are something else besides mailboxes,
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen can't optimize this. */
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainendoveadm_expire_analyze_and_query(struct doveadm_mail_cmd_context *ctx,
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen struct doveadm_expire_mail_cmd_context *ectx =
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen for (arg = args; arg != NULL; arg = arg->next) {
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen query.glob = imap_match_init(ctx->pool, arg->value.str,
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen /* fall through */
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen /* require mailbox to be in expire patterns */
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen query.mailbox = p_strdup(ctx->pool, arg->value.str);
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen if (arg->value.date_type != MAIL_SEARCH_DATE_TYPE_SAVED)
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen /* no SAVEDBEFORE, can't optimize */
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen /* one mailbox */
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen /* no MAILBOX, but check if one of the ORs lists mailboxes */
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen for (arg = args; arg != NULL; arg = arg->next) {
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen doveadm_expire_get_or_mailboxes(ctx, arg->value.subargs,
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainendoveadm_expire_analyze_or_query(struct doveadm_mail_cmd_context *ctx,
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen /* all of the subqueries must have mailbox and savedbefore */
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen for (arg = args; arg != NULL; arg = arg->next) {
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen if (!doveadm_expire_analyze_and_query(ctx, arg->value.subargs))
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainenstatic bool doveadm_expire_analyze_query(struct doveadm_mail_cmd_context *ctx)
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen struct doveadm_expire_mail_cmd_context *ectx =
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen struct mail_search_arg *args = ctx->search_args->args;
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen unsigned int i, count;
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen /* we support two kinds of queries:
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen 1) mailbox-pattern savedbefore <stamp> ...
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen 2) or 2*(mailbox-pattern savedbefore <stamp> ...)
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen mailbox-pattern can be:
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen a) mailbox <name>
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen b) or 2*(mailbox <name>)
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen if (!doveadm_expire_analyze_and_query(ctx, args) &&
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen (args->type != SEARCH_OR || args->next != NULL ||
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen !doveadm_expire_analyze_or_query(ctx, args->value.subargs))) {
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen i_debug("expire: Couldn't optimize search query");
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen /* make sure all mailboxes match expire patterns */
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen set = expire_set_init(doveadm_expire_get_patterns());
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen for (i = 0; i < count; i++) {
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen if (!expire_set_lookup(set, queries[i].mailbox)) {
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen i_debug("expire: Couldn't optimize search query: "
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen "mailbox %s not in expire database",
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainenstatic void doveadm_expire_mail_cmd_deinit(struct doveadm_mail_cmd_context *ctx)
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen struct doveadm_expire_mail_cmd_context *ectx =
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainenstatic void doveadm_expire_mail_init(struct doveadm_mail_cmd_context *ctx)
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen expire_dict = doveadm_plugin_getenv("expire_dict");
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen ectx = p_new(ctx->pool, struct doveadm_expire_mail_cmd_context, 1);
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen MODULE_CONTEXT_SET(ctx, doveadm_expire_mail_cmd_module, ectx);
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen /* we can potentially optimize this query. see if the search args
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen are valid for optimization. */
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen i_debug("expire: Searching only users listed in expire database");
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen dict = dict_init(expire_dict, DICT_DATA_TYPE_UINT32, "",
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen i_error("dict_init(%s) failed, not using it", expire_dict);
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen if (ectx->oldest_before_time > query->before_time ||
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen ectx->oldest_before_time = query->before_time;
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen ctx->v.deinit = doveadm_expire_mail_cmd_deinit;
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen ctx->v.get_next_user = doveadm_expire_mail_cmd_get_next_user;
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen ectx->iter = dict_iterate_init(dict, DICT_EXPIRE_PREFIX,
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainenvoid doveadm_expire_plugin_init(struct module *module ATTR_UNUSED)
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen next_hook_doveadm_mail_init = hook_doveadm_mail_init;
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen hook_doveadm_mail_init = doveadm_expire_mail_init;
f6d57a2c182f63cd52819f0abb3c3d9f828afe19Timo Sirainen i_assert(hook_doveadm_mail_init == doveadm_expire_mail_init);