changeset 9563:1cf278c2fd63 HEAD

expire: Support per-user expire configuration.
author Timo Sirainen <tss@iki.fi>
date Tue, 07 Jul 2009 14:19:05 -0400
parents 90f8e2d091b5
children 279af9682cd6
files src/plugins/expire/expire-env.c src/plugins/expire/expire-env.h src/plugins/expire/expire-plugin.c src/plugins/expire/expire-tool.c
diffstat 4 files changed, 106 insertions(+), 74 deletions(-) [+]
line wrap: on
line diff
--- a/src/plugins/expire/expire-env.c	Tue Jul 07 13:25:01 2009 -0400
+++ b/src/plugins/expire/expire-env.c	Tue Jul 07 14:19:05 2009 -0400
@@ -3,6 +3,7 @@
 #include "lib.h"
 #include "array.h"
 #include "imap-match.h"
+#include "mail-namespace.h"
 #include "expire-env.h"
 
 #include <stdlib.h>
@@ -25,11 +26,14 @@
 	ARRAY_DEFINE(expire_boxes, struct expire_box);
 };
 
-static void expire_env_parse(struct expire_env *env, const char *str,
-			     enum expire_type type)
+static void
+expire_env_parse(struct expire_env *env, struct mail_namespace *namespaces,
+		 const char *str, enum expire_type type)
 {
 	struct expire_box box;
+	struct mail_namespace *ns;
 	char *const *names;
+	const char *ns_name;
 	unsigned int len;
 
 	if (str == NULL)
@@ -46,8 +50,15 @@
 		}
 
 		box.pattern = *names;
-		/* FIXME: hardcoded separator isn't very good */
-		box.glob = imap_match_init(env->pool, box.pattern, TRUE, '/');
+		ns_name = *names;
+		ns = mail_namespace_find(namespaces, &ns_name);
+		if (ns == NULL && *box.pattern != '*') {
+			i_warning("expire: No namespace found for mailbox: %s",
+				  box.pattern);
+		}
+
+		box.glob = imap_match_init(env->pool, box.pattern, TRUE,
+					   ns == NULL ? '/' : ns->sep);
 		box.type = type;
 		box.expire_secs = strtoul(names[1], NULL, 10) * 3600 * 24;
 
@@ -55,7 +66,8 @@
 	}
 }
 
-struct expire_env *expire_env_init(const char *expunges, const char *altmoves)
+struct expire_env *expire_env_init(struct mail_namespace *namespaces,
+				   const char *expunges, const char *altmoves)
 {
 	struct expire_env *env;
 	pool_t pool;
@@ -64,13 +76,16 @@
 	env = p_new(pool, struct expire_env, 1);
 	env->pool = pool;
 
-	expire_env_parse(env, expunges, EXPIRE_TYPE_EXPUNGE);
-	expire_env_parse(env, altmoves, EXPIRE_TYPE_ALTMOVE);
+	expire_env_parse(env, namespaces, expunges, EXPIRE_TYPE_EXPUNGE);
+	expire_env_parse(env, namespaces, altmoves, EXPIRE_TYPE_ALTMOVE);
 	return env;
 }
 
-void expire_env_deinit(struct expire_env *env)
+void expire_env_deinit(struct expire_env **_env)
 {
+	struct expire_env *env = *_env;
+
+	*_env = NULL;
 	pool_unref(&env->pool);
 }
 
--- a/src/plugins/expire/expire-env.h	Tue Jul 07 13:25:01 2009 -0400
+++ b/src/plugins/expire/expire-env.h	Tue Jul 07 14:19:05 2009 -0400
@@ -4,9 +4,11 @@
 #define DICT_EXPIRE_PREFIX DICT_PATH_SHARED"expire/"
 
 struct expire_env;
+struct mail_namespace;
 
-struct expire_env *expire_env_init(const char *expunges, const char *altmoves);
-void expire_env_deinit(struct expire_env *env);
+struct expire_env *expire_env_init(struct mail_namespace *namespaces,
+				   const char *expunges, const char *altmoves);
+void expire_env_deinit(struct expire_env **env);
 
 bool expire_box_find(struct expire_env *env, const char *name,
 		     unsigned int *expunge_secs_r,
--- a/src/plugins/expire/expire-plugin.c	Tue Jul 07 13:25:01 2009 -0400
+++ b/src/plugins/expire/expire-plugin.c	Tue Jul 07 14:19:05 2009 -0400
@@ -44,7 +44,7 @@
 const char *expire_plugin_version = PACKAGE_VERSION;
 
 static void (*next_hook_mailbox_allocated)(struct mailbox *box);
-static void (*next_hook_mail_user_created)(struct mail_user *user);
+static void (*next_hook_mail_namespaces_created)(struct mail_namespace *ns);
 
 static MODULE_CONTEXT_DEFINE_INIT(expire_storage_module,
 				  &mail_storage_module_register);
@@ -282,13 +282,14 @@
 	struct expire_mail_user *euser = EXPIRE_USER_CONTEXT(user);
 
 	dict_deinit(&euser->db);
-	expire_env_deinit(euser->env);
+	expire_env_deinit(&euser->env);
 
 	euser->module_ctx.super.deinit(user);
 }
 
-static void expire_mail_user_created(struct mail_user *user)
+static void expire_mail_namespaces_created(struct mail_namespace *ns)
 {
+	struct mail_user *user = ns->user;
 	struct expire_mail_user *euser;
 	const char *expunge_env, *altmove_env, *dict_uri, *service_name;
 
@@ -310,7 +311,7 @@
 		euser->module_ctx.super = user->v;
 		user->v.deinit = expire_mail_user_deinit;
 
-		euser->env = expire_env_init(expunge_env, altmove_env);
+		euser->env = expire_env_init(ns, expunge_env, altmove_env);
 		/* we're using only shared dictionary, the username
 		   doesn't matter. */
 		euser->db = dict_init(dict_uri, DICT_DATA_TYPE_UINT32, "",
@@ -321,8 +322,8 @@
 			MODULE_CONTEXT_SET(user, expire_mail_user_module, euser);
 	}
 
-	if (next_hook_mail_user_created != NULL)
-		next_hook_mail_user_created(user);
+	if (next_hook_mail_namespaces_created != NULL)
+		next_hook_mail_namespaces_created(ns);
 }
 
 void expire_plugin_init(void)
@@ -330,12 +331,12 @@
 	next_hook_mailbox_allocated = hook_mailbox_allocated;
 	hook_mailbox_allocated = expire_mailbox_allocated;
 
-	next_hook_mail_user_created = hook_mail_user_created;
-	hook_mail_user_created = expire_mail_user_created;
+	next_hook_mail_namespaces_created = hook_mail_namespaces_created;
+	hook_mail_namespaces_created = expire_mail_namespaces_created;
 }
 
 void expire_plugin_deinit(void)
 {
 	hook_mailbox_allocated = next_hook_mailbox_allocated;
-	hook_mail_user_created = next_hook_mail_user_created;
+	hook_mail_namespaces_created = next_hook_mail_namespaces_created;
 }
--- a/src/plugins/expire/expire-tool.c	Tue Jul 07 13:25:01 2009 -0400
+++ b/src/plugins/expire/expire-tool.c	Tue Jul 07 14:19:05 2009 -0400
@@ -20,17 +20,59 @@
 	pool_t multi_user_pool;
 	struct mail_storage_service_multi_ctx *multi;
 	struct mail_user *mail_user;
+	struct expire_env *env;
 	bool testrun;
 };
 
+static int expire_init_user(struct expire_context *ctx, const char *user)
+{
+	struct mail_storage_service_input input;
+	struct mail_storage_service_multi_user *multi_user;
+	const char *expire, *expire_altmove, *errstr;
+	int ret;
+
+	i_set_failure_prefix(t_strdup_printf("expire-tool(%s): ", user));
+
+	memset(&input, 0, sizeof(input));
+	input.username = user;
+
+	p_clear(ctx->multi_user_pool);
+	ret = mail_storage_service_multi_lookup(ctx->multi, &input,
+						ctx->multi_user_pool,
+						&multi_user, &errstr);
+	if (ret <= 0) {
+		if (ret < 0 || ctx->testrun)
+			i_error("User lookup failed: %s", errstr);
+		return ret;
+	}
+	ret = mail_storage_service_multi_next(ctx->multi, multi_user,
+					      &ctx->mail_user, &errstr);
+	if (ret < 0) {
+		i_error("User init failed: %s", errstr);
+		return ret;
+	}
+
+	expire = mail_user_set_plugin_getenv(ctx->mail_user->set, "expire");
+	expire_altmove = mail_user_set_plugin_getenv(ctx->mail_user->set, 
+						     "expire_altmove");
+	if (expire == NULL && expire_altmove == NULL)
+		i_fatal("expire and expire_altmove settings not set");
+
+	ctx->env = expire_env_init(ctx->mail_user->namespaces,
+				   expire, expire_altmove);
+	return 1;
+}
+
+static void expire_deinit_user(struct expire_context *ctx)
+{
+	mail_user_unref(&ctx->mail_user);
+	expire_env_deinit(&ctx->env);
+}
+
 static int
 mailbox_delete_old_mails(struct expire_context *ctx, const char *user,
-			 const char *mailbox,
-			 unsigned int expunge_secs, unsigned int altmove_secs,
-			 time_t *oldest_r)
+			 const char *mailbox, time_t *next_expire_r)
 {
-	struct mail_storage_service_input input;
-	struct mail_storage_service_multi_user *multi_user;
 	struct mail_namespace *ns;
 	struct mailbox *box;
 	struct mail_search_context *search_ctx;
@@ -38,37 +80,29 @@
 	struct mail_search_args *search_args;
 	struct mail *mail;
 	const char *ns_mailbox, *errstr;
+	unsigned int expunge_secs, altmove_secs;
 	time_t now, save_time;
 	enum mail_error error;
 	enum mail_flags flags;
 	int ret;
 
-	memset(&input, 0, sizeof(input));
-	input.username = user;
-
-	*oldest_r = 0;
+	*next_expire_r = 0;
 
 	if (ctx->mail_user != NULL &&
 	    strcmp(user, ctx->mail_user->username) != 0)
-		mail_user_unref(&ctx->mail_user);
+		expire_deinit_user(ctx);
 	if (ctx->mail_user == NULL) {
-		i_set_failure_prefix(t_strdup_printf("expire-tool(%s): ",
-						     user));
-		p_clear(ctx->multi_user_pool);
-		ret = mail_storage_service_multi_lookup(ctx->multi, &input,
-							ctx->multi_user_pool,
-							&multi_user, &errstr);
-		if (ret <= 0) {
-			if (ret < 0 || ctx->testrun)
-				i_error("User lookup failed: %s", errstr);
+		if ((ret = expire_init_user(ctx, user)) <= 0)
 			return ret;
+	}
+
+	if (!expire_box_find(ctx->env, mailbox, &expunge_secs, &altmove_secs)) {
+		/* we're no longer expunging old messages from here */
+		if (ctx->testrun) {
+			i_info("%s: mailbox '%s' removed from config",
+			       user, mailbox);
 		}
-		ret = mail_storage_service_multi_next(ctx->multi, multi_user,
-						      &ctx->mail_user, &errstr);
-		if (ret < 0) {
-			i_error("User init failed: %s", errstr);
-			return ret;
-		}
+		return 0;
 	}
 
 	ns_mailbox = mailbox;
@@ -140,7 +174,9 @@
 			}
 		} else {
 			/* first non-expired one. */
-			*oldest_r = save_time;
+			*next_expire_r = save_time +
+				(altmove_secs != 0 ?
+				 altmove_secs : expunge_secs);
 			break;
 		}
 	}
@@ -170,10 +206,8 @@
 	void **sets;
 	struct dict_transaction_context *trans;
 	struct dict_iterate_context *iter;
-	struct expire_env *env;
-	time_t oldest, expire_time;
-	unsigned int expunge_secs, altmove_secs;
-	const char *p, *key, *value, *expire, *expire_altmove, *expire_dict;
+	time_t next_expire, expire_time;
+	const char *p, *key, *value, *expire_dict;
 	const char *userp = NULL, *mailbox;
 	int ret;
 
@@ -185,17 +219,11 @@
 	sets = master_service_settings_get_others(service);
 	user_set = sets[0];
 
-	expire = mail_user_set_plugin_getenv(user_set, "expire");
-	expire_altmove = mail_user_set_plugin_getenv(user_set, "expire_altmove");
 	expire_dict = mail_user_set_plugin_getenv(user_set, "expire_dict");
-
-	if (expire == NULL && expire_altmove == NULL)
-		i_fatal("expire and expire_altmove settings not set");
 	if (expire_dict == NULL)
 		i_fatal("expire_dict setting not set");
 
 	ctx.testrun = testrun;
-	env = expire_env_init(expire, expire_altmove);
 	dict = dict_init(expire_dict, DICT_DATA_TYPE_UINT32, "",
 			 user_set->base_dir);
 	if (dict == NULL)
@@ -219,17 +247,6 @@
 		}
 
 		mailbox = p + 1;
-		if (!expire_box_find(env, mailbox,
-				     &expunge_secs, &altmove_secs)) {
-			/* we're no longer expunging old messages from here */
-			if (!testrun)
-				dict_unset(trans, key);
-			else {
-				i_info("%s: mailbox '%s' removed from config",
-				       userp, mailbox);
-			}
-			continue;
-		}
 		expire_time = strtoul(value, NULL, 10);
 		if (time(NULL) < expire_time) {
 			/* this and the rest of the timestamps are in future,
@@ -246,13 +263,12 @@
 
 			username = t_strdup_until(userp, p);
 			ret = mailbox_delete_old_mails(&ctx, username,
-						       mailbox, expunge_secs,
-						       altmove_secs, &oldest);
+						       mailbox, &next_expire);
 		} T_END;
 
 		if (ret < 0) {
 			/* failed to update */
-		} else if (oldest == 0) {
+		} else if (next_expire == 0) {
 			/* no more messages or mailbox deleted */
 			if (!testrun)
 				dict_unset(trans, key);
@@ -261,10 +277,8 @@
 		} else {
 			char new_value[MAX_INT_STRLEN];
 
-			oldest += altmove_secs != 0 ?
-				altmove_secs : expunge_secs;
 			i_snprintf(new_value, sizeof(new_value), "%lu",
-				   (unsigned long)oldest);
+				   (unsigned long)next_expire);
 			if (strcmp(value, new_value) == 0) {
 				/* no change */
 			} else if (!testrun)
@@ -274,7 +288,7 @@
 				       userp, value,
 				       t_strcut(ctime(&expire_time), '\n'),
 				       new_value,
-				       t_strcut(ctime(&oldest), '\n'));
+				       t_strcut(ctime(&next_expire), '\n'));
 			} T_END;
 		}
 	}
@@ -289,7 +303,7 @@
 	dict_deinit(&dict);
 
 	if (ctx.mail_user != NULL)
-		mail_user_unref(&ctx.mail_user);
+		expire_deinit_user(&ctx);
 	mail_storage_service_multi_deinit(&ctx.multi);
 	pool_unref(&ctx.multi_user_pool);
 }