changeset 8082:db66611fd195 HEAD

Added struct mail_user and fixed the code to support multiple users per process.
author Timo Sirainen <tss@iki.fi>
date Tue, 12 Aug 2008 12:28:42 -0400
parents 0d5fba71cb93
children bed6d0895dce
files src/deliver/deliver.c src/imap/client.c src/imap/client.h src/imap/cmd-list.c src/imap/cmd-namespace.c src/imap/cmd-subscribe.c src/imap/commands-util.c src/imap/main.c src/lib-storage/Makefile.am src/lib-storage/index/maildir/maildir-storage.c src/lib-storage/index/mbox/mbox-save.c src/lib-storage/index/mbox/mbox-storage.c src/lib-storage/mail-namespace.c src/lib-storage/mail-namespace.h src/lib-storage/mail-storage-private.h src/lib-storage/mail-storage.c src/lib-storage/mail-storage.h src/plugins/acl/acl-mailbox-list.c src/plugins/convert/convert-plugin.c src/plugins/convert/convert-storage.c src/plugins/convert/convert-storage.h src/plugins/convert/convert-tool.c src/plugins/expire/expire-plugin.c src/plugins/expire/expire-tool.c src/plugins/imap-quota/imap-quota-plugin.c src/plugins/lazy-expunge/lazy-expunge-plugin.c src/plugins/quota/quota-count.c src/plugins/quota/quota-dict.c src/plugins/quota/quota-maildir.c src/plugins/quota/quota-plugin.c src/plugins/quota/quota-plugin.h src/plugins/quota/quota-private.h src/plugins/quota/quota-storage.c src/plugins/quota/quota.c src/plugins/quota/quota.h src/plugins/trash/trash-plugin.c src/plugins/virtual/virtual-config.c src/plugins/virtual/virtual-plugin.c src/plugins/virtual/virtual-plugin.h src/plugins/virtual/virtual-storage.c src/pop3/client.c src/pop3/client.h src/pop3/main.c
diffstat 43 files changed, 515 insertions(+), 376 deletions(-) [+]
line wrap: on
line diff
--- a/src/deliver/deliver.c	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/deliver/deliver.c	Tue Aug 12 12:28:42 2008 -0400
@@ -777,7 +777,8 @@
 	const char *auth_socket;
 	const char *home, *destaddr, *user, *value, *errstr, *path;
 	ARRAY_TYPE(string) extra_fields;
-	struct mail_namespace *ns, *raw_ns;
+	struct mail_user *mail_user, *raw_mail_user;
+	struct mail_namespace *raw_ns;
 	struct mail_storage *storage;
 	struct mailbox *box;
 	struct raw_mailbox *raw_box;
@@ -1002,12 +1003,16 @@
 	module_dir_init(modules);
 
 	namespace_pool = pool_alloconly_create("namespaces", 1024);
-	if (mail_namespaces_init(namespace_pool, user, &ns) < 0)
+	mail_user = mail_user_init(user, home);
+	if (mail_namespaces_init(namespace_pool, mail_user) < 0)
 		i_fatal("Namespace initialization failed");
 
-	raw_ns = mail_namespaces_init_empty(namespace_pool);
+	/* create a separate mail user for the internal namespace */
+	raw_mail_user = mail_user_init(user, NULL);
+	raw_ns = mail_namespaces_init_empty(namespace_pool, raw_mail_user);
 	raw_ns->flags |= NAMESPACE_FLAG_INTERNAL;
-	if (mail_storage_create(raw_ns, "raw", "/tmp", user,
+
+	if (mail_storage_create(raw_ns, "raw", "/tmp",
 				MAIL_STORAGE_FLAG_FULL_FS_ACCESS,
 				FILE_LOCK_METHOD_FCNTL, &errstr) < 0)
 		i_fatal("Couldn't create internal raw storage: %s", errstr);
@@ -1044,7 +1049,8 @@
 	if (deliver_mail == NULL)
 		ret = -1;
 	else {
-		if (deliver_mail(ns, &storage, mail, destaddr, mailbox) <= 0) {
+		if (deliver_mail(mail_user->namespaces, &storage, mail,
+				 destaddr, mailbox) <= 0) {
 			/* if message was saved, don't bounce it even though
 			   the script failed later. */
 			ret = saved_mail ? 0 : -1;
@@ -1056,12 +1062,14 @@
 
 	if (ret < 0 && !tried_default_save) {
 		/* plugins didn't handle this. save into the default mailbox. */
-		ret = deliver_save(ns, &storage, mailbox, mail, 0, NULL);
+		ret = deliver_save(mail_user->namespaces,
+				   &storage, mailbox, mail, 0, NULL);
 	}
 	if (ret < 0 && strcasecmp(mailbox, "INBOX") != 0) {
 		/* still didn't work. try once more to save it
 		   to INBOX. */
-		ret = deliver_save(ns, &storage, "INBOX", mail, 0, NULL);
+		ret = deliver_save(mail_user->namespaces,
+				   &storage, "INBOX", mail, 0, NULL);
 	}
 
 	if (ret < 0 ) {
@@ -1108,8 +1116,8 @@
 	mailbox_transaction_rollback(&t);
 	mailbox_close(&box);
 
-	mail_namespaces_deinit(&raw_ns);
-	mail_namespaces_deinit(&ns);
+	mail_user_deinit(&mail_user);
+	mail_user_deinit(&raw_mail_user);
 
 	module_dir_unload(&modules);
 	mail_storage_deinit();
--- a/src/imap/client.c	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/imap/client.c	Tue Aug 12 12:28:42 2008 -0400
@@ -25,10 +25,10 @@
 	client_destroy(client, "Disconnected for inactivity");
 }
 
-struct client *client_create(int fd_in, int fd_out,
-			     struct mail_namespace *namespaces)
+struct client *client_create(int fd_in, int fd_out, struct mail_user *user)
 {
 	struct client *client;
+	struct mail_namespace *ns;
 
 	/* always use nonblocking I/O */
 	net_set_nonblock(fd_in, TRUE);
@@ -48,12 +48,11 @@
 				      client_idle_timeout, client);
 
 	client->command_pool = pool_alloconly_create("client command", 1024*12);
-	client->namespaces = namespaces;
+	client->user = user;
 
-	while (namespaces != NULL) {
-		mail_storage_set_callbacks(namespaces->storage,
+	for (ns = user->namespaces; ns != NULL; ns = ns->next) {
+		mail_storage_set_callbacks(ns->storage,
 					   &mail_storage_callbacks, client);
-		namespaces = namespaces->next;
 	}
 
 	i_assert(my_client == NULL);
@@ -130,6 +129,7 @@
 void client_destroy(struct client *client, const char *reason)
 {
 	struct client_command_context *cmd;
+
 	i_assert(!client->destroyed);
 	client->destroyed = TRUE;
 
@@ -161,7 +161,7 @@
 		client_search_updates_free(client);
 		mailbox_close(&client->mailbox);
 	}
-	mail_namespaces_deinit(&client->namespaces);
+	mail_user_deinit(&client->user);
 
 	if (client->free_parser != NULL)
 		imap_parser_destroy(&client->free_parser);
--- a/src/imap/client.h	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/imap/client.h	Tue Aug 12 12:28:42 2008 -0400
@@ -74,7 +74,7 @@
 	struct ostream *output;
 	struct timeout *to_idle, *to_idle_output;
 
-        struct mail_namespace *namespaces;
+	struct mail_user *user;
 	struct mailbox *mailbox;
         struct mailbox_keywords keywords;
 	unsigned int select_counter; /* increased when mailbox is changed */
@@ -124,8 +124,7 @@
 
 /* Create new client with specified input/output handles. socket specifies
    if the handle is a socket. */
-struct client *client_create(int fd_in, int fd_out,
-			     struct mail_namespace *namespaces);
+struct client *client_create(int fd_in, int fd_out, struct mail_user *user);
 void client_destroy(struct client *client, const char *reason);
 
 /* Disconnect client connection */
--- a/src/imap/cmd-list.c	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/imap/cmd-list.c	Tue Aug 12 12:28:42 2008 -0400
@@ -185,7 +185,7 @@
 	}
 
 	/* find the INBOX flags */
-	ns = mail_namespace_find_inbox(ctx->cmd->client->namespaces);
+	ns = mail_namespace_find_inbox(ctx->cmd->client->user->namespaces);
 	list_iter = mailbox_list_iter_init(ns->list, "INBOX", 0);
 	info = mailbox_list_iter_next(list_iter);
 	if (info != NULL) {
@@ -704,13 +704,13 @@
 	/* Special request to return the hierarchy delimiter and mailbox root
 	   name. If namespace has a prefix, it's returned as the mailbox root.
 	   Otherwise we'll emulate UW-IMAP behavior. */
-	ns = mail_namespace_find_visible(client->namespaces, &ref);
+	ns = mail_namespace_find_visible(client->user->namespaces, &ref);
 	if (ns != NULL) {
 		ns_prefix = ns->prefix;
 		ns_sep = ns->sep;
 	} else {
 		ns_prefix = "";
-		ns_sep = mail_namespace_get_root_sep(client->namespaces);
+		ns_sep = mail_namespace_get_root_sep(client->user->namespaces);
 	}
 
 	str = t_str_new(64);
@@ -754,7 +754,7 @@
 
 	ctx = p_new(cmd->pool, struct cmd_list_context, 1);
 	ctx->cmd = cmd;
-	ctx->ns = client->namespaces;
+	ctx->ns = client->user->namespaces;
 	ctx->lsub = lsub;
 
 	cmd->context = ctx;
--- a/src/imap/cmd-namespace.c	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/imap/cmd-namespace.c	Tue Aug 12 12:28:42 2008 -0400
@@ -42,11 +42,11 @@
 	str = t_str_new(256);
 	str_append(str, "* NAMESPACE ");
 
-        list_namespaces(client->namespaces, NAMESPACE_PRIVATE, str);
+        list_namespaces(client->user->namespaces, NAMESPACE_PRIVATE, str);
 	str_append_c(str, ' ');
-	list_namespaces(client->namespaces, NAMESPACE_SHARED, str);
+	list_namespaces(client->user->namespaces, NAMESPACE_SHARED, str);
 	str_append_c(str, ' ');
-        list_namespaces(client->namespaces, NAMESPACE_PUBLIC, str);
+        list_namespaces(client->user->namespaces, NAMESPACE_PUBLIC, str);
 
 	client_send_line(client, str_c(str));
 	client_send_tagline(cmd, "OK Namespace completed.");
--- a/src/imap/cmd-subscribe.c	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/imap/cmd-subscribe.c	Tue Aug 12 12:28:42 2008 -0400
@@ -35,7 +35,7 @@
 		return FALSE;
 
 	verify_name = mailbox;
-	ns = mail_namespace_find_subscribable(cmd->client->namespaces,
+	ns = mail_namespace_find_subscribable(cmd->client->user->namespaces,
 					      &mailbox);
 	if (ns == NULL) {
 		client_send_tagline(cmd, "NO Unknown namespace.");
@@ -49,7 +49,7 @@
 		verify_name = t_strndup(verify_name, strlen(verify_name)-1);
 	}
 
-	if (have_listable_namespace_prefix(cmd->client->namespaces,
+	if (have_listable_namespace_prefix(cmd->client->user->namespaces,
 					   verify_name)) {
 		/* subscribing to a listable namespace prefix, allow it. */
 	} else {
--- a/src/imap/commands-util.c	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/imap/commands-util.c	Tue Aug 12 12:28:42 2008 -0400
@@ -23,7 +23,7 @@
 {
 	struct mail_namespace *ns;
 
-	ns = mail_namespace_find(cmd->client->namespaces, mailbox);
+	ns = mail_namespace_find(cmd->client->user->namespaces, mailbox);
 	if (ns != NULL)
 		return ns;
 
--- a/src/imap/main.c	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/imap/main.c	Tue Aug 12 12:28:42 2008 -0400
@@ -161,8 +161,8 @@
 {
 	struct client *client;
 	struct ostream *output;
-	struct mail_namespace *ns;
-	const char *user, *str, *tag;
+	struct mail_user *user;
+	const char *username, *home, *str, *tag;
 
 	lib_signals_init();
         lib_signals_set_handler(SIGINT, TRUE, sig_die, NULL);
@@ -170,18 +170,16 @@
         lib_signals_ignore(SIGPIPE, TRUE);
         lib_signals_ignore(SIGALRM, FALSE);
 
-	user = getenv("USER");
-	if (user == NULL) {
+	username = getenv("USER");
+	if (username == NULL) {
 		if (IS_STANDALONE())
-			user = getlogin();
-		if (user == NULL)
+			username = getlogin();
+		if (username == NULL)
 			i_fatal("USER environment missing");
 	}
 
+	home = getenv("HOME");
 	if (getenv("DEBUG") != NULL) {
-		const char *home;
-
-		home = getenv("HOME");
 		i_info("Effective uid=%s, gid=%s, home=%s",
 		       dec2str(geteuid()), dec2str(getegid()),
 		       home != NULL ? home : "(none)");
@@ -232,9 +230,10 @@
         parse_workarounds();
 
 	namespace_pool = pool_alloconly_create("namespaces", 1024);
-	if (mail_namespaces_init(namespace_pool, user, &ns) < 0)
+	user = mail_user_init(username, home);
+	if (mail_namespaces_init(namespace_pool, user) < 0)
 		i_fatal("Namespace initialization failed");
-	client = client_create(0, 1, ns);
+	client = client_create(0, 1, user);
 
 	output = client->output;
 	o_stream_ref(output);
@@ -246,7 +245,7 @@
 		client_send_line(client, t_strconcat(
 			"* PREAUTH [CAPABILITY ",
 			str_c(capability_string), "] "
-			"Logged in as ", user, NULL));
+			"Logged in as ", user->username, NULL));
 	} else {
 		client_send_line(client, t_strconcat(
 			tag, " OK [CAPABILITY ",
--- a/src/lib-storage/Makefile.am	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/lib-storage/Makefile.am	Tue Aug 12 12:28:42 2008 -0400
@@ -16,6 +16,7 @@
 	mail-search.c \
 	mail-search-build.c \
 	mail-storage.c \
+	mail-user.c \
 	mailbox-list.c \
 	mailbox-search-result.c \
 	mailbox-tree.c
@@ -29,6 +30,7 @@
 	mail-thread.h \
 	mail-storage.h \
 	mail-storage-private.h \
+	mail-user.h \
 	mailbox-list.h \
 	mailbox-list-private.h \
 	mailbox-search-result-private.h \
--- a/src/lib-storage/index/maildir/maildir-storage.c	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/lib-storage/index/maildir/maildir-storage.c	Tue Aug 12 12:28:42 2008 -0400
@@ -60,11 +60,13 @@
 
 static int
 maildir_get_list_settings(struct mailbox_list_settings *list_set,
-			  const char *data, enum mail_storage_flags flags,
+			  const char *data, struct mail_storage *storage,
 			  const char **layout_r, const char **error_r)
 {
+	enum mail_storage_flags flags = storage->flags;
+	struct mail_user *user = storage->ns->user;
 	bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
-	const char *home, *path;
+	const char *path;
 
 	*layout_r = MAILDIR_PLUSPLUS_DRIVER_NAME;
 
@@ -79,9 +81,9 @@
 		}
 
 		/* we'll need to figure out the maildir location ourself.
-		   It's $HOME/Maildir unless we are chrooted. */
-		if ((home = getenv("HOME")) != NULL) {
-			path = t_strconcat(home, "/Maildir", NULL);
+		   It's ~/Maildir unless we are chrooted. */
+		if (user->home != NULL) {
+			path = t_strconcat(user->home, "/Maildir", NULL);
 			if (access(path, R_OK|W_OK|X_OK) == 0) {
 				if (debug) {
 					i_info("maildir: root exists (%s)",
@@ -96,7 +98,7 @@
 			}
 		} else {
 			if (debug)
-				i_info("maildir: HOME not set");
+				i_info("maildir: Home directory not set");
 		}
 
 		if (access("/cur", R_OK|W_OK|X_OK) == 0) {
@@ -191,7 +193,7 @@
 	const char *layout;
 	struct stat st;
 
-	if (maildir_get_list_settings(&list_set, data, flags, &layout,
+	if (maildir_get_list_settings(&list_set, data, _storage, &layout,
 				      error_r) < 0)
 		return -1;
 	list_set.mail_storage_flags = &_storage->flags;
--- a/src/lib-storage/index/mbox/mbox-save.c	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/lib-storage/index/mbox/mbox-save.c	Tue Aug 12 12:28:42 2008 -0400
@@ -135,9 +135,11 @@
 		const char *line;
 
 		if (from_envelope == NULL) {
-			from_envelope =
-				t_strconcat(ctx->mbox->storage->storage.user,
-					    "@", my_hostdomain, NULL);
+			struct mail_storage *storage =
+				&ctx->mbox->storage->storage;
+
+			from_envelope = t_strconcat(storage->ns->user->username,
+						    "@", my_hostdomain, NULL);
 		}
 
 		/* save in local timezone, no matter what it was given with */
--- a/src/lib-storage/index/mbox/mbox-storage.c	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/lib-storage/index/mbox/mbox-storage.c	Tue Aug 12 12:28:42 2008 -0400
@@ -185,12 +185,12 @@
 	return FALSE;
 }
 
-static const char *get_root_dir(enum mail_storage_flags flags)
+static const char *get_root_dir(struct mail_storage *storage)
 {
 	const char *home, *path;
-	bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
+	bool debug = (storage->flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
 
-	home = getenv("HOME");
+	home = storage->ns->user->home;
 	if (home != NULL) {
 		path = t_strconcat(home, "/mail", NULL);
 		if (access(path, R_OK|W_OK|X_OK) == 0) {
@@ -213,7 +213,7 @@
 
 	if (debug)
 		i_info("mbox: checking if we are chrooted:");
-	if (mbox_autodetect("", flags))
+	if (mbox_autodetect("", storage->flags))
 		return "/";
 
 	if (debug)
@@ -223,11 +223,12 @@
 }
 
 static const char *
-get_inbox_file(const char *root_dir, bool only_root, bool debug)
+get_inbox_file(const char *user, const char *root_dir,
+	       bool only_root, bool debug)
 {
-	const char *user, *path;
+	const char *path;
 
-	if (!only_root && (user = getenv("USER")) != NULL) {
+	if (!only_root) {
 		path = t_strconcat("/var/mail/", user, NULL);
 		if (access(path, R_OK|W_OK) == 0) {
 			if (debug)
@@ -253,11 +254,12 @@
 	return path;
 }
 
-static const char *create_root_dir(bool debug, const char **error_r)
+static const char *create_root_dir(struct mail_storage *storage,
+				   const char **error_r)
 {
 	const char *home, *path;
 
-	home = getenv("HOME");
+	home = storage->ns->user->home;
 	if (home == NULL) {
 		*error_r = "Root mail directory not set and "
 			"home directory is missing";
@@ -270,16 +272,17 @@
 		return NULL;
 	}
 
-	if (debug)
+	if ((storage->flags & MAIL_STORAGE_FLAG_DEBUG) != 0)
 		i_info("mbox: root directory created: %s", path);
 	return path;
 }
 
 static int
 mbox_get_list_settings(struct mailbox_list_settings *list_set,
-		       const char *data, enum mail_storage_flags flags,
+		       const char *data, struct mail_storage *storage,
 		       const char **layout_r, const char **error_r)
 {
+	enum mail_storage_flags flags = storage->flags;
 	bool debug = (flags & MAIL_STORAGE_FLAG_DEBUG) != 0;
 	const char *p;
 	struct stat st;
@@ -300,8 +303,8 @@
 
 		/* we'll need to figure out the mail location ourself.
 		   it's root dir if we've already chroot()ed, otherwise
-		   either $HOME/mail or $HOME/Mail */
-		list_set->root_dir = get_root_dir(flags);
+		   either ~/mail or ~/Mail */
+		list_set->root_dir = get_root_dir(storage);
 	} else {
 		if (debug)
 			i_info("mbox: data=%s", data);
@@ -313,7 +316,7 @@
 			if (stat(data, &st) < 0 || S_ISDIR(st.st_mode))
 				list_set->root_dir = data;
 			else {
-				list_set->root_dir = get_root_dir(flags);
+				list_set->root_dir = get_root_dir(storage);
 				list_set->inbox_path = data;
 			}
 		} else {
@@ -330,7 +333,7 @@
 			return -1;
 		}
 
-		list_set->root_dir = create_root_dir(debug, error_r);
+		list_set->root_dir = create_root_dir(storage, error_r);
 		if (list_set->root_dir == NULL)
 			return -1;
 	} else {
@@ -360,7 +363,8 @@
 
 	if (list_set->inbox_path == NULL) {
 		list_set->inbox_path =
-			get_inbox_file(list_set->root_dir, !autodetect, debug);
+			get_inbox_file(storage->ns->user->username,
+				       list_set->root_dir, !autodetect, debug);
 	}
 	return 0;
 }
@@ -432,8 +436,8 @@
 	struct mailbox_list_settings list_set;
 	const char *layout;
 
-	if (mbox_get_list_settings(&list_set, data,
-				   _storage->flags, &layout, error_r) < 0)
+	if (mbox_get_list_settings(&list_set, data, _storage,
+				   &layout, error_r) < 0)
 		return -1;
 	list_set.mail_storage_flags = &_storage->flags;
 	list_set.lock_method = &_storage->lock_method;
--- a/src/lib-storage/mail-namespace.c	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/lib-storage/mail-namespace.c	Tue Aug 12 12:28:42 2008 -0400
@@ -29,7 +29,7 @@
 
 static struct mail_namespace *
 namespace_add_env(pool_t pool, const char *data, unsigned int num,
-		  const char *user, enum mail_storage_flags flags,
+		  struct mail_user *user, enum mail_storage_flags flags,
 		  enum file_lock_method lock_method)
 {
         struct mail_namespace *ns;
@@ -77,8 +77,9 @@
 	if (sep != NULL)
 		ns->sep = *sep;
 	ns->prefix = p_strdup(pool, prefix);
+	ns->user = user;
 
-	if (mail_storage_create(ns, NULL, data, user, flags, lock_method,
+	if (mail_storage_create(ns, NULL, data, flags, lock_method,
 				&error) < 0) {
 		i_error("Namespace '%s': %s", ns->prefix, error);
 		return NULL;
@@ -177,8 +178,7 @@
 	return dest;
 }
 
-int mail_namespaces_init(pool_t pool, const char *user,
-			 struct mail_namespace **namespaces_r)
+int mail_namespaces_init(pool_t pool, struct mail_user *user)
 {
 	struct mail_namespace *namespaces, *ns, **ns_p;
 	enum mail_storage_flags flags;
@@ -213,7 +213,7 @@
 		if (!namespaces_check(namespaces))
 			return -1;
 		namespaces = namespaces_sort(namespaces);
-		*namespaces_r = namespaces;
+		user->namespaces = namespaces;
 
 		if (hook_mail_namespaces_created != NULL) {
 			T_BEGIN {
@@ -237,8 +237,9 @@
 	ns->flags = NAMESPACE_FLAG_INBOX | NAMESPACE_FLAG_LIST |
 		NAMESPACE_FLAG_SUBSCRIPTIONS;
 	ns->prefix = "";
+	ns->user = user;
 
-	if (mail_storage_create(ns, NULL, mail, user, flags, lock_method,
+	if (mail_storage_create(ns, NULL, mail, flags, lock_method,
 				&error) < 0) {
 		if (mail != NULL && *mail != '\0')
 			i_error("mail_location: %s", error);
@@ -248,7 +249,7 @@
 		}
 		return -1;
 	}
-	*namespaces_r = ns;
+	user->namespaces = ns;
 
 	if (hook_mail_namespaces_created != NULL) {
 		T_BEGIN {
@@ -258,14 +259,17 @@
 	return 0;
 }
 
-struct mail_namespace *mail_namespaces_init_empty(pool_t pool)
+struct mail_namespace *
+mail_namespaces_init_empty(pool_t pool, struct mail_user *user)
 {
 	struct mail_namespace *ns;
 
 	ns = p_new(pool, struct mail_namespace, 1);
+	ns->user = user;
 	ns->prefix = "";
 	ns->flags = NAMESPACE_FLAG_INBOX | NAMESPACE_FLAG_LIST |
 		NAMESPACE_FLAG_SUBSCRIPTIONS;
+	user->namespaces = ns;
 	return ns;
 }
 
--- a/src/lib-storage/mail-namespace.h	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/lib-storage/mail-namespace.h	Tue Aug 12 12:28:42 2008 -0400
@@ -1,6 +1,8 @@
 #ifndef MAIL_NAMESPACE_H
 #define MAIL_NAMESPACE_H
 
+#include "mail-user.h"
+
 enum namespace_type {
 	NAMESPACE_PRIVATE,
 	NAMESPACE_SHARED,
@@ -32,6 +34,7 @@
 	const char *prefix;
 	size_t prefix_len;
 
+	struct mail_user *user;
 	struct mailbox_list *list;
 	/* FIXME: we should support multiple storages in one namespace */
 	struct mail_storage *storage;
@@ -40,9 +43,9 @@
 /* Called after namespaces has been created */
 extern void (*hook_mail_namespaces_created)(struct mail_namespace *namespaces);
 
-int mail_namespaces_init(pool_t pool, const char *user,
-			 struct mail_namespace **namespaces_r);
-struct mail_namespace *mail_namespaces_init_empty(pool_t pool);
+int mail_namespaces_init(pool_t pool, struct mail_user *user);
+struct mail_namespace *
+mail_namespaces_init_empty(pool_t pool, struct mail_user *user);
 void mail_namespaces_deinit(struct mail_namespace **namespaces);
 
 /* Update hierarchy separators in given name to real_sep characters. */
--- a/src/lib-storage/mail-storage-private.h	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/lib-storage/mail-storage-private.h	Tue Aug 12 12:28:42 2008 -0400
@@ -61,7 +61,6 @@
 	struct mail_namespace *ns;
 	struct mailbox_list *list;
 
-	const char *user; /* name of user accessing the storage */
 	enum mail_storage_flags flags;
 	enum file_lock_method lock_method;
 	unsigned int keyword_max_len;
--- a/src/lib-storage/mail-storage.c	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/lib-storage/mail-storage.c	Tue Aug 12 12:28:42 2008 -0400
@@ -169,8 +169,7 @@
 }
 
 int mail_storage_create(struct mail_namespace *ns, const char *driver,
-			const char *data, const char *user,
-			enum mail_storage_flags flags,
+			const char *data, enum mail_storage_flags flags,
 			enum file_lock_method lock_method,
 			const char **error_r)
 {
@@ -214,7 +213,6 @@
 		storage = classes[i]->v.alloc();
 		storage->flags = flags;
 		storage->lock_method = lock_method;
-		storage->user = p_strdup(storage->pool, user);
 		storage->ns = ns;
 
 		storage->callbacks =
@@ -239,7 +237,7 @@
 			return -1;
 		}
 
-		home = getenv("HOME");
+		home = ns->user->home;
 		if (home == NULL || *home == '\0') home = "(not set)";
 
 		*error_r = t_strdup_printf(
--- a/src/lib-storage/mail-storage.h	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/lib-storage/mail-storage.h	Tue Aug 12 12:28:42 2008 -0400
@@ -248,8 +248,7 @@
    from data. If data is NULL, it uses the first storage that exists.
    The storage is put into ns->storage. */
 int mail_storage_create(struct mail_namespace *ns, const char *driver,
-			const char *data, const char *user,
-			enum mail_storage_flags flags,
+			const char *data, enum mail_storage_flags flags,
 			enum file_lock_method lock_method,
 			const char **error_r);
 void mail_storage_destroy(struct mail_storage **storage);
--- a/src/plugins/acl/acl-mailbox-list.c	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/plugins/acl/acl-mailbox-list.c	Tue Aug 12 12:28:42 2008 -0400
@@ -415,10 +415,7 @@
 	acl_env = getenv("ACL");
 	i_assert(acl_env != NULL);
 
-	owner_username = getenv("USER");
-	if (owner_username == NULL)
-		i_fatal("ACL: USER environment not set");
-
+	owner_username = list->ns->user->username;
 	current_username = getenv("MASTER_USER");
 	if (current_username == NULL)
 		current_username = owner_username;
@@ -432,7 +429,6 @@
 	if (ns->type != NAMESPACE_PRIVATE)
 		owner = FALSE;
 
-	/* FIXME: set groups */
 	backend = acl_backend_init(acl_env, list, current_username,
 				   getenv("ACL_GROUPS") == NULL ? NULL :
 				   t_strsplit(getenv("ACL_GROUPS"), ","),
--- a/src/plugins/convert/convert-plugin.c	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/plugins/convert/convert-plugin.c	Tue Aug 12 12:28:42 2008 -0400
@@ -19,11 +19,7 @@
 	struct convert_settings set;
 
 	memset(&set, 0, sizeof(set));
-	set.user = getenv("USER");
-	if (set.user == NULL)
-		i_fatal("convert plugin: USER unset");
-	set.home = getenv("HOME");
-	if (set.home == NULL)
+	if (namespaces->user->home == NULL)
 		i_fatal("convert plugin: HOME unset");
 
 	set.skip_broken_mailboxes =
--- a/src/plugins/convert/convert-storage.c	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/plugins/convert/convert-storage.c	Tue Aug 12 12:28:42 2008 -0400
@@ -392,6 +392,7 @@
 		    struct mail_namespace *dest_namespaces,
 		    const struct convert_settings *set)
 {
+	struct mail_user *user = dest_namespaces->user;
 	struct mail_namespace *source_ns, *dest_inbox_ns;
 	struct dotlock *dotlock;
         enum mail_storage_flags src_flags;
@@ -399,19 +400,19 @@
 	const char *path, *error;
 	int ret;
 
-	source_ns = mail_namespaces_init_empty(pool_datastack_create());
+	source_ns = mail_namespaces_init_empty(pool_datastack_create(), user);
 	dest_inbox_ns = mail_namespace_find_inbox(dest_namespaces);
 	src_flags = dest_inbox_ns->storage->flags;
 	lock_method = dest_inbox_ns->storage->lock_method;
 
 	src_flags |= MAIL_STORAGE_FLAG_NO_AUTOCREATE;
-	if (mail_storage_create(source_ns, NULL, source_data, set->user,
+	if (mail_storage_create(source_ns, NULL, source_data,
 				src_flags, lock_method, &error) < 0) {
 		/* No need for conversion. */
 		return 0;
 	}
 
-        path = t_strconcat(set->home, "/"CONVERT_LOCK_FILENAME, NULL);
+        path = t_strconcat(user->home, "/"CONVERT_LOCK_FILENAME, NULL);
 	dotlock_settings.use_excl_lock =
 		(source_ns->storage->flags &
 		 MAIL_STORAGE_FLAG_DOTLOCK_USE_EXCL) != 0;
@@ -430,7 +431,7 @@
 	/* just in case if another process just had converted the mailbox,
 	   reopen the source storage */
 	mail_storage_destroy(&source_ns->storage);
-	if (mail_storage_create(source_ns, NULL, source_data, set->user,
+	if (mail_storage_create(source_ns, NULL, source_data,
 				src_flags, lock_method, &error) < 0) {
 		/* No need for conversion anymore. */
 		file_dotlock_delete(&dotlock);
--- a/src/plugins/convert/convert-storage.h	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/plugins/convert/convert-storage.h	Tue Aug 12 12:28:42 2008 -0400
@@ -4,8 +4,6 @@
 struct mail_namespace;
 
 struct convert_settings {
-	const char *user;
-	const char *home;
 	bool skip_broken_mailboxes;
 	bool skip_dotdirs;
 	char alt_hierarchy_char;
--- a/src/plugins/convert/convert-tool.c	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/plugins/convert/convert-tool.c	Tue Aug 12 12:28:42 2008 -0400
@@ -18,6 +18,7 @@
 {
 	struct ioloop *ioloop;
 	struct convert_settings set;
+	struct mail_user *user;
 	struct mail_namespace *dest_ns;
         enum mail_storage_flags dest_flags;
 	enum file_lock_method lock_method;
@@ -37,9 +38,6 @@
 	ioloop = io_loop_create();
 
 	memset(&set, 0, sizeof(set));
-	set.user = argv[1];
-	set.home = argv[2];
-
 	for (i = 5; i < argc; i++) {
 		if (strcmp(argv[i], "skip_broken_mailboxes") != 0)
 			set.skip_broken_mailboxes = TRUE;
@@ -50,8 +48,10 @@
 	}
 
 	mail_storage_parse_env(&dest_flags, &lock_method);
-	dest_ns = mail_namespaces_init_empty(pool_datastack_create());
-	if (mail_storage_create(dest_ns, NULL, argv[4], set.user,
+	user = mail_user_init(argv[1], argv[2]);
+	dest_ns = mail_namespaces_init_empty(pool_datastack_create(), user);
+
+	if (mail_storage_create(dest_ns, NULL, argv[4],
 				dest_flags, lock_method, &error) < 0) {
 		i_fatal("Failed to create destination "
 			"mail storage with data '%s': %s", argv[4], error);
@@ -64,7 +64,7 @@
 		i_error("Source storage not found");
 	else
 		i_error("Internal failure");
-	mail_namespaces_deinit(&dest_ns);
+	mail_user_deinit(&user);
 
 	io_loop_destroy(&ioloop);
 	mail_storage_deinit();
--- a/src/plugins/expire/expire-plugin.c	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/plugins/expire/expire-plugin.c	Tue Aug 12 12:28:42 2008 -0400
@@ -294,6 +294,7 @@
 		if (dict_uri == NULL)
 			i_fatal("expire plugin: expire_dict setting missing");
 
+		// FIXME: user should be per-mail_user?...
 		expire.username = getenv("USER");
 		expire.env = expire_env_init(expunge_env, altmove_env);
 		expire.db = dict_init(dict_uri, DICT_DATA_TYPE_UINT32, expire.username);
--- a/src/plugins/expire/expire-tool.c	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/plugins/expire/expire-tool.c	Tue Aug 12 12:28:42 2008 -0400
@@ -2,6 +2,7 @@
 
 #include "lib.h"
 #include "ioloop.h"
+#include "env-util.h"
 #include "file-lock.h"
 #include "randgen.h"
 #include "lib-signals.h"
@@ -25,8 +26,8 @@
 	struct auth_connection *auth_conn;
 
 	char *user;
+	struct mail_user *mail_user;
 	pool_t namespace_pool;
-	struct mail_namespace *ns;
 	bool testrun;
 };
 
@@ -34,6 +35,7 @@
 {
 	int ret;
 
+	env_clean();
 	if ((ret = auth_client_put_user_env(ctx->auth_conn, user)) <= 0) {
 		if (ret < 0)
 			return ret;
@@ -42,14 +44,15 @@
 		return 0;
 	}
 
-	if (mail_namespaces_init(ctx->namespace_pool, user, &ctx->ns) < 0)
+	ctx->mail_user = mail_user_init(user, getenv("HOME"));
+	if (mail_namespaces_init(ctx->namespace_pool, ctx->mail_user) < 0)
 		return -1;
 	return 1;
 }
 
 static void user_deinit(struct expire_context *ctx)
 {
-	mail_namespaces_deinit(&ctx->ns);
+	mail_user_deinit(&ctx->mail_user);
 	i_free_and_null(ctx->user);
 	p_clear(ctx->namespace_pool);
 }
@@ -86,7 +89,7 @@
 	}
 
 	ns_mailbox = mailbox;
-	ns = mail_namespace_find(ctx->ns, &ns_mailbox);
+	ns = mail_namespace_find(ctx->mail_user->namespaces, &ns_mailbox);
 	if (ns == NULL) {
 		/* entire namespace no longer exists, remove the entry */
 		if (ctx->testrun)
--- a/src/plugins/imap-quota/imap-quota-plugin.c	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/plugins/imap-quota/imap-quota-plugin.c	Tue Aug 12 12:28:42 2008 -0400
@@ -82,7 +82,7 @@
 	str_append(str, "* QUOTAROOT ");
 	imap_quote_append_string(str, orig_mailbox, FALSE);
 
-	iter = quota_root_iter_init(quota_set, box);
+	iter = quota_root_iter_init(box);
 	while ((root = quota_root_iter_next(iter)) != NULL) {
 		str_append_c(str, ' ');
 		imap_quote_append_string(str, quota_root_get_name(root), FALSE);
@@ -91,7 +91,7 @@
 	client_send_line(cmd->client, str_c(str));
 
 	/* send QUOTA reply for each quotaroot */
-	iter = quota_root_iter_init(quota_set, box);
+	iter = quota_root_iter_init(box);
 	while ((root = quota_root_iter_next(iter)) != NULL)
 		quota_send(cmd, root);
 	quota_root_iter_deinit(&iter);
@@ -115,7 +115,7 @@
 		return TRUE;
 	}
 
-	root = quota_root_lookup(quota_set, root_name);
+	root = quota_root_lookup(cmd->client->user, root_name);
 	if (root == NULL) {
 		client_send_tagline(cmd, "NO Quota root doesn't exist.");
 		return TRUE;
@@ -148,7 +148,7 @@
 		return TRUE;
 	}
 
-	root = quota_root_lookup(quota_set, root_name);
+	root = quota_root_lookup(cmd->client->user, root_name);
 	if (root == NULL) {
 		client_send_tagline(cmd, "NO Quota root doesn't exist.");
 		return TRUE;
--- a/src/plugins/lazy-expunge/lazy-expunge-plugin.c	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/plugins/lazy-expunge/lazy-expunge-plugin.c	Tue Aug 12 12:28:42 2008 -0400
@@ -19,6 +19,8 @@
 	MODULE_CONTEXT(obj, lazy_expunge_mail_storage_module)
 #define LAZY_EXPUNGE_LIST_CONTEXT(obj) \
 	MODULE_CONTEXT(obj, lazy_expunge_mailbox_list_module)
+#define LAZY_EXPUNGE_USER_CONTEXT(obj) \
+	MODULE_CONTEXT(obj, lazy_expunge_mail_user_module)
 
 enum lazy_namespace {
 	LAZY_NAMESPACE_EXPUNGE,
@@ -28,6 +30,12 @@
 	LAZY_NAMESPACE_COUNT
 };
 
+struct lazy_expunge_mail_user {
+	union mail_user_module_context module_ctx;
+
+	struct mail_namespace *lazy_ns[LAZY_NAMESPACE_COUNT];
+};
+
 struct lazy_expunge_mailbox_list {
 	union mailbox_list_module_context module_ctx;
 
@@ -57,6 +65,7 @@
 	(struct mail_storage *storage);
 static void (*lazy_expunge_next_hook_mailbox_list_created)
 	(struct mailbox_list *list);
+static void (*lazy_expunge_next_hook_mail_user_created)(struct mail_user *user);
 
 static MODULE_CONTEXT_DEFINE_INIT(lazy_expunge_mail_storage_module,
 				  &mail_storage_module_register);
@@ -64,8 +73,8 @@
 				  &mail_module_register);
 static MODULE_CONTEXT_DEFINE_INIT(lazy_expunge_mailbox_list_module,
 				  &mailbox_list_module_register);
-
-static struct mail_namespace *lazy_namespaces[LAZY_NAMESPACE_COUNT];
+static MODULE_CONTEXT_DEFINE_INIT(lazy_expunge_mail_user_module,
+				  &mail_user_module_register);
 
 static struct mailbox *
 mailbox_open_or_create(struct mail_storage *storage, const char *name)
@@ -95,12 +104,14 @@
 
 static void lazy_expunge_mail_expunge(struct mail *_mail)
 {
+	struct lazy_expunge_mail_user *luser =
+		LAZY_EXPUNGE_USER_CONTEXT(_mail->box->storage->ns->user);
 	struct lazy_expunge_transaction *lt =
 		LAZY_EXPUNGE_CONTEXT(_mail->transaction);
 	struct mail_storage *deststorage;
 
 	if (lt->expunge_box == NULL) {
-		deststorage = lazy_namespaces[LAZY_NAMESPACE_EXPUNGE]->storage;
+		deststorage = luser->lazy_ns[LAZY_NAMESPACE_EXPUNGE]->storage;
 		lt->expunge_box = mailbox_open_or_create(deststorage,
 							 _mail->box->name);
 		if (lt->expunge_box == NULL) {
@@ -414,6 +425,8 @@
 static int
 lazy_expunge_mailbox_list_delete(struct mailbox_list *list, const char *name)
 {
+	struct lazy_expunge_mail_user *luser =
+		LAZY_EXPUNGE_USER_CONTEXT(list->ns->user);
 	struct lazy_expunge_mailbox_list *llist =
 		LAZY_EXPUNGE_LIST_CONTEXT(list);
 	struct lazy_expunge_mail_storage *lstorage;
@@ -455,7 +468,7 @@
 	destname = t_strconcat(name, "-", timestamp, NULL);
 
 	/* first move the actual mailbox */
-	dest_list = lazy_namespaces[LAZY_NAMESPACE_DELETE]->storage->list;
+	dest_list = luser->lazy_ns[LAZY_NAMESPACE_DELETE]->storage->list;
 	if ((ret = mailbox_move(list, name, dest_list, &destname)) < 0)
 		return -1;
 	if (ret == 0) {
@@ -465,9 +478,9 @@
 	}
 
 	/* next move the expunged messages mailbox, if it exists */
-	list = lazy_namespaces[LAZY_NAMESPACE_EXPUNGE]->storage->list;
+	list = luser->lazy_ns[LAZY_NAMESPACE_EXPUNGE]->storage->list;
 	dest_list =
-		lazy_namespaces[LAZY_NAMESPACE_DELETE_EXPUNGE]->storage->list;
+		luser->lazy_ns[LAZY_NAMESPACE_DELETE_EXPUNGE]->storage->list;
 	(void)mailbox_move(list, name, dest_list, &destname);
 	return 0;
 }
@@ -526,13 +539,12 @@
 static void
 lazy_expunge_hook_mail_namespaces_created(struct mail_namespace *namespaces)
 {
+	struct lazy_expunge_mail_user *luser =
+		LAZY_EXPUNGE_USER_CONTEXT(namespaces->user);
 	struct lazy_expunge_mail_storage *lstorage;
 	const char *const *p;
 	int i;
 
-	if (lazy_expunge_next_hook_mail_namespaces_created != NULL)
-		lazy_expunge_next_hook_mail_namespaces_created(namespaces);
-
 	p = t_strsplit_spaces(getenv("LAZY_EXPUNGE"), " ");
 	for (i = 0; i < LAZY_NAMESPACE_COUNT; i++, p++) {
 		const char *name = *p;
@@ -540,20 +552,36 @@
 		if (name == NULL)
 			i_fatal("lazy_expunge: Missing namespace #%d", i + 1);
 
-		lazy_namespaces[i] =
+		luser->lazy_ns[i] =
 			mail_namespace_find_prefix(namespaces, name);
-		if (lazy_namespaces[i] == NULL)
+		if (luser->lazy_ns[i] == NULL)
 			i_fatal("lazy_expunge: Unknown namespace: '%s'", name);
-		if (strcmp(lazy_namespaces[i]->storage->name, "maildir") != 0) {
+		if (strcmp(luser->lazy_ns[i]->storage->name, "maildir") != 0) {
 			i_fatal("lazy_expunge: Namespace must be in maildir "
 				"format: %s", name);
 		}
 
 		/* we don't want to override these namespaces' expunge/delete
 		   operations. */
-		lstorage = LAZY_EXPUNGE_CONTEXT(lazy_namespaces[i]->storage);
+		lstorage = LAZY_EXPUNGE_CONTEXT(luser->lazy_ns[i]->storage);
 		lstorage->internal_namespace = TRUE;
 	}
+
+	if (lazy_expunge_next_hook_mail_namespaces_created != NULL)
+		lazy_expunge_next_hook_mail_namespaces_created(namespaces);
+}
+
+static void lazy_expunge_mail_user_created(struct mail_user *user)
+{
+	struct lazy_expunge_mail_user *luser;
+
+	luser = p_new(user->pool, struct lazy_expunge_mail_user, 1);
+	luser->module_ctx.super = user->v;
+
+	MODULE_CONTEXT_SET(user, lazy_expunge_mail_user_module, luser);
+
+	if (lazy_expunge_next_hook_mail_user_created != NULL)
+		lazy_expunge_next_hook_mail_user_created(user);
 }
 
 void lazy_expunge_plugin_init(void)
@@ -571,6 +599,9 @@
 
 	lazy_expunge_next_hook_mailbox_list_created = hook_mailbox_list_created;
 	hook_mailbox_list_created = lazy_expunge_mailbox_list_created;
+
+	lazy_expunge_next_hook_mail_user_created = hook_mail_user_created;
+	hook_mail_user_created = lazy_expunge_mail_user_created;
 }
 
 void lazy_expunge_plugin_deinit(void)
@@ -582,4 +613,5 @@
 		lazy_expunge_hook_mail_namespaces_created;
 	hook_mail_storage_created = lazy_expunge_next_hook_mail_storage_created;
 	hook_mailbox_list_created = lazy_expunge_next_hook_mailbox_list_created;
+	hook_mail_user_created = lazy_expunge_next_hook_mail_user_created;
 }
--- a/src/plugins/quota/quota-count.c	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/plugins/quota/quota-count.c	Tue Aug 12 12:28:42 2008 -0400
@@ -19,7 +19,7 @@
 	uoff_t size;
 	int ret = 0;
 
-	rule = quota_root_rule_find(root, name);
+	rule = quota_root_rule_find(root->set, name);
 	if (rule != NULL && rule->ignore) {
 		/* mailbox not included in quota */
 		return 0;
--- a/src/plugins/quota/quota-dict.c	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/plugins/quota/quota-dict.c	Tue Aug 12 12:28:42 2008 -0400
@@ -3,6 +3,7 @@
 #include "lib.h"
 #include "str.h"
 #include "dict.h"
+#include "mail-user.h"
 #include "quota-private.h"
 
 #include <stdlib.h>
@@ -48,9 +49,9 @@
 	}
 
 	if (*username == '\0')
-		username = getenv("USER");
+		username = _root->quota->user->username;
 
-	if (_root->quota->debug) {
+	if (_root->quota->set->debug) {
 		i_info("dict quota: user=%s, uri=%s, enforcing=%d",
 		       username, args, _root->no_enforcing);
 	}
@@ -104,8 +105,8 @@
 }
 
 static int
-dict_quota_get_resource(struct quota_root *_root, const char *name,
-			uint64_t *value_r)
+dict_quota_get_resource(struct quota_root *_root,
+			const char *name, uint64_t *value_r)
 {
 	struct dict_quota_root *root = (struct dict_quota_root *)_root;
 	bool want_bytes;
--- a/src/plugins/quota/quota-maildir.c	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/plugins/quota/quota-maildir.c	Tue Aug 12 12:28:42 2008 -0400
@@ -149,7 +149,7 @@
 			if (ctx->info == NULL)
 				return NULL;
 
-			rule = quota_root_rule_find(&ctx->root->root,
+			rule = quota_root_rule_find(ctx->root->root.set,
 						    ctx->info->name);
 			if (rule != NULL && rule->ignore) {
 				/* mailbox not included in quota */
@@ -217,7 +217,7 @@
 
 static int maildirsize_write(struct maildir_quota_root *root, const char *path)
 {
-	const struct quota_rule *rule = &root->root.default_rule;
+	const struct quota_rule *rule = &root->root.set->default_rule;
 	struct mail_storage *const *storages;
 	unsigned int i, count;
 	struct dotlock *dotlock;
@@ -319,7 +319,7 @@
 
 static void maildirsize_rebuild_later(struct maildir_quota_root *root)
 {
-	if (!root->root.force_default_rule) {
+	if (!root->root.set->force_default_rule) {
 		/* FIXME: can't unlink(), because the limits would be lost. */
 		return;
 	}
@@ -410,7 +410,7 @@
 static int maildirsize_parse(struct maildir_quota_root *root,
 			     int fd, const char *const *lines)
 {
-	struct quota_rule *rule = &root->root.default_rule;
+	struct quota_rule *rule = &root->root.set->default_rule;
 	uint64_t message_bytes_limit, message_count_limit;
 	long long bytes_diff, total_bytes;
 	int count_diff, total_count;
@@ -432,7 +432,7 @@
 	if (rule->bytes_limit == (int64_t)message_bytes_limit &&
 	    rule->count_limit == (int64_t)message_count_limit) {
 		/* limits haven't changed */
-	} else if (root->root.force_default_rule) {
+	} else if (root->root.set->force_default_rule) {
 		/* we know the limits and they've changed.
 		   the file must be rewritten. */
 		return 0;
@@ -440,7 +440,7 @@
 		/* we're using limits from the file. */
 		rule->bytes_limit = message_bytes_limit;
 		rule->count_limit = message_count_limit;
-		quota_root_recalculate_relative_rules(&root->root);
+		quota_root_recalculate_relative_rules(root->root.set);
 	}
 
 	if (*lines == NULL) {
@@ -603,8 +603,8 @@
 		ret = maildirsize_read(root);
 	} T_END;
 	if (ret == 0) {
-		if (root->root.default_rule.bytes_limit == 0 &&
-		    root->root.default_rule.count_limit == 0) {
+		if (root->root.set->default_rule.bytes_limit == 0 &&
+		    root->root.set->default_rule.count_limit == 0) {
 			/* no quota */
 			return 0;
 		}
@@ -661,7 +661,7 @@
 }
 
 static bool
-maildir_quota_parse_rule(struct quota_root *root ATTR_UNUSED,
+maildir_quota_parse_rule(struct quota_root_settings *root_set ATTR_UNUSED,
 			 struct quota_rule *rule,
 			 const char *str, const char **error_r)
 {
--- a/src/plugins/quota/quota-plugin.c	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/plugins/quota/quota-plugin.c	Tue Aug 12 12:28:42 2008 -0400
@@ -11,14 +11,15 @@
 /* defined by imap, pop3, lda */
 extern void (*hook_mail_storage_created)(struct mail_storage *storage);
 
+void (*quota_next_hook_mail_user_created)(struct mail_user *user);
 void (*quota_next_hook_mail_storage_created)(struct mail_storage *storage);
 void (*quota_next_hook_mailbox_list_created)(struct mailbox_list *list);
 
 const char *quota_plugin_version = PACKAGE_VERSION;
-struct quota *quota_set;
+struct quota_settings *quota_set;
 
 static void quota_root_add_rules(const char *root_name, 
-				 struct quota_root *root)
+				 struct quota_root_settings *root_set)
 {
 	const char *rule_name, *rule, *error;
 	unsigned int i;
@@ -30,7 +31,7 @@
 		if (rule == NULL)
 			break;
 
-		if (quota_root_add_rule(root, rule, &error) < 0) {
+		if (quota_root_add_rule(root_set, rule, &error) < 0) {
 			i_fatal("Quota root %s: Invalid rule %s: %s",
 				root_name, rule, error);
 		}
@@ -39,7 +40,7 @@
 }
 
 static void quota_root_add_warning_rules(const char *root_name,
-					 struct quota_root *root)
+					 struct quota_root_settings *root_set)
 {
 	const char *rule_name, *rule, *error;
 	unsigned int i;
@@ -51,7 +52,7 @@
 		if (rule == NULL)
 			break;
 
-		if (quota_root_add_warning_rule(root, rule, &error) < 0) {
+		if (quota_root_add_warning_rule(root_set, rule, &error) < 0) {
 			i_fatal("Quota root %s: Invalid warning rule: %s",
 				root_name, rule);
 		}
@@ -61,7 +62,7 @@
 
 void quota_plugin_init(void)
 {
-	struct quota_root *root;
+	struct quota_root_settings *root_set;
 	unsigned int i;
 	const char *env;
 
@@ -69,13 +70,13 @@
 	if (env == NULL)
 		return;
 
-	quota_set = quota_init();
+	quota_set = quota_settings_init();
 
-	root = quota_root_init(quota_set, env);
-	if (root == NULL)
+	root_set = quota_root_settings_init(quota_set, env);
+	if (root_set == NULL)
 		i_fatal("Couldn't create quota root: %s", env);
-	quota_root_add_rules("QUOTA", root);
-	quota_root_add_warning_rules("QUOTA", root);
+	quota_root_add_rules("QUOTA", root_set);
+	quota_root_add_warning_rules("QUOTA", root_set);
 
 	for (i = 2;; i++) {
 		const char *root_name;
@@ -86,13 +87,16 @@
 		if (env == NULL)
 			break;
 
-		root = quota_root_init(quota_set, env);
-		if (root == NULL)
+		root_set = quota_root_settings_init(quota_set, env);
+		if (root_set == NULL)
 			i_fatal("Couldn't create quota root: %s", env);
-		quota_root_add_rules(root_name, root);
-		quota_root_add_warning_rules(root_name, root);
+		quota_root_add_rules(root_name, root_set);
+		quota_root_add_warning_rules(root_name, root_set);
 	}
 
+	quota_next_hook_mail_user_created = hook_mail_user_created;
+	hook_mail_user_created = quota_mail_user_created;
+
 	quota_next_hook_mail_storage_created = hook_mail_storage_created;
 	hook_mail_storage_created = quota_mail_storage_created;
 
@@ -103,10 +107,11 @@
 void quota_plugin_deinit(void)
 {
 	if (quota_set != NULL) {
+		hook_mail_user_created = quota_next_hook_mail_user_created;
 		hook_mail_storage_created =
 			quota_next_hook_mail_storage_created;
 		hook_mailbox_list_created =
 			quota_next_hook_mailbox_list_created;
-		quota_deinit(&quota_set);
+		quota_settings_deinit(&quota_set);
 	}
 }
--- a/src/plugins/quota/quota-plugin.h	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/plugins/quota/quota-plugin.h	Tue Aug 12 12:28:42 2008 -0400
@@ -3,14 +3,14 @@
 
 struct mail_storage;
 
+extern void (*quota_next_hook_mail_user_created)(struct mail_user *user);
 extern void (*quota_next_hook_mail_storage_created)
 	(struct mail_storage *storage);
 extern void (*quota_next_hook_mailbox_list_created)(struct mailbox_list *list);
 
-/* "quota" symbol already exists in OSX, so we'll use this slightly uglier
-   name. */
-extern struct quota *quota_set;
+extern struct quota_settings *quota_set;
 
+void quota_mail_user_created(struct mail_user *user);
 void quota_mail_storage_created(struct mail_storage *storage);
 void quota_mailbox_list_created(struct mailbox_list *list);
 
--- a/src/plugins/quota/quota-private.h	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/plugins/quota/quota-private.h	Tue Aug 12 12:28:42 2008 -0400
@@ -9,9 +9,17 @@
 extern unsigned int quota_module_id;
 
 struct quota {
+	struct mail_user *user;
+	struct quota_settings *set;
+
 	ARRAY_DEFINE(roots, struct quota_root *);
 	ARRAY_DEFINE(storages, struct mail_storage *);
+};
 
+struct quota_settings {
+	pool_t pool;
+
+	ARRAY_DEFINE(root_sets, struct quota_root_settings *);
 	int (*test_alloc)(struct quota_transaction_context *ctx,
 			  uoff_t size, bool *too_large_r);
 
@@ -20,7 +28,7 @@
 };
 
 struct quota_rule {
-	char *mailbox_name;
+	const char *mailbox_name;
 
 	int64_t bytes_limit, count_limit;
 	/* relative to default_rule */
@@ -33,7 +41,7 @@
 struct quota_warning_rule {
 	struct quota_rule rule;
 
-	char *command;
+	const char *command;
 };
 
 struct quota_backend_vfuncs {
@@ -41,7 +49,8 @@
 	int (*init)(struct quota_root *root, const char *args);
 	void (*deinit)(struct quota_root *root);
 
-	bool (*parse_rule)(struct quota_root *root, struct quota_rule *rule,
+	bool (*parse_rule)(struct quota_root_settings *root_set,
+			   struct quota_rule *rule,
 			   const char *str, const char **error_r);
 
 	/* called once for each backend */
@@ -49,8 +58,8 @@
 			      struct mail_storage *storage);
 
 	const char *const *(*get_resources)(struct quota_root *root);
-	int (*get_resource)(struct quota_root *root, const char *name,
-			    uint64_t *value_r);
+	int (*get_resource)(struct quota_root *root,
+			    const char *name, uint64_t *value_r);
 
 	int (*update)(struct quota_root *root, 
 		      struct quota_transaction_context *ctx);
@@ -64,27 +73,34 @@
 	struct quota_backend_vfuncs v;
 };
 
-struct quota_root {
-	pool_t pool;
-
+struct quota_root_settings {
 	/* Unique quota root name. */
 	const char *name;
 
-	/* pointer to the quota that owns this root */
-	struct quota *quota;
+	struct quota_settings *set;
+	const char *args;
 
-	struct quota_backend backend;
+	const struct quota_backend *backend;
 	struct quota_rule default_rule;
 	ARRAY_DEFINE(rules, struct quota_rule);
 	ARRAY_DEFINE(warning_rules, struct quota_warning_rule);
 
+	/* Limits in default_rule override backend's quota limits */
+	unsigned int force_default_rule:1;
+};
+
+struct quota_root {
+	pool_t pool;
+
+	struct quota_root_settings *set;
+	struct quota *quota;
+	struct quota_backend backend;
+
 	/* Module-specific contexts. See quota_module_id. */
 	ARRAY_DEFINE(quota_module_contexts, void);
 
 	/* don't enforce quota when saving */
 	unsigned int no_enforcing:1;
-	/* Limits in default_rule override backend's quota limits */
-	unsigned int force_default_rule:1;
 };
 
 struct quota_transaction_context {
@@ -105,13 +121,14 @@
 
 /* Register storage to all user's quota roots. */
 void quota_add_user_storage(struct quota *quota, struct mail_storage *storage);
-void quota_remove_user_storage(struct quota *quota, 
-			       struct mail_storage *storage);
+void quota_remove_user_storage(struct mail_storage *storage);
+
+struct quota *quota_get_mail_user_quota(struct mail_user *user);
 
 struct quota_rule *
-quota_root_rule_find(struct quota_root *root, const char *name);
+quota_root_rule_find(struct quota_root_settings *root_set, const char *name);
 
-void quota_root_recalculate_relative_rules(struct quota_root *root);
+void quota_root_recalculate_relative_rules(struct quota_root_settings *root_set);
 int quota_count(struct quota_root *root, uint64_t *bytes_r, uint64_t *count_r);
 
 #endif
--- a/src/plugins/quota/quota-storage.c	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/plugins/quota/quota-storage.c	Tue Aug 12 12:28:42 2008 -0400
@@ -17,6 +17,14 @@
 	MODULE_CONTEXT(obj, quota_mail_module)
 #define QUOTA_LIST_CONTEXT(obj) \
 	MODULE_CONTEXT(obj, quota_mailbox_list_module)
+#define QUOTA_USER_CONTEXT(obj) \
+	MODULE_CONTEXT(obj, quota_user_module)
+
+struct quota_user {
+	union mail_user_module_context module_ctx;
+
+	struct quota *quota;
+};
 
 struct quota_mailbox_list {
 	union mailbox_list_module_context module_ctx;
@@ -41,6 +49,8 @@
 static MODULE_CONTEXT_DEFINE_INIT(quota_mail_module, &mail_module_register);
 static MODULE_CONTEXT_DEFINE_INIT(quota_mailbox_list_module,
 				  &mailbox_list_module_register);
+static MODULE_CONTEXT_DEFINE_INIT(quota_user_module,
+				  &mail_user_module_register);
 
 static void quota_mail_expunge(struct mail *_mail)
 {
@@ -74,7 +84,7 @@
 	struct quota_transaction_context *qt;
 
 	t = qbox->module_ctx.super.transaction_begin(box, flags);
-	qt = quota_transaction_begin(quota_set, box);
+	qt = quota_transaction_begin(box);
 
 	MODULE_CONTEXT_SET(t, quota_storage_module, qt);
 	return t;
@@ -150,7 +160,7 @@
 		return 0;
 	else if (ret == 0) {
 		mail_storage_set_error(t->box->storage, MAIL_ERROR_NOSPACE,
-				       qt->quota->quota_exceeded_msg);
+				       qt->quota->set->quota_exceeded_msg);
 		return -1;
 	} else {
 		mail_storage_set_critical(t->box->storage,
@@ -212,7 +222,7 @@
 		if (ret == 0) {
 			mail_storage_set_error(t->box->storage,
 				MAIL_ERROR_NOSPACE,
-				qt->quota->quota_exceeded_msg);
+				qt->quota->set->quota_exceeded_msg);
 			return -1;
 		} else if (ret < 0) {
 			mail_storage_set_critical(t->box->storage,
@@ -294,7 +304,7 @@
 	}
 
 	if (qbox->expunge_qt == NULL)
-		qbox->expunge_qt = quota_transaction_begin(quota_set, box);
+		qbox->expunge_qt = quota_transaction_begin(box);
 
 	if (i != count) {
 		/* we already know the size */
@@ -436,16 +446,47 @@
 {
 	union mail_storage_module_context *qstorage = QUOTA_CONTEXT(storage);
 
-	quota_remove_user_storage(quota_set, storage);
+	quota_remove_user_storage(storage);
 
 	if (qstorage->super.destroy != NULL)
 		qstorage->super.destroy(storage);
 }
 
+struct quota *quota_get_mail_user_quota(struct mail_user *user)
+{
+	struct quota_user *quser = QUOTA_USER_CONTEXT(user);
+
+	return quser->quota;
+}
+
+static void quota_user_deinit(struct mail_user *user)
+{
+	struct quota_user *quser = QUOTA_USER_CONTEXT(user);
+
+	quota_deinit(&quser->quota);
+	quser->module_ctx.super.deinit(user);
+}
+
+void quota_mail_user_created(struct mail_user *user)
+{
+	struct quota_user *quser;
+
+	quser = p_new(user->pool, struct quota_user, 1);
+	quser->module_ctx.super = user->v;
+	user->v.deinit = quota_user_deinit;
+	quser->quota = quota_init(quota_set, user);
+
+	MODULE_CONTEXT_SET(user, quota_user_module, quser);
+
+	if (quota_next_hook_mail_user_created != NULL)
+		quota_next_hook_mail_user_created(user);
+}
+
 void quota_mail_storage_created(struct mail_storage *storage)
 {
 	struct quota_mailbox_list *qlist = QUOTA_LIST_CONTEXT(storage->list);
 	union mail_storage_module_context *qstorage;
+	struct quota *quota;
 
 	qlist->storage = storage;
 
@@ -459,7 +500,8 @@
 	if (storage->ns->type == NAMESPACE_PRIVATE &&
 	    (storage->ns->flags & NAMESPACE_FLAG_INTERNAL) == 0) {
 		/* register to user's quota roots */
-		quota_add_user_storage(quota_set, storage);
+		quota = quota_get_mail_user_quota(storage->ns->user);
+		quota_add_user_storage(quota, storage);
 	}
 
 	if (quota_next_hook_mail_storage_created != NULL)
--- a/src/plugins/quota/quota.c	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/plugins/quota/quota.c	Tue Aug 12 12:28:42 2008 -0400
@@ -42,37 +42,30 @@
 static int quota_default_test_alloc(struct quota_transaction_context *ctx,
 				    uoff_t size, bool *too_large_r);
 
-struct quota *quota_init(void)
+struct quota_settings *quota_settings_init(void)
 {
-	struct quota *quota;
+	struct quota_settings *quota_set;
+	pool_t pool;
 
-	quota = i_new(struct quota, 1);
-	quota->test_alloc = quota_default_test_alloc;
-	quota->debug = getenv("DEBUG") != NULL;
-	quota->quota_exceeded_msg = getenv("QUOTA_EXCEEDED_MESSAGE");
-	if (quota->quota_exceeded_msg == NULL)
-		quota->quota_exceeded_msg = DEFAULT_QUOTA_EXCEEDED_MSG;
-	i_array_init(&quota->roots, 4);
-	i_array_init(&quota->storages, 8);
-
-	return quota;
+	pool = pool_alloconly_create("quota settings", 256);
+	quota_set = p_new(pool, struct quota_settings, 1);
+	quota_set->pool = pool;
+	quota_set->test_alloc = quota_default_test_alloc;
+	quota_set->debug = getenv("DEBUG") != NULL;
+	quota_set->quota_exceeded_msg = getenv("QUOTA_EXCEEDED_MESSAGE");
+	if (quota_set->quota_exceeded_msg == NULL)
+		quota_set->quota_exceeded_msg = DEFAULT_QUOTA_EXCEEDED_MSG;
+	p_array_init(&quota_set->root_sets, pool, 4);
+	return quota_set;
 }
 
-void quota_deinit(struct quota **_quota)
+void quota_settings_deinit(struct quota_settings **_quota_set)
 {
-	struct quota *quota = *_quota;
-	struct quota_root **root_p, *root;
+	struct quota_settings *quota_set = *_quota_set;
 
-	*_quota = NULL;
-	while (array_count(&quota->roots) > 0) {
-		root_p = array_idx_modifiable(&quota->roots, 0);
-		root = *root_p;
-		quota_root_deinit(&root);
-	}
+	*_quota_set = NULL;
 
-	array_free(&quota->roots);
-	array_free(&quota->storages);
-	i_free(quota);
+	pool_unref(&quota_set->pool);
 }
 
 static const struct quota_backend *quota_backend_find(const char *name)
@@ -87,11 +80,12 @@
 	return NULL;
 }
 
-struct quota_root *quota_root_init(struct quota *quota, const char *root_def)
+struct quota_root_settings *
+quota_root_settings_init(struct quota_settings *quota_set, const char *root_def)
 {
-	struct quota_root *root;
+	struct quota_root_settings *root_set;
 	const struct quota_backend *backend;
-	const char *p, *args, *backend_name, *const *tmp;
+	const char *p, *args, *backend_name;
 
 	/* <backend>[:<quota root name>[:<backend args>]] */
 	p = strchr(root_def, ':');
@@ -107,44 +101,57 @@
 	if (backend == NULL)
 		i_fatal("Unknown quota backend: %s", backend_name);
 	
-	root = backend->v.alloc();
-	root->quota = quota;
-	root->backend = *backend;
-	root->pool = pool_alloconly_create("quota root", 512);
+	root_set = p_new(quota_set->pool, struct quota_root_settings, 1);
+	root_set->set = quota_set;
+	root_set->backend = backend;
 
 	if (args != NULL) {
 		/* save root's name */
 		p = strchr(args, ':');
 		if (p == NULL) {
-			root->name = p_strdup(root->pool, args);
+			root_set->name = p_strdup(quota_set->pool, args);
 			args = NULL;
 		} else {
-			root->name = p_strdup_until(root->pool, args, p);
+			root_set->name =
+				p_strdup_until(quota_set->pool, args, p);
 			args = p + 1;
 		}
 	} else {
-		root->name = "";
+		root_set->name = "";
 	}
+	root_set->args = p_strdup(quota_set->pool, args);
 
-	if (quota->debug) {
+	if (quota_set->debug) {
 		i_info("Quota root: name=%s backend=%s args=%s",
-		       root->name, backend_name, args == NULL ? "" : args);
+		       root_set->name, backend_name, args == NULL ? "" : args);
 	}
 
-	i_array_init(&root->rules, 4);
-	i_array_init(&root->warning_rules, 4);
-	array_create(&root->quota_module_contexts, default_pool,
-		     sizeof(void *), 5);
+	p_array_init(&root_set->rules, quota_set->pool, 4);
+	p_array_init(&root_set->warning_rules, quota_set->pool, 4);
+	array_append(&quota_set->root_sets, &root_set, 1);
+	return root_set;
+}
 
-	array_append(&quota->roots, &root, 1);
+static struct quota_root *
+quota_root_init(struct quota_root_settings *root_set, struct quota *quota)
+{
+	struct quota_root *root;
+	const char *const *tmp;
 
-	if (backend->v.init != NULL) {
-		if (backend->v.init(root, args) < 0) {
-			quota_root_deinit(&root);
+	root = root_set->backend->v.alloc();
+	root->pool = pool_alloconly_create("quota root", 512);
+	root->set = root_set;
+	root->quota = quota;
+	root->backend = *root_set->backend;
+
+	array_create(&root->quota_module_contexts, root->pool,
+		     sizeof(void *), 10);
+
+	if (root->backend.v.init != NULL) {
+		if (root->backend.v.init(root, root_set->args) < 0)
 			return NULL;
-		}
-	} else if (args != NULL) {
-		tmp = t_strsplit_spaces(args, " ");
+	} else if (root_set->args != NULL) {
+		tmp = t_strsplit_spaces(root_set->args, " ");
 		for (; *tmp != NULL; tmp++) {
 			if (strcmp(*tmp, "noenforcing") == 0)
 				root->no_enforcing = TRUE;
@@ -154,49 +161,65 @@
 		if (*tmp != NULL) {
 			i_fatal("Quota root %s backend %s: "
 				"Unknown parameter: %s",
-				root->name, backend_name, *tmp);
+				root_set->name, root->backend.name, *tmp);
 		}
 	}
 	return root;
 }
 
-void quota_root_deinit(struct quota_root **_root)
+static void quota_root_deinit(struct quota_root *root)
 {
-	struct quota_root *root = *_root;
 	pool_t pool = root->pool;
-	struct quota_root *const *roots;
-	struct quota_warning_rule *warnings;
-	unsigned int i, count;
-
-	*_root = NULL;
-
-	roots = array_get(&root->quota->roots, &count);
-	for (i = 0; i < count; i++) {
-		if (roots[i] == root) {
-			array_delete(&root->quota->roots, i, 1);
-			break;
-		}
-	}
-
-	warnings = array_get_modifiable(&root->warning_rules, &count);
-	for (i = 0; i < count; i++)
-		i_free(warnings[i].command);
-	array_free(&root->warning_rules);
-
-	array_free(&root->rules);
-	array_free(&root->quota_module_contexts);
 
 	root->backend.v.deinit(root);
 	pool_unref(&pool);
 }
 
+struct quota *quota_init(struct quota_settings *quota_set,
+			 struct mail_user *user)
+{
+	struct quota *quota;
+	struct quota_root *root;
+	struct quota_root_settings *const *root_sets;
+	unsigned int i, count;
+
+	quota = i_new(struct quota, 1);
+	quota->user = user;
+	quota->set = quota_set;
+	i_array_init(&quota->roots, 8);
+
+	root_sets = array_get(&quota_set->root_sets, &count);
+	i_array_init(&quota->storages, count);
+	for (i = 0; i < count; i++) {
+		root = quota_root_init(root_sets[i], quota);
+		array_append(&quota->roots, &root, 1);
+	}
+	return quota;
+}
+
+void quota_deinit(struct quota **_quota)
+{
+	struct quota *quota = *_quota;
+	struct quota_root *const *roots;
+	unsigned int i, count;
+
+	*_quota = NULL;
+
+	roots = array_get(&quota->roots, &count);
+	for (i = 0; i < count; i++)
+		quota_root_deinit(roots[i]);
+	array_free(&quota->roots);
+	array_free(&quota->storages);
+	i_free(quota);
+}
+
 struct quota_rule *
-quota_root_rule_find(struct quota_root *root, const char *name)
+quota_root_rule_find(struct quota_root_settings *root_set, const char *name)
 {
 	struct quota_rule *rules;
 	unsigned int i, count;
 
-	rules = array_get_modifiable(&root->rules, &count);
+	rules = array_get_modifiable(&root_set->rules, &count);
 	for (i = 0; i < count; i++) {
 		if (strcmp(rules[i].mailbox_name, name) == 0)
 			return &rules[i];
@@ -205,18 +228,19 @@
 }
 
 static int
-quota_rule_parse_percentage(struct quota_root *root, struct quota_rule *rule,
+quota_rule_parse_percentage(struct quota_root_settings *root_set,
+			    struct quota_rule *rule,
 			    int64_t *limit, const char **error_r)
 {
 	int64_t percentage = *limit;
 
 	if (percentage <= 0 || percentage >= -1U) {
-		*error_r = p_strdup_printf(root->pool,
+		*error_r = p_strdup_printf(root_set->set->pool,
 			"Invalid rule percentage: %lld", (long long)percentage);
 		return -1;
 	}
 
-	if (rule == &root->default_rule) {
+	if (rule == &root_set->default_rule) {
 		*error_r = "Default rule can't be a percentage";
 		return -1;
 	}
@@ -244,29 +268,29 @@
 	}
 }
 
-void quota_root_recalculate_relative_rules(struct quota_root *root)
+void quota_root_recalculate_relative_rules(struct quota_root_settings *root_set)
 {
 	struct quota_rule *rules;
 	struct quota_warning_rule *warning_rules;
 	unsigned int i, count;
 
-	rules = array_get_modifiable(&root->rules, &count);
+	rules = array_get_modifiable(&root_set->rules, &count);
 	for (i = 0; i < count; i++) {
 		quota_rule_recalculate_relative_rules(&rules[i],
-						      &root->default_rule);
+						      &root_set->default_rule);
 	}
 
-	warning_rules = array_get_modifiable(&root->warning_rules, &count);
+	warning_rules = array_get_modifiable(&root_set->warning_rules, &count);
 	for (i = 0; i < count; i++) {
 		quota_rule_recalculate_relative_rules(&warning_rules[i].rule,
-						      &root->default_rule);
+						      &root_set->default_rule);
 	}
 }
 
 static int
-quota_rule_parse_limits(struct quota_root *root, struct quota_rule *rule,
-			const char *limits, bool allow_negative,
-			const char **error_r)
+quota_rule_parse_limits(struct quota_root_settings *root_set,
+			struct quota_rule *rule, const char *limits,
+			bool allow_negative, const char **error_r)
 {
 	const char **args;
 	char *p;
@@ -288,7 +312,7 @@
 			limit = &rule->count_limit;
 			*limit = strtoll(*args + 9, &p, 10);
 		} else {
-			*error_r = p_strdup_printf(root->pool,
+			*error_r = p_strdup_printf(root_set->set->pool,
 					"Unknown rule limit name: %s", *args);
 			return -1;
 		}
@@ -314,12 +338,12 @@
 			break;
 		case '%':
 			multiply = 0;
-			if (quota_rule_parse_percentage(root, rule, limit,
+			if (quota_rule_parse_percentage(root_set, rule, limit,
 							error_r) < 0)
 				return -1;
 			break;
 		default:
-			*error_r = p_strdup_printf(root->pool,
+			*error_r = p_strdup_printf(root_set->set->pool,
 					"Invalid rule limit value: %s", *args);
 			return -1;
 		}
@@ -338,8 +362,8 @@
 	return 0;
 }
 
-int quota_root_add_rule(struct quota_root *root, const char *rule_def,
-			const char **error_r)
+int quota_root_add_rule(struct quota_root_settings *root_set,
+			const char *rule_def, const char **error_r)
 {
 	struct quota_rule *rule;
 	const char *p, *mailbox_name;
@@ -354,43 +378,45 @@
 	/* <mailbox name>:<quota limits> */
 	mailbox_name = t_strdup_until(rule_def, p++);
 
-	rule = quota_root_rule_find(root, mailbox_name);
+	rule = quota_root_rule_find(root_set, mailbox_name);
 	if (rule == NULL) {
 		if (strcmp(mailbox_name, RULE_NAME_DEFAULT_NONFORCE) == 0)
-			rule = &root->default_rule;
+			rule = &root_set->default_rule;
 		else if (strcmp(mailbox_name, RULE_NAME_DEFAULT_FORCE) == 0) {
-			rule = &root->default_rule;
-			root->force_default_rule = TRUE;
+			rule = &root_set->default_rule;
+			root_set->force_default_rule = TRUE;
 		} else {
-			rule = array_append_space(&root->rules);
-			rule->mailbox_name = p_strdup(root->pool, mailbox_name);
+			rule = array_append_space(&root_set->rules);
+			rule->mailbox_name =
+				p_strdup(root_set->set->pool, mailbox_name);
 		}
 	}
 
 	if (strcmp(p, "ignore") == 0) {
 		rule->ignore = TRUE;
-		if (root->quota->debug) {
+		if (root_set->set->debug) {
 			i_info("Quota rule: root=%s mailbox=%s ignored",
-			       root->name, mailbox_name);
+			       root_set->name, mailbox_name);
 		}
 		return 0;
 	}
 
 	if (strncmp(p, "backend=", 8) == 0) {
-		if (!root->backend.v.parse_rule(root, rule, p + 8, error_r))
+		if (!root_set->backend->v.parse_rule(root_set, rule,
+						     p + 8, error_r))
 			ret = -1;
 	} else {
-		bool allow_negative = rule != &root->default_rule;
+		bool allow_negative = rule != &root_set->default_rule;
 
-		if (quota_rule_parse_limits(root, rule, p,
+		if (quota_rule_parse_limits(root_set, rule, p,
 					    allow_negative, error_r) < 0)
 			ret = -1;
 	}
 
-	quota_root_recalculate_relative_rules(root);
-	if (root->quota->debug) {
+	quota_root_recalculate_relative_rules(root_set);
+	if (root_set->set->debug) {
 		i_info("Quota rule: root=%s mailbox=%s "
-		       "bytes=%lld (%u%%) messages=%lld (%u%%)", root->name,
+		       "bytes=%lld (%u%%) messages=%lld (%u%%)", root_set->name,
 		       mailbox_name,
 		       (long long)rule->bytes_limit, rule->bytes_percent,
 		       (long long)rule->count_limit, rule->count_percent);
@@ -398,7 +424,7 @@
 	return ret;
 }
 
-static bool quota_root_get_rule_limits(struct quota_root *root,
+static bool quota_root_get_rule_limits(struct quota_root_settings *root_set,
 				       const char *mailbox_name,
 				       uint64_t *bytes_limit_r,
 				       uint64_t *count_limit_r)
@@ -407,14 +433,14 @@
 	int64_t bytes_limit, count_limit;
 	bool found;
 
-	bytes_limit = root->default_rule.bytes_limit;
-	count_limit = root->default_rule.count_limit;
+	bytes_limit = root_set->default_rule.bytes_limit;
+	count_limit = root_set->default_rule.count_limit;
 
 	/* if default rule limits are 0, this rule applies only to specific
 	   mailboxes */
 	found = bytes_limit != 0 || count_limit != 0;
 
-	rule = quota_root_rule_find(root, mailbox_name);
+	rule = quota_root_rule_find(root_set, mailbox_name);
 	if (rule != NULL) {
 		if (!rule->ignore) {
 			bytes_limit += rule->bytes_limit;
@@ -489,12 +515,18 @@
 	}
 }
 
-void quota_remove_user_storage(struct quota *quota,
-			       struct mail_storage *storage)
+void quota_remove_user_storage(struct mail_storage *storage)
 {
+	struct quota *quota;
 	struct mail_storage *const *storages;
 	unsigned int i, count;
-	
+
+	quota = quota_get_mail_user_quota(storage->ns->user);
+	if (quota == NULL) {
+		/* no quota for this storage */
+		return;
+	}
+
 	storages = array_get(&quota->storages, &count);
 	for (i = 0; i < count; i++) {
 		if (storages[i] == storage) {
@@ -504,8 +536,8 @@
 	}
 }
 
-int quota_root_add_warning_rule(struct quota_root *root, const char *rule_def,
-				const char **error_r)
+int quota_root_add_warning_rule(struct quota_root_settings *root_set,
+				const char *rule_def, const char **error_r)
 {
 	struct quota_warning_rule *warning;
 	struct quota_rule rule;
@@ -519,17 +551,18 @@
 	}
 
 	memset(&rule, 0, sizeof(rule));
-	ret = quota_rule_parse_limits(root, &rule, t_strdup_until(rule_def, p),
+	ret = quota_rule_parse_limits(root_set, &rule,
+				      t_strdup_until(rule_def, p),
 				      TRUE, error_r);
 	if (ret < 0)
 		return -1;
 
-	warning = array_append_space(&root->warning_rules);
+	warning = array_append_space(&root_set->warning_rules);
 	warning->command = i_strdup(p+1);
 	warning->rule = rule;
 
-	quota_root_recalculate_relative_rules(root);
-	if (root->quota->debug) {
+	quota_root_recalculate_relative_rules(root_set);
+	if (root_set->set->debug) {
 		i_info("Quota warning: bytes=%llu (%u%%) "
 		       "messages=%llu (%u%%) command=%s",
 		       (unsigned long long)warning->rule.bytes_limit,
@@ -541,12 +574,13 @@
 }
 
 struct quota_root_iter *
-quota_root_iter_init(struct quota *quota, struct mailbox *box)
+quota_root_iter_init(struct mailbox *box)
 {
+	struct mail_user *user = box->storage->ns->user;
 	struct quota_root_iter *iter;
 
 	iter = i_new(struct quota_root_iter, 1);
-	iter->quota = quota;
+	iter->quota = quota_get_mail_user_quota(user);
 	iter->box = box;
 	return iter;
 }
@@ -608,14 +642,16 @@
 	i_free(iter);
 }
 
-struct quota_root *quota_root_lookup(struct quota *quota, const char *name)
+struct quota_root *quota_root_lookup(struct mail_user *user, const char *name)
 {
+	struct quota *quota;
 	struct quota_root *const *roots;
 	unsigned int i, count;
 
+	quota = quota_get_mail_user_quota(user);
 	roots = array_get(&quota->roots, &count);
 	for (i = 0; i < count; i++) {
-		if (strcmp(roots[i]->name, name) == 0)
+		if (strcmp(roots[i]->set->name, name) == 0)
 			return roots[i];
 	}
 	return NULL;
@@ -623,7 +659,7 @@
 
 const char *quota_root_get_name(struct quota_root *root)
 {
-	return root->name;
+	return root->set->name;
 }
 
 const char *const *quota_root_get_resources(struct quota_root *root)
@@ -649,7 +685,7 @@
 	if (ret <= 0)
 		return ret;
 
-	(void)quota_root_get_rule_limits(root, mailbox_name,
+	(void)quota_root_get_rule_limits(root->set, mailbox_name,
 					 &bytes_limit, &count_limit);
 	if (strcmp(name, QUOTA_NAME_STORAGE_BYTES) == 0)
 		*limit_r = bytes_limit;
@@ -676,13 +712,13 @@
 	return -1;
 }
 
-struct quota_transaction_context *quota_transaction_begin(struct quota *quota,
-							  struct mailbox *box)
+struct quota_transaction_context *quota_transaction_begin(struct mailbox *box)
 {
+	struct mail_user *user = box->storage->ns->user;
 	struct quota_transaction_context *ctx;
 
 	ctx = i_new(struct quota_transaction_context, 1);
-	ctx->quota = quota;
+	ctx->quota = quota_get_mail_user_quota(user);
 	ctx->box = box;
 	ctx->bytes_left = (uint64_t)-1;
 	ctx->count_left = (uint64_t)-1;
@@ -756,7 +792,7 @@
 	uint64_t bytes_current, bytes_before, bytes_limit;
 	uint64_t count_current, count_before, count_limit;
 
-	warnings = array_get_modifiable(&root->warning_rules, &count);
+	warnings = array_get_modifiable(&root->set->warning_rules, &count);
 	if (count == 0)
 		return;
 
@@ -801,7 +837,8 @@
 			if (!quota_root_is_visible(roots[i], ctx->box, TRUE))
 				continue;
 
-			rule = quota_root_rule_find(roots[i], mailbox_name);
+			rule = quota_root_rule_find(roots[i]->set,
+						    mailbox_name);
 			if (rule != NULL && rule->ignore) {
 				/* mailbox not included in quota */
 				continue;
@@ -856,7 +893,7 @@
 		if (quota_transaction_set_limits(ctx) < 0)
 			return -1;
 	}
-	return ctx->quota->test_alloc(ctx, size, too_large_r);
+	return ctx->quota->set->test_alloc(ctx, size, too_large_r);
 }
 
 static int quota_default_test_alloc(struct quota_transaction_context *ctx,
@@ -877,7 +914,7 @@
 		if (!quota_root_is_visible(roots[i], ctx->box, TRUE))
 			continue;
 
-		if (!quota_root_get_rule_limits(roots[i],
+		if (!quota_root_get_rule_limits(roots[i]->set,
 						mailbox_get_name(ctx->box),
 						&bytes_limit, &count_limit))
 			continue;
--- a/src/plugins/quota/quota.h	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/plugins/quota/quota.h	Tue Aug 12 12:28:42 2008 -0400
@@ -3,6 +3,7 @@
 
 struct mail;
 struct mailbox;
+struct mail_user;
 
 /* Message storage size kilobytes. */
 #define QUOTA_NAME_STORAGE_KILOBYTES "STORAGE"
@@ -16,29 +17,35 @@
 struct quota_root_iter;
 struct quota_transaction_context;
 
-struct quota *quota_init(void);
-void quota_deinit(struct quota **quota);
+struct quota_settings *quota_settings_init(void);
+void quota_settings_deinit(struct quota_settings **quota_set);
 
-/* Create a new quota root. */
-struct quota_root *quota_root_init(struct quota *quota, const char *root_def);
-void quota_root_deinit(struct quota_root **root);
+/* Set up a new quota root. */
+struct quota_root_settings *
+quota_root_settings_init(struct quota_settings *quota_set,
+			 const char *root_def);
+void quota_root_settings_deinit(struct quota_root_settings **root_set);
 
 /* Add a new rule too the quota root. Returns 0 if ok, -1 if rule is invalid. */
-int quota_root_add_rule(struct quota_root *root, const char *rule_def,
-			const char **error_r);
+int quota_root_add_rule(struct quota_root_settings *root_set,
+			const char *rule_def, const char **error_r);
 /* Add a new warning rule for the quota root. Returns 0 if ok, -1 if rule is
    invalid. */
-int quota_root_add_warning_rule(struct quota_root *root, const char *rule_def,
-				const char **error_r);
+int quota_root_add_warning_rule(struct quota_root_settings *root_set,
+				const char *rule_def, const char **error_r);
+
+/* Initialize quota for the given user. */
+struct quota *quota_init(struct quota_settings *quota_set,
+			 struct mail_user *user);
+void quota_deinit(struct quota **quota);
 
 /* List all quota roots. Returned quota roots are freed by quota_deinit(). */
-struct quota_root_iter *
-quota_root_iter_init(struct quota *quota, struct mailbox *box);
+struct quota_root_iter *quota_root_iter_init(struct mailbox *box);
 struct quota_root *quota_root_iter_next(struct quota_root_iter *iter);
 void quota_root_iter_deinit(struct quota_root_iter **iter);
 
 /* Return quota root or NULL. */
-struct quota_root *quota_root_lookup(struct quota *quota, const char *name);
+struct quota_root *quota_root_lookup(struct mail_user *user, const char *name);
 
 /* Returns name of the quota root. */
 const char *quota_root_get_name(struct quota_root *root);
@@ -53,8 +60,7 @@
 		       uint64_t value, const char **error_r);
 
 /* Start a new quota transaction. */
-struct quota_transaction_context *quota_transaction_begin(struct quota *quota, 
-							  struct mailbox *box);
+struct quota_transaction_context *quota_transaction_begin(struct mailbox *box);
 /* Commit quota transaction. Returns 0 if ok, -1 if failed. */
 int quota_transaction_commit(struct quota_transaction_context **ctx);
 /* Rollback quota transaction changes. */
--- a/src/plugins/trash/trash-plugin.c	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/plugins/trash/trash-plugin.c	Tue Aug 12 12:28:42 2008 -0400
@@ -21,9 +21,9 @@
 	const char *name;
 	int priority; /* lower number = higher priority */
 
+	/* temporarily set while cleaning: */
+	const char *ns_name;
 	struct mail_storage *storage;
-
-	/* temporarily set while cleaning: */
 	struct mailbox *box;
 	struct mailbox_transaction_context *trans;
 	struct mail_search_context *search_ctx;
@@ -45,7 +45,7 @@
 {
 	struct mail_search_args *search_args;
 
-	trash->box = mailbox_open(trash->storage, trash->name, NULL,
+	trash->box = mailbox_open(trash->storage, trash->ns_name, NULL,
 				  MAILBOX_OPEN_KEEP_RECENT);
 	if (trash->box == NULL)
 		return 0;
@@ -89,14 +89,17 @@
 	return 1;
 }
 
-static void trash_find_storage(struct trash_mailbox *trash)
+static void trash_find_storage(struct quota *quota,
+			       struct trash_mailbox *trash)
 {
 	struct mail_storage *const *storages;
 	unsigned int i, count;
 
-	storages = array_get(&quota_set->storages, &count);
+	storages = array_get(&quota->storages, &count);
 	for (i = 0; i < count; i++) {
-		if (mail_namespace_update_name(storages[i]->ns, &trash->name)) {
+		trash->ns_name = trash->name;
+		if (mail_namespace_update_name(storages[i]->ns,
+					       &trash->ns_name)) {
 			trash->storage = storages[i];
 			return;
 		}
@@ -124,7 +127,7 @@
 				break;
 
 			if (trashes[j].storage == NULL)
-				trash_find_storage(&trashes[j]);
+				trash_find_storage(ctx->quota, &trashes[j]);
 
 			ret = trash_clean_mailbox_get_next(&trashes[j],
 							   &received);
@@ -177,6 +180,8 @@
 		}
 
 		mailbox_close(&trash->box);
+		trash->storage = NULL;
+		trash->ns_name = NULL;
 	}
 
 	if (size_expunged < size_needed) {
--- a/src/plugins/virtual/virtual-config.c	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/plugins/virtual/virtual-config.c	Tue Aug 12 12:28:42 2008 -0400
@@ -89,6 +89,7 @@
 virtual_config_parse_line(struct virtual_parse_context *ctx, const char *line,
 			  const char **error_r)
 {
+	struct mail_user *user = ctx->mbox->storage->storage.ns->user;
 	struct virtual_backend_box *bbox;
 
 	if (*line == ' ') {
@@ -110,7 +111,7 @@
 	    strchr(bbox->name, '%') != NULL) {
 		bbox->glob = imap_match_init(ctx->pool, bbox->name,
 					     TRUE, ctx->sep);
-		bbox->ns = mail_namespace_find(virtual_all_namespaces, &line);
+		bbox->ns = mail_namespace_find(user->namespaces, &line);
 		ctx->have_wildcards = TRUE;
 	}
 	array_append(&ctx->mbox->backend_boxes, &bbox, 1);
@@ -154,6 +155,7 @@
 
 static int virtual_config_expand_wildcards(struct virtual_parse_context *ctx)
 {
+	struct mail_user *user = ctx->mbox->storage->storage.ns->user;
 	ARRAY_TYPE(virtual_backend_box) wildcard_boxes;
 	struct mailbox_list_iterate_context *iter;
 	struct virtual_backend_box *const *wboxes;
@@ -170,8 +172,7 @@
 		patterns[i] = wboxes[i]->name;
 
 	/* match listed mailboxes to wildcards */
-	iter = mailbox_list_iter_init_namespaces(
-					virtual_all_namespaces, patterns,
+	iter = mailbox_list_iter_init_namespaces(user->namespaces, patterns,
 					MAILBOX_LIST_ITER_VIRTUAL_NAMES |
 					MAILBOX_LIST_ITER_RETURN_NO_FLAGS);
 	while ((info = mailbox_list_iter_next(iter)) != NULL) {
@@ -191,6 +192,7 @@
 
 int virtual_config_read(struct virtual_mailbox *mbox)
 {
+	struct mail_user *user = mbox->storage->storage.ns->user;
 	struct virtual_parse_context ctx;
 	const char *path, *line, *error;
 	unsigned int linenum = 0;
@@ -213,7 +215,7 @@
 	}
 
 	memset(&ctx, 0, sizeof(ctx));
-	ctx.sep = mail_namespace_get_root_sep(virtual_all_namespaces);
+	ctx.sep = mail_namespace_get_root_sep(user->namespaces);
 	ctx.mbox = mbox;
 	ctx.pool = mbox->ibox.box.pool;
 	ctx.rule = t_str_new(256);
--- a/src/plugins/virtual/virtual-plugin.c	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/plugins/virtual/virtual-plugin.c	Tue Aug 12 12:28:42 2008 -0400
@@ -5,36 +5,14 @@
 #include "virtual-storage.h"
 #include "virtual-plugin.h"
 
-static void (*virtual_next_hook_mail_namespaces_created)
-	(struct mail_namespace *namespaces);
-
 const char *virtual_plugin_version = PACKAGE_VERSION;
-struct mail_namespace *virtual_all_namespaces;
-
-static void
-virtual_hook_mail_namespaces_created(struct mail_namespace *namespaces)
-{
-	if (virtual_next_hook_mail_namespaces_created != NULL)
-		virtual_next_hook_mail_namespaces_created(namespaces);
-
-	/* FIXME: some day we should support multiple clients and this
-	   global namespaces list doesn't work */
-	virtual_all_namespaces = namespaces;
-}
 
 void virtual_plugin_init(void)
 {
 	mail_storage_class_register(&virtual_storage);
-
-	virtual_next_hook_mail_namespaces_created =
-		hook_mail_namespaces_created;
-	hook_mail_namespaces_created = virtual_hook_mail_namespaces_created;
 }
 
 void virtual_plugin_deinit(void)
 {
 	mail_storage_class_unregister(&virtual_storage);
-
-	hook_mail_namespaces_created =
-		virtual_next_hook_mail_namespaces_created;
 }
--- a/src/plugins/virtual/virtual-plugin.h	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/plugins/virtual/virtual-plugin.h	Tue Aug 12 12:28:42 2008 -0400
@@ -1,8 +1,6 @@
 #ifndef VIRTUAL_PLUGIN_H
 #define VIRTUAL_PLUGIN_H
 
-extern struct mail_namespace *virtual_all_namespaces;
-
 void virtual_plugin_init(void);
 void virtual_plugin_deinit(void);
 
--- a/src/plugins/virtual/virtual-storage.c	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/plugins/virtual/virtual-storage.c	Tue Aug 12 12:28:42 2008 -0400
@@ -169,6 +169,7 @@
 static int virtual_mailboxes_open(struct virtual_mailbox *mbox,
 				  enum mailbox_open_flags open_flags)
 {
+	struct mail_user *user = mbox->storage->storage.ns->user;
 	struct virtual_backend_box *const *bboxes;
 	struct mail_namespace *ns;
 	unsigned int i, count;
@@ -180,7 +181,7 @@
 	bboxes = array_get(&mbox->backend_boxes, &count);
 	for (i = 0; i < count; i++) {
 		mailbox = bboxes[i]->name;
-		ns = mail_namespace_find(virtual_all_namespaces, &mailbox);
+		ns = mail_namespace_find(user->namespaces, &mailbox);
 		bboxes[i]->box = mailbox_open(ns->storage, mailbox,
 					      NULL, open_flags);
 
--- a/src/pop3/client.c	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/pop3/client.c	Tue Aug 12 12:28:42 2008 -0400
@@ -138,8 +138,7 @@
 	return FALSE;
 }
 
-struct client *client_create(int fd_in, int fd_out,
-			     struct mail_namespace *namespaces)
+struct client *client_create(int fd_in, int fd_out, struct mail_user *user)
 {
 	struct mail_storage *storage;
 	const char *inbox;
@@ -164,10 +163,10 @@
 	client->to_idle = timeout_add(CLIENT_IDLE_TIMEOUT_MSECS,
 				      client_idle_timeout, client);
 
-	client->namespaces = namespaces;
+	client->user = user;
 
 	inbox = "INBOX";
-	client->inbox_ns = mail_namespace_find(namespaces, &inbox);
+	client->inbox_ns = mail_namespace_find(user->namespaces, &inbox);
 	if (client->inbox_ns == NULL) {
 		client_send_line(client, "-ERR No INBOX namespace for user.");
 		client_destroy(client, "No INBOX namespace for user.");
@@ -273,7 +272,7 @@
 	}
 	if (client->mailbox != NULL)
 		mailbox_close(&client->mailbox);
-	mail_namespaces_deinit(&client->namespaces);
+	mail_user_deinit(&client->user);
 
 	i_free(client->message_sizes);
 	i_free(client->deleted_bitmask);
--- a/src/pop3/client.h	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/pop3/client.h	Tue Aug 12 12:28:42 2008 -0400
@@ -16,7 +16,8 @@
 	command_func_t *cmd;
 	void *cmd_context;
 
-	struct mail_namespace *namespaces, *inbox_ns;
+	struct mail_user *user;
+	struct mail_namespace *inbox_ns;
 	struct mailbox *mailbox;
 	struct mailbox_transaction_context *trans;
 
@@ -49,8 +50,7 @@
 
 /* Create new client with specified input/output handles. socket specifies
    if the handle is a socket. */
-struct client *client_create(int fd_in, int fd_out,
-			     struct mail_namespace *namespaces);
+struct client *client_create(int fd_in, int fd_out, struct mail_user *user);
 void client_destroy(struct client *client, const char *reason);
 
 /* Disconnect client connection */
--- a/src/pop3/main.c	Fri Aug 08 17:16:07 2008 -0400
+++ b/src/pop3/main.c	Tue Aug 12 12:28:42 2008 -0400
@@ -180,7 +180,7 @@
 
 static bool main_init(void)
 {
-	struct mail_namespace *ns;
+	struct mail_user *user;
 	struct client *client;
 	const char *str;
 	bool ret = TRUE;
@@ -231,9 +231,11 @@
 			"%% variables.");
 
 	namespace_pool = pool_alloconly_create("namespaces", 1024);
-	if (mail_namespaces_init(namespace_pool, getenv("USER"), &ns) < 0)
+	user = mail_user_init(getenv("USER"), getenv("HOME"));
+	if (mail_namespaces_init(namespace_pool, user) < 0)
 		i_fatal("Namespace initialization failed");
-	client = client_create(0, 1, ns);
+
+	client = client_create(0, 1, user);
 	if (client == NULL)
 		return FALSE;