dovecot-2.0: expire: Rewrote expire-tool as a plugin for doveadm.

dovecot at dovecot.org dovecot at dovecot.org
Thu May 27 22:31:46 EEST 2010


details:   http://hg.dovecot.org/dovecot-2.0/rev/da750dc62c14
changeset: 11398:da750dc62c14
user:      Timo Sirainen <tss at iki.fi>
date:      Thu May 27 20:30:04 2010 +0100
description:
expire: Rewrote expire-tool as a plugin for doveadm.
Whenever using some doveadm mail command with -A parameter, the plugin checks
if it can get the list of potentially matching users from the expire database.

Currently only the list of users is filtered based on expire database, list of
mailboxes could also be filtered but this isn't supported (yet).

diffstat:

 src/plugins/expire/Makefile.am      |   30 +--
 src/plugins/expire/doveadm-expire.c |  388 ++++++++++++++++++++++++++++++++++++++
 src/plugins/expire/expire-env.c     |  176 -----------------
 src/plugins/expire/expire-env.h     |   19 -
 src/plugins/expire/expire-plugin.c  |   71 ++----
 src/plugins/expire/expire-set.c     |   51 +++++
 src/plugins/expire/expire-set.h     |   11 +
 src/plugins/expire/expire-tool.c    |  346 ----------------------------------
 8 files changed, 489 insertions(+), 603 deletions(-)

diffs (truncated from 1221 to 300 lines):

diff -r caecf9866909 -r da750dc62c14 src/plugins/expire/Makefile.am
--- a/src/plugins/expire/Makefile.am	Thu May 27 20:00:28 2010 +0100
+++ b/src/plugins/expire/Makefile.am	Thu May 27 20:30:04 2010 +0100
@@ -1,4 +1,4 @@
-pkglibexecdir = $(libexecdir)/dovecot
+doveadm_moduledir = $(moduledir)/doveadm
 
 AM_CPPFLAGS = \
 	-I$(top_srcdir)/src/lib \
@@ -10,35 +10,25 @@
 	-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/lib-storage/index \
+	-I$(top_srcdir)/src/doveadm
 
+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-env.c \
+	expire-set.c \
 	expire-plugin.c
 
 noinst_HEADERS = \
-	expire-env.h \
+	expire-set.h \
 	expire-plugin.h
 
-pkglibexec_PROGRAMS = expire-tool
+doveadm_module_LTLIBRARIES = \
+	lib10_doveadm_expire_plugin.la
 
-expire_tool_SOURCES = \
-	expire-tool.c
-
-if !BUILD_SHARED_LIBS
-unused_objects = \
-	$(top_builddir)/src/lib/mountpoint.o
-endif
-
-libs = \
-	expire-env.lo \
-	$(LIBDOVECOT_STORAGE) \
-	$(unused_objects)
-
-expire_tool_LDADD = $(libs) $(LIBDOVECOT) $(MODULE_LIBS)
-expire_tool_DEPENDENCIES = $(libs) $(LIBDOVECOT_DEPS)
+lib10_doveadm_expire_plugin_la_SOURCES = \
+	doveadm-expire.c
diff -r caecf9866909 -r da750dc62c14 src/plugins/expire/doveadm-expire.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/plugins/expire/doveadm-expire.c	Thu May 27 20:30:04 2010 +0100
@@ -0,0 +1,388 @@
+/* Copyright (c) 2005-2010 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-mail.h"
+
+#define DOVEADM_EXPIRE_MAIL_CMD_CONTEXT(obj) \
+	MODULE_CONTEXT(obj, doveadm_expire_mail_cmd_module)
+
+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;
+
+	struct hash_table *seen_users;
+	ARRAY_DEFINE(queries, struct expire_query);
+	time_t oldest_before_time;
+};
+
+const char *doveadm_expire_plugin_version = DOVECOT_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 bool
+doveadm_expire_mail_want(struct doveadm_mail_cmd_context *ctx,
+			 const char *key, time_t stamp, const char **username_r)
+{
+	struct doveadm_expire_mail_cmd_context *ectx =
+		DOVEADM_EXPIRE_MAIL_CMD_CONTEXT(ctx);
+	const char *username, *mailbox;
+	char *username_dup;
+
+	/* key = DICT_EXPIRE_PREFIX<user>/<mailbox> */
+	username = key + strlen(DICT_EXPIRE_PREFIX);
+	mailbox = strchr(username, '/');
+	if (mailbox == NULL) {
+		/* invalid record, ignore */
+		return FALSE;
+	}
+	username = t_strdup_until(username, mailbox++);
+
+	if (hash_table_lookup(ectx->seen_users, username) != NULL) {
+		/* seen this user already, skip the record */
+		return FALSE;
+	}
+
+	if (!doveadm_expire_mail_match_mailbox(ectx, mailbox, stamp)) {
+		/* this mailbox doesn't have any matching messages */
+		return FALSE;
+	}
+	username_dup = p_strdup(ctx->pool, username);
+	hash_table_insert(ectx->seen_users, username_dup, username_dup);
+
+	*username_r = username_dup;
+	return TRUE;
+}
+
+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;
+	unsigned long stamp;
+	bool ret;
+
+	while (dict_iterate(ectx->iter, &key, &value)) {
+		if (str_to_ulong(value, &stamp) < 0) {
+			/* invalid record */
+			continue;
+		}
+		if ((time_t)stamp > ectx->oldest_before_time)
+			break;
+
+		T_BEGIN {
+			ret = doveadm_expire_mail_want(ctx, key, stamp,
+						       username_r);
+		} T_END;
+		if (ret)
+			return TRUE;
+	}
+
+	/* finished */
+	if (dict_iterate_deinit(&ectx->iter) < 0) {
+		i_error("Dictionary iteration failed");
+		return -1;
+	}
+	return 0;
+}
+
+static const char *const *doveadm_expire_get_patterns(void)
+{
+	ARRAY_TYPE(const_string) patterns;
+	const char *str;
+	char set_name[20];
+	unsigned int i;
+
+	t_array_init(&patterns, 16);
+	str = doveadm_plugin_getenv("expire");
+	for (i = 2; str != NULL; i++) {
+		array_append(&patterns, &str, 1);
+
+		i_snprintf(set_name, sizeof(set_name), "expire%u", i);
+		str = doveadm_plugin_getenv(set_name);
+	}
+	(void)array_append_space(&patterns);
+	return array_idx(&patterns, 0);
+}
+
+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_append(&ectx->queries, &query, 1);
+			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;
+
+	memset(&query, 0, sizeof(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_USE_TZ) == 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_append(&ectx->queries, &query, 1);
+		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))


More information about the dovecot-cvs mailing list