changeset 5500:4862cb37106c HEAD

Moved namespace handling to lib-storage. Beginnings of namespace support for non-IMAP parts of Dovecot.
author Timo Sirainen <tss@iki.fi>
date Tue, 03 Apr 2007 11:34:27 +0300
parents e1e19a0db57d
children e9745c1c4d14
files src/deliver/deliver.c src/deliver/deliver.h src/imap/Makefile.am src/imap/client.c src/imap/client.h src/imap/cmd-create.c src/imap/cmd-list.c src/imap/cmd-namespace.c src/imap/commands-util.c src/imap/commands-util.h src/imap/main.c src/imap/namespace.c src/imap/namespace.h src/lib-storage/Makefile.am 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/convert/convert-storage.c src/plugins/expire/expire-tool.c src/plugins/lazy-expunge/lazy-expunge-plugin.c src/pop3/client.c src/pop3/client.h src/pop3/main.c
diffstat 25 files changed, 478 insertions(+), 433 deletions(-) [+]
line wrap: on
line diff
--- a/src/deliver/deliver.c	Tue Apr 03 10:31:48 2007 +0300
+++ b/src/deliver/deliver.c	Tue Apr 03 11:34:27 2007 +0300
@@ -18,6 +18,7 @@
 #include "message-address.h"
 #include "istream-header-filter.h"
 #include "mbox-storage.h"
+#include "mail-namespace.h"
 #include "dict-client.h"
 #include "mbox-from.h"
 #include "auth-client.h"
@@ -75,26 +76,35 @@
 }
 
 static struct mailbox *
-mailbox_open_or_create_synced(struct mail_storage *storage, const char *name)
+mailbox_open_or_create_synced(struct mail_namespace *namespaces,
+			      struct mail_storage **storage_r, const char *name)
 {
+	struct mail_namespace *ns;
 	struct mailbox *box;
 	bool syntax, temp;
 
-	box = mailbox_open(storage, name, NULL, MAILBOX_OPEN_FAST |
+	ns = mail_namespace_find(namespaces, &name);
+	if (ns == NULL) {
+		*storage_r = NULL;
+		return NULL;
+	}
+	*storage_r = ns->storage;
+
+	box = mailbox_open(ns->storage, name, NULL, MAILBOX_OPEN_FAST |
 			   MAILBOX_OPEN_KEEP_RECENT);
 	if (box != NULL || no_mailbox_autocreate)
 		return box;
 
-	(void)mail_storage_get_last_error(storage, &syntax, &temp);
+	(void)mail_storage_get_last_error(ns->storage, &syntax, &temp);
 	if (syntax || temp)
 		return NULL;
 
 	/* probably the mailbox just doesn't exist. try creating it. */
-	if (mail_storage_mailbox_create(storage, name, FALSE) < 0)
+	if (mail_storage_mailbox_create(ns->storage, name, FALSE) < 0)
 		return NULL;
 
 	/* and try opening again */
-	box = mailbox_open(storage, name, NULL, MAILBOX_OPEN_FAST |
+	box = mailbox_open(ns->storage, name, NULL, MAILBOX_OPEN_FAST |
 			   MAILBOX_OPEN_KEEP_RECENT);
 	if (box == NULL)
 		return NULL;
@@ -106,7 +116,8 @@
 	return box;
 }
 
-int deliver_save(struct mail_storage *storage, const char *mailbox,
+int deliver_save(struct mail_namespace *namespaces,
+		 struct mail_storage **storage_r, const char *mailbox,
 		 struct mail *mail, enum mail_flags flags,
 		 const char *const *keywords)
 {
@@ -119,7 +130,7 @@
 	if (strcmp(mailbox, default_mailbox_name) == 0)
 		tried_default_save = TRUE;
 
-	box = mailbox_open_or_create_synced(storage, mailbox);
+	box = mailbox_open_or_create_synced(namespaces, storage_r, mailbox);
 	if (box == NULL)
 		return -1;
 
@@ -480,14 +491,14 @@
 	const char *auth_socket;
 	const char *home, *destination, *user, *mail_env, *value;
         const struct var_expand_table *table;
-        enum mail_storage_flags flags;
-        enum file_lock_method lock_method;
-	struct mail_storage *storage, *mbox_storage;
+	struct mail_namespace *ns, *mbox_ns;
+	struct mail_storage *storage;
 	struct mailbox *box;
 	struct istream *input;
 	struct mailbox_transaction_context *t;
 	struct mail *mail;
 	uid_t process_euid;
+	pool_t namespace_pool;
 	int i, ret;
 
 	i_set_failure_exit_callback(failure_exit_callback);
@@ -644,7 +655,8 @@
 	mail_storage_register_all();
 	mailbox_list_register_all();
 
-	/* MAIL comes from userdb, MAIL_LOCATION from dovecot.conf */
+	/* MAIL comes from userdb, MAIL_LOCATION from dovecot.conf.
+	   FIXME: should remove these and support namespaces.. */
 	mail_env = getenv("MAIL");
 	if (mail_env == NULL) 
 		mail_env = getenv("MAIL_LOCATION");
@@ -656,23 +668,20 @@
 		table = get_var_expand_table(destination, getenv("HOME"));
 		mail_env = expand_mail_env(mail_env, table);
 	}
+	env_put(t_strconcat("MAIL=", mail_env, NULL));
 
 	module_dir_init(modules);
 
-	/* FIXME: how should we handle namespaces? */
-	mail_storage_parse_env(&flags, &lock_method);
-	storage = mail_storage_create(NULL, mail_env, destination,
-				      flags, lock_method);
-	if (storage == NULL) {
-		i_fatal_status(EX_TEMPFAIL,
-			"Failed to create storage for '%s' with mail '%s'",
-			destination, mail_env == NULL ? "(null)" : mail_env);
-	}
+	namespace_pool = pool_alloconly_create("namespaces", 1024);
+	if (mail_namespaces_init(namespace_pool, destination, &ns) < 0)
+		exit(EX_TEMPFAIL);
 
-	mbox_storage = mail_storage_create("mbox", "/tmp", destination, 0,
-					   FILE_LOCK_METHOD_FCNTL);
+	mbox_ns = mail_namespaces_init_empty(namespace_pool);
+	if (mail_storage_create(mbox_ns, "mbox", "/tmp", destination,
+				0, FILE_LOCK_METHOD_FCNTL) < 0)
+		i_fatal("Couldn't create internal mbox storage");
 	input = create_mbox_stream(0, envelope_sender);
-	box = mailbox_open(mbox_storage, "Dovecot Delivery Mail", input,
+	box = mailbox_open(mbox_ns->storage, "Dovecot Delivery Mail", input,
 			   MAILBOX_OPEN_NO_INDEX_FILES |
 			   MAILBOX_OPEN_MBOX_ONE_MSG_ONLY);
 	if (box == NULL)
@@ -687,18 +696,18 @@
 
 	default_mailbox_name = mailbox;
 	ret = deliver_mail == NULL ? 0 :
-		deliver_mail(storage, mail, destination, mailbox);
+		deliver_mail(ns, &storage, mail, destination, mailbox);
 
 	if (ret == 0 || (ret < 0 && !tried_default_save)) {
 		/* plugins didn't handle this. save into the default mailbox. */
 		i_stream_seek(input, 0);
-		ret = deliver_save(storage, mailbox, mail, 0, NULL);
+		ret = deliver_save(ns, &storage, mailbox, mail, 0, NULL);
 	}
 	if (ret < 0 && strcasecmp(mailbox, "INBOX") != 0) {
 		/* still didn't work. try once more to save it
 		   to INBOX. */
 		i_stream_seek(input, 0);
-		ret = deliver_save(storage, "INBOX", mail, 0, NULL);
+		ret = deliver_save(ns, &storage, "INBOX", mail, 0, NULL);
 	}
 
 	if (ret < 0) {
@@ -723,8 +732,8 @@
 	mailbox_transaction_rollback(&t);
 	mailbox_close(&box);
 
-        mail_storage_destroy(&mbox_storage);
-        mail_storage_destroy(&storage);
+	mail_namespaces_deinit(&mbox_ns);
+	mail_namespaces_deinit(&ns);
 
 	module_dir_unload(&modules);
 	mail_storage_deinit();
--- a/src/deliver/deliver.h	Tue Apr 03 10:31:48 2007 +0300
+++ b/src/deliver/deliver.h	Tue Apr 03 11:34:27 2007 +0300
@@ -14,7 +14,9 @@
 
 extern struct deliver_settings *deliver_set;
 
-typedef int deliver_mail_func_t(struct mail_storage *storage, struct mail *mail,
+typedef int deliver_mail_func_t(struct mail_namespace *namespaces,
+				struct mail_storage **storage_r,
+				struct mail *mail,
 				const char *username, const char *mailbox);
 
 extern deliver_mail_func_t *deliver_mail;
@@ -22,7 +24,8 @@
 void deliver_env_clean(void);
 
 /* Save a mail into given mailbox with given flags and keywords. */
-int deliver_save(struct mail_storage *storage, const char *mailbox,
+int deliver_save(struct mail_namespace *namespaces,
+		 struct mail_storage **storage_r, const char *mailbox,
 		 struct mail *mail, enum mail_flags flags,
 		 const char *const *keywords);
 
--- a/src/imap/Makefile.am	Tue Apr 03 10:31:48 2007 +0300
+++ b/src/imap/Makefile.am	Tue Apr 03 11:34:27 2007 +0300
@@ -84,8 +84,7 @@
 	imap-sync.c \
 	imap-thread.c \
 	mail-storage-callbacks.c \
-	main.c \
-	namespace.c
+	main.c
 
 
 headers = \
@@ -99,8 +98,7 @@
 	imap-search.h \
 	imap-sort.h \
 	imap-sync.h \
-	imap-thread.h \
-	namespace.h
+	imap-thread.h
 
 if INSTALL_HEADERS
   pkginc_libdir=$(pkgincludedir)/src/imap
--- a/src/imap/client.c	Tue Apr 03 10:31:48 2007 +0300
+++ b/src/imap/client.c	Tue Apr 03 11:34:27 2007 +0300
@@ -6,7 +6,7 @@
 #include "istream.h"
 #include "ostream.h"
 #include "commands.h"
-#include "namespace.h"
+#include "mail-namespace.h"
 
 #include <stdlib.h>
 #include <unistd.h>
@@ -17,7 +17,7 @@
 static struct timeout *to_idle;
 
 struct client *client_create(int fd_in, int fd_out,
-			     struct namespace *namespaces)
+			     struct mail_namespace *namespaces)
 {
 	struct client *client;
 
@@ -95,7 +95,7 @@
 
 	if (client->mailbox != NULL)
 		mailbox_close(&client->mailbox);
-	namespace_deinit(client->namespaces);
+	mail_namespaces_deinit(&client->namespaces);
 
 	if (client->free_parser != NULL)
 		imap_parser_destroy(&client->free_parser);
--- a/src/imap/client.h	Tue Apr 03 10:31:48 2007 +0300
+++ b/src/imap/client.h	Tue Apr 03 11:34:27 2007 +0300
@@ -43,7 +43,7 @@
 	struct istream *input;
 	struct ostream *output;
 
-        struct namespace *namespaces;
+        struct mail_namespace *namespaces;
 	struct mailbox *mailbox;
         struct mailbox_keywords keywords;
 	unsigned int select_counter; /* increased when mailbox is changed */
@@ -73,7 +73,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 namespace *namespaces);
+			     struct mail_namespace *namespaces);
 void client_destroy(struct client *client, const char *reason);
 
 /* Disconnect client connection */
--- a/src/imap/cmd-create.c	Tue Apr 03 10:31:48 2007 +0300
+++ b/src/imap/cmd-create.c	Tue Apr 03 11:34:27 2007 +0300
@@ -1,12 +1,12 @@
 /* Copyright (C) 2002 Timo Sirainen */
 
 #include "common.h"
-#include "namespace.h"
+#include "mail-namespace.h"
 #include "commands.h"
 
 bool cmd_create(struct client_command_context *cmd)
 {
-	struct namespace *ns;
+	struct mail_namespace *ns;
 	const char *mailbox, *full_mailbox;
 	bool directory;
 	size_t len;
--- a/src/imap/cmd-list.c	Tue Apr 03 10:31:48 2007 +0300
+++ b/src/imap/cmd-list.c	Tue Apr 03 11:34:27 2007 +0300
@@ -6,7 +6,7 @@
 #include "imap-quote.h"
 #include "imap-match.h"
 #include "commands.h"
-#include "namespace.h"
+#include "mail-namespace.h"
 
 enum {
 	_MAILBOX_LIST_ITER_HIDE_CHILDREN	= 0x1000000,
@@ -18,7 +18,7 @@
 	const char *mask;
 	enum mailbox_list_flags list_flags;
 
-	struct namespace *ns;
+	struct mail_namespace *ns;
 	struct mailbox_list_iterate_context *list_iter;
 	struct imap_match_glob *glob;
 
@@ -232,7 +232,7 @@
 		    struct cmd_list_context *ctx)
 {
         struct client *client = cmd->client;
-	struct namespace *ns = ctx->ns;
+	struct mail_namespace *ns = ctx->ns;
 	const char *cur_ns_prefix, *cur_ref, *cur_mask;
 	enum imap_match_result match;
 	enum imap_match_result inbox_match;
@@ -392,8 +392,8 @@
 		ctx->glob = NULL;
 	}
 
-	cur_ref = namespace_fix_sep(ns, cur_ref);
-	cur_mask = namespace_fix_sep(ns, cur_mask);
+	cur_ref = mail_namespace_fix_sep(ns, cur_ref);
+	cur_mask = mail_namespace_fix_sep(ns, cur_mask);
 
 	list_flags = ctx->list_flags;
 	if (ctx->match_inbox)
@@ -438,7 +438,7 @@
 bool _cmd_list_full(struct client_command_context *cmd, bool lsub)
 {
 	struct client *client = cmd->client;
-	struct namespace *ns;
+	struct mail_namespace *ns;
 	struct imap_arg *args;
 	enum mailbox_list_flags list_flags;
         struct cmd_list_context *ctx;
@@ -485,19 +485,20 @@
 		   concept which probably no other client uses than Pine.
 		   Just try our best to emulate UW-IMAP behavior and hopefully
 		   we're fine. */
-		ns = namespace_find_visible(client->namespaces, &ref);
+		ns = mail_namespace_find_visible(client->namespaces, &ref);
 		if (ns != NULL)
 			ns_prefix = ns->prefix;
 		else {
 			const char *empty = "";
 
 			ns_prefix = "";
-			ns = namespace_find(client->namespaces, &empty);
+			ns = mail_namespace_find(client->namespaces, &empty);
 			if (ns == NULL) {
 				/* we must reply something. use INBOX
 				   namespace's separator. */
 				const char *inbox = "INBOX";
-				ns = namespace_find(client->namespaces, &inbox);
+				ns = mail_namespace_find(client->namespaces,
+							 &inbox);
 			}
 		}
 
--- a/src/imap/cmd-namespace.c	Tue Apr 03 10:31:48 2007 +0300
+++ b/src/imap/cmd-namespace.c	Tue Apr 03 11:34:27 2007 +0300
@@ -4,10 +4,10 @@
 #include "str.h"
 #include "imap-quote.h"
 #include "commands.h"
-#include "namespace.h"
+#include "mail-namespace.h"
 
-static void list_namespaces(struct namespace *ns, enum namespace_type type,
-			    string_t *str)
+static void list_namespaces(struct mail_namespace *ns,
+			    enum namespace_type type, string_t *str)
 {
 	bool found = FALSE;
 
--- a/src/imap/commands-util.c	Tue Apr 03 10:31:48 2007 +0300
+++ b/src/imap/commands-util.c	Tue Apr 03 11:34:27 2007 +0300
@@ -10,7 +10,7 @@
 #include "imap-parser.h"
 #include "imap-sync.h"
 #include "imap-util.h"
-#include "namespace.h"
+#include "mail-namespace.h"
 
 /* Maximum length for mailbox name, including it's path. This isn't fully
    exact since the user can create folder hierarchy with small names, then
@@ -18,12 +18,12 @@
    to them, mbox/maildir currently allow paths only up to PATH_MAX. */
 #define MAILBOX_MAX_NAME_LEN 512
 
-struct namespace *
+struct mail_namespace *
 client_find_namespace(struct client_command_context *cmd, const char **mailbox)
 {
-	struct namespace *ns;
+	struct mail_namespace *ns;
 
-	ns = namespace_find(cmd->client->namespaces, mailbox);
+	ns = mail_namespace_find(cmd->client->namespaces, mailbox);
 	if (ns != NULL)
 		return ns;
 
@@ -34,7 +34,7 @@
 struct mail_storage *
 client_find_storage(struct client_command_context *cmd, const char **mailbox)
 {
-	struct namespace *ns;
+	struct mail_namespace *ns;
 
 	ns = client_find_namespace(cmd, mailbox);
 	return ns == NULL ? NULL : ns->storage;
@@ -44,7 +44,7 @@
 				const char *mailbox,
 				bool should_exist, bool should_not_exist)
 {
-	struct namespace *ns;
+	struct mail_namespace *ns;
 	struct mailbox_list *list;
 	enum mailbox_name_status mailbox_status;
 	const char *orig_mailbox, *p;
--- a/src/imap/commands-util.h	Tue Apr 03 10:31:48 2007 +0300
+++ b/src/imap/commands-util.h	Tue Apr 03 11:34:27 2007 +0300
@@ -11,7 +11,7 @@
 
 /* Finds namespace for given mailbox from namespaces. If not found,
    sends "Unknown namespace" error message to client. */
-struct namespace *
+struct mail_namespace *
 client_find_namespace(struct client_command_context *cmd, const char **mailbox);
 /* Finds mail storage for given mailbox from namespaces. If not found,
    sends "Unknown namespace" error message to client. */
--- a/src/imap/main.c	Tue Apr 03 10:31:48 2007 +0300
+++ b/src/imap/main.c	Tue Apr 03 11:34:27 2007 +0300
@@ -14,7 +14,7 @@
 #include "dict-client.h"
 #include "mail-storage.h"
 #include "commands.h"
-#include "namespace.h"
+#include "mail-namespace.h"
 #include "imap-thread.h"
 
 #include <stdio.h>
@@ -163,6 +163,7 @@
 static void main_init(void)
 {
 	struct client *client;
+	struct mail_namespace *ns;
 	const char *user, *str;
 
 	lib_signals_init();
@@ -232,7 +233,9 @@
         parse_workarounds();
 
 	namespace_pool = pool_alloconly_create("namespaces", 1024);
-	client = client_create(0, 1, namespace_init(namespace_pool, user));
+	if (mail_namespaces_init(namespace_pool, user, &ns) < 0)
+		exit(FATAL_DEFAULT);
+	client = client_create(0, 1, ns);
 
         o_stream_cork(client->output);
 	if (IS_STANDALONE()) {
--- a/src/imap/namespace.c	Tue Apr 03 10:31:48 2007 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,248 +0,0 @@
-/* Copyright (C) 2003 Timo Sirainen */
-
-#include "common.h"
-#include "file-lock.h"
-#include "commands.h"
-#include "namespace.h"
-
-#include <stdlib.h>
-
-static void namespace_init_storage(struct namespace *ns)
-{
-	ns->prefix_len = strlen(ns->prefix);
-	ns->real_sep = mail_storage_get_hierarchy_sep(ns->storage);
-
-	if (ns->sep == '\0')
-                ns->sep = ns->real_sep;
-
-	if (ns->sep == '"' || ns->sep == '\\') {
-		ns->sep_str[0] = '\\';
-		ns->sep_str[1] = ns->sep;
-	} else {
-		ns->sep_str[0] = ns->sep;
-	}
-}
-
-static struct namespace *
-namespace_add_env(pool_t pool, const char *data, unsigned int num,
-		  const char *user, enum mail_storage_flags flags,
-		  enum file_lock_method lock_method)
-{
-        struct namespace *ns;
-        const char *sep, *type, *prefix;
-	bool inbox, hidden, subscriptions;
-
-	ns = p_new(pool, struct namespace, 1);
-
-	sep = getenv(t_strdup_printf("NAMESPACE_%u_SEP", num));
-	type = getenv(t_strdup_printf("NAMESPACE_%u_TYPE", num));
-	prefix = getenv(t_strdup_printf("NAMESPACE_%u_PREFIX", num));
-	inbox = getenv(t_strdup_printf("NAMESPACE_%u_INBOX", num)) != NULL;
-	hidden = getenv(t_strdup_printf("NAMESPACE_%u_HIDDEN", num)) != NULL;
-	subscriptions = getenv(t_strdup_printf("NAMESPACE_%u_SUBSCRIPTIONS",
-					       num)) != NULL;
-
-	if (type == NULL || *type == '\0' || strncmp(type, "private", 7) == 0)
-		ns->type = NAMESPACE_PRIVATE;
-	else if (strncmp(type, "shared", 6) == 0)
-		ns->type = NAMESPACE_SHARED;
-	else if (strncmp(type, "public", 6) == 0)
-		ns->type = NAMESPACE_PUBLIC;
-	else
-		i_fatal("Unknown namespace type: %s", type);
-
-	if (ns->type != NAMESPACE_PRIVATE)
-		flags |= MAIL_STORAGE_FLAG_SHARED_NAMESPACE;
-	if (ns->inbox)
-		flags |= MAIL_STORAGE_FLAG_HAS_INBOX;
-
-	if (prefix == NULL)
-		prefix = "";
-
-	if ((flags & MAIL_STORAGE_FLAG_DEBUG) != 0) {
-		i_info("Namespace: type=%s, prefix=%s, sep=%s, "
-		       "inbox=%s, hidden=%s, subscriptions=%s",
-		       type == NULL ? "" : type, prefix, sep == NULL ? "" : sep,
-		       inbox ? "yes" : "no",
-		       hidden ? "yes" : "no",
-		       subscriptions ? "yes" : "no");
-	}
-
-	ns->prefix = p_strdup(pool, prefix);
-	ns->inbox = inbox;
-	ns->hidden = hidden;
-	ns->subscriptions = subscriptions;
-	ns->storage = mail_storage_create(NULL, data, user, flags, lock_method);
-	if (ns->storage == NULL) {
-		i_fatal("Failed to create storage for '%s' with data: %s",
-			ns->prefix, data);
-	}
-
-	if (sep != NULL)
-		ns->sep = *sep;
-        namespace_init_storage(ns);
-	return ns;
-}
-
-struct namespace *namespace_init(pool_t pool, const char *user)
-{
-	struct namespace *namespaces, *ns, **ns_p;
-	enum mail_storage_flags flags;
-        enum file_lock_method lock_method;
-	const char *mail, *data;
-	unsigned int i;
-
-	mail_storage_parse_env(&flags, &lock_method);
-        namespaces = NULL; ns_p = &namespaces;
-
-	/* first try NAMESPACE_* environments */
-	for (i = 1; ; i++) {
-		t_push();
-		data = getenv(t_strdup_printf("NAMESPACE_%u", i));
-		t_pop();
-
-		if (data == NULL)
-			break;
-
-		t_push();
-		*ns_p = namespace_add_env(pool, data, i, user, flags,
-					  lock_method);
-		t_pop();
-
-		ns_p = &(*ns_p)->next;
-	}
-
-	if (namespaces != NULL)
-		return namespaces;
-
-	/* fallback to MAIL */
-	mail = getenv("MAIL");
-	if (mail == NULL) {
-		/* support also maildir-specific environment */
-		mail = getenv("MAILDIR");
-		if (mail != NULL)
-			mail = t_strconcat("maildir:", mail, NULL);
-	}
-
-	ns = p_new(pool, struct namespace, 1);
-	ns->type = NAMESPACE_PRIVATE;
-	ns->inbox = TRUE;
-	ns->subscriptions = TRUE;
-	ns->prefix = "";
-
-	flags |= MAIL_STORAGE_FLAG_HAS_INBOX;
-	ns->storage = mail_storage_create(NULL, mail, user, flags, lock_method);
-	if (ns->storage == NULL) {
-		if (mail != NULL && *mail != '\0')
-			i_fatal("Failed to create storage with data: %s", mail);
-		else {
-			const char *home;
-
-			home = getenv("HOME");
-			if (home == NULL) home = "not set";
-
-			i_fatal("MAIL environment missing and "
-				"autodetection failed (home %s)", home);
-		}
-	}
-
-	namespace_init_storage(ns);
-	return ns;
-}
-
-void namespace_deinit(struct namespace *namespaces)
-{
-	while (namespaces != NULL) {
-		mail_storage_destroy(&namespaces->storage);
-		namespaces = namespaces->next;
-	}
-}
-
-const char *namespace_fix_sep(struct namespace *ns, const char *name)
-{
-	char *ret, *p;
-
-	if (ns->sep == ns->real_sep)
-		return name;
-
-	ret = p_strdup(unsafe_data_stack_pool, name);
-	for (p = ret; *p != '\0'; p++) {
-		if (*p == ns->sep)
-			*p = ns->real_sep;
-	}
-	return ret;
-}
-
-static struct namespace *
-namespace_find_int(struct namespace *namespaces, const char **mailbox,
-		   int show_hidden)
-{
-#define CHECK_VISIBILITY(ns, show_hidden) \
-	((!(ns)->hidden) || (show_hidden))
-        struct namespace *ns = namespaces;
-	const char *box = *mailbox;
-	struct namespace *best = NULL;
-	size_t best_len = 0;
-	bool inbox;
-
-	inbox = strncasecmp(box, "INBOX", 5) == 0;
-	if (inbox && box[5] == '\0') {
-		/* find the INBOX namespace */
-		*mailbox = "INBOX";
-		while (ns != NULL) {
-			if (ns->inbox && CHECK_VISIBILITY(ns, show_hidden))
-				return ns;
-			if (*ns->prefix == '\0')
-				best = ns;
-			ns = ns->next;
-		}
-		return best;
-	}
-
-	for (; ns != NULL; ns = ns->next) {
-		if (ns->prefix_len >= best_len &&
-		    (strncmp(ns->prefix, box, ns->prefix_len) == 0 ||
-		     (inbox && strncmp(ns->prefix, "INBOX", 5) == 0 &&
-		      strncmp(ns->prefix+5, box+5, ns->prefix_len-5) == 0)) &&
-		    CHECK_VISIBILITY(ns, show_hidden)) {
-			best = ns;
-			best_len = ns->prefix_len;
-		}
-	}
-
-	if (best != NULL) {
-		if (best_len > 0)
-			*mailbox += best_len;
-		else if (inbox && (box[5] == best->sep || box[5] == '\0'))
-			*mailbox = t_strconcat("INBOX", box+5, NULL);
-
-		*mailbox = namespace_fix_sep(best, *mailbox);
-	}
-
-	return best;
-}
-
-struct namespace *
-namespace_find(struct namespace *namespaces, const char **mailbox)
-{
-	return namespace_find_int(namespaces, mailbox, TRUE);
-}
-
-struct namespace *
-namespace_find_visible(struct namespace *namespaces, const char **mailbox)
-{
-	return namespace_find_int(namespaces, mailbox, FALSE);
-}
-
-struct namespace *
-namespace_find_prefix(struct namespace *namespaces, const char *prefix)
-{
-        struct namespace *ns;
-	unsigned int len = strlen(prefix);
-
-	for (ns = namespaces; ns != NULL; ns = ns->next) {
-		if (ns->prefix_len == len && strcmp(ns->prefix, prefix) == 0)
-			return ns;
-	}
-	return NULL;
-}
--- a/src/imap/namespace.h	Tue Apr 03 10:31:48 2007 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-#ifndef __NAMESPACE_H
-#define __NAMESPACE_H
-
-enum namespace_type {
-	NAMESPACE_PRIVATE,
-	NAMESPACE_SHARED,
-	NAMESPACE_PUBLIC
-};
-
-struct namespace {
-	struct namespace *next;
-
-        enum namespace_type type;
-	char sep, real_sep, sep_str[3];
-
-	const char *prefix;
-	size_t prefix_len;
-
-	bool inbox, hidden, subscriptions;
-	struct mail_storage *storage;
-};
-
-struct namespace *namespace_init(pool_t pool, const char *user);
-void namespace_deinit(struct namespace *namespaces);
-
-const char *namespace_fix_sep(struct namespace *ns, const char *name);
-
-struct namespace *
-namespace_find(struct namespace *namespaces, const char **mailbox);
-struct namespace *
-namespace_find_visible(struct namespace *namespaces, const char **mailbox);
-struct namespace *
-namespace_find_prefix(struct namespace *namespaces, const char *prefix);
-
-#endif
--- a/src/lib-storage/Makefile.am	Tue Apr 03 10:31:48 2007 +0300
+++ b/src/lib-storage/Makefile.am	Tue Apr 03 11:34:27 2007 +0300
@@ -11,6 +11,7 @@
 libstorage_a_SOURCES = \
 	mail.c \
 	mail-copy.c \
+	mail-namespace.c \
 	mail-search.c \
 	mail-storage.c \
 	mailbox-list.c \
@@ -18,6 +19,7 @@
 
 headers = \
 	mail-copy.h \
+	mail-namespace.h \
 	mail-search.h \
 	mail-storage.h \
 	mail-storage-private.h \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-storage/mail-namespace.c	Tue Apr 03 11:34:27 2007 +0300
@@ -0,0 +1,273 @@
+/* Copyright (C) 2005-2007 Timo Sirainen */
+
+#include "lib.h"
+#include "file-lock.h"
+#include "mail-storage.h"
+#include "mail-namespace.h"
+
+#include <stdlib.h>
+
+static void namespace_init_storage(struct mail_namespace *ns)
+{
+	ns->prefix_len = strlen(ns->prefix);
+	ns->real_sep = mail_storage_get_hierarchy_sep(ns->storage);
+
+	if (ns->sep == '\0')
+                ns->sep = ns->real_sep;
+
+	if (ns->sep == '"' || ns->sep == '\\') {
+		ns->sep_str[0] = '\\';
+		ns->sep_str[1] = ns->sep;
+	} else {
+		ns->sep_str[0] = ns->sep;
+	}
+}
+
+static struct mail_namespace *
+namespace_add_env(pool_t pool, const char *data, unsigned int num,
+		  const char *user, enum mail_storage_flags flags,
+		  enum file_lock_method lock_method)
+{
+        struct mail_namespace *ns;
+        const char *sep, *type, *prefix;
+	bool inbox, hidden, subscriptions;
+
+	ns = p_new(pool, struct mail_namespace, 1);
+
+	sep = getenv(t_strdup_printf("NAMESPACE_%u_SEP", num));
+	type = getenv(t_strdup_printf("NAMESPACE_%u_TYPE", num));
+	prefix = getenv(t_strdup_printf("NAMESPACE_%u_PREFIX", num));
+	inbox = getenv(t_strdup_printf("NAMESPACE_%u_INBOX", num)) != NULL;
+	hidden = getenv(t_strdup_printf("NAMESPACE_%u_HIDDEN", num)) != NULL;
+	subscriptions = getenv(t_strdup_printf("NAMESPACE_%u_SUBSCRIPTIONS",
+					       num)) != NULL;
+
+	if (type == NULL || *type == '\0' || strncmp(type, "private", 7) == 0)
+		ns->type = NAMESPACE_PRIVATE;
+	else if (strncmp(type, "shared", 6) == 0)
+		ns->type = NAMESPACE_SHARED;
+	else if (strncmp(type, "public", 6) == 0)
+		ns->type = NAMESPACE_PUBLIC;
+	else {
+		i_error("Unknown namespace type: %s", type);
+		return NULL;
+	}
+
+	if (ns->type != NAMESPACE_PRIVATE)
+		flags |= MAIL_STORAGE_FLAG_SHARED_NAMESPACE;
+	if (ns->inbox)
+		flags |= MAIL_STORAGE_FLAG_HAS_INBOX;
+
+	if (prefix == NULL)
+		prefix = "";
+
+	if ((flags & MAIL_STORAGE_FLAG_DEBUG) != 0) {
+		i_info("Namespace: type=%s, prefix=%s, sep=%s, "
+		       "inbox=%s, hidden=%s, subscriptions=%s",
+		       type == NULL ? "" : type, prefix, sep == NULL ? "" : sep,
+		       inbox ? "yes" : "no",
+		       hidden ? "yes" : "no",
+		       subscriptions ? "yes" : "no");
+	}
+
+	ns->prefix = p_strdup(pool, prefix);
+	ns->inbox = inbox;
+	ns->hidden = hidden;
+	ns->subscriptions = subscriptions;
+	if (mail_storage_create(ns, NULL, data, user, flags, lock_method) < 0) {
+		i_error("Failed to create storage for '%s' with data: %s",
+			ns->prefix, data);
+		return NULL;
+	}
+
+	if (sep != NULL)
+		ns->sep = *sep;
+        namespace_init_storage(ns);
+	return ns;
+}
+
+int mail_namespaces_init(pool_t pool, const char *user,
+			 struct mail_namespace **namespaces_r)
+{
+	struct mail_namespace *namespaces, *ns, **ns_p;
+	enum mail_storage_flags flags;
+        enum file_lock_method lock_method;
+	const char *mail, *data;
+	unsigned int i;
+
+	mail_storage_parse_env(&flags, &lock_method);
+        namespaces = NULL; ns_p = &namespaces;
+
+	/* first try NAMESPACE_* environments */
+	for (i = 1; ; i++) {
+		t_push();
+		data = getenv(t_strdup_printf("NAMESPACE_%u", i));
+		t_pop();
+
+		if (data == NULL)
+			break;
+
+		t_push();
+		*ns_p = namespace_add_env(pool, data, i, user, flags,
+					  lock_method);
+		t_pop();
+
+		if (*ns_p != NULL)
+			return -1;
+
+		ns_p = &(*ns_p)->next;
+	}
+
+	if (namespaces != NULL) {
+		*namespaces_r = namespaces;
+		return 0;
+	}
+
+	/* fallback to MAIL */
+	mail = getenv("MAIL");
+	if (mail == NULL) {
+		/* support also maildir-specific environment */
+		mail = getenv("MAILDIR");
+		if (mail != NULL)
+			mail = t_strconcat("maildir:", mail, NULL);
+	}
+
+	ns = p_new(pool, struct mail_namespace, 1);
+	ns->type = NAMESPACE_PRIVATE;
+	ns->inbox = TRUE;
+	ns->subscriptions = TRUE;
+	ns->prefix = "";
+
+	flags |= MAIL_STORAGE_FLAG_HAS_INBOX;
+	if (mail_storage_create(ns, NULL, mail, user, flags, lock_method) < 0) {
+		if (mail != NULL && *mail != '\0')
+			i_error("Failed to create storage with data: %s", mail);
+		else {
+			const char *home;
+
+			home = getenv("HOME");
+			if (home == NULL) home = "not set";
+
+			i_error("MAIL environment missing and "
+				"autodetection failed (home %s)", home);
+		}
+		return -1;
+	}
+
+	namespace_init_storage(ns);
+	*namespaces_r = ns;
+	return 0;
+}
+
+struct mail_namespace *mail_namespaces_init_empty(pool_t pool)
+{
+	struct mail_namespace *ns;
+
+	ns = p_new(pool, struct mail_namespace, 1);
+	ns->prefix = "";
+	return ns;
+}
+
+void mail_namespaces_deinit(struct mail_namespace **_namespaces)
+{
+	struct mail_namespace *namespaces = *_namespaces;
+
+	*_namespaces = NULL;
+	while (namespaces != NULL) {
+		if (namespaces->storage != NULL)
+			mail_storage_destroy(&namespaces->storage);
+		namespaces = namespaces->next;
+	}
+}
+
+const char *mail_namespace_fix_sep(struct mail_namespace *ns, const char *name)
+{
+	char *ret, *p;
+
+	if (ns->sep == ns->real_sep)
+		return name;
+
+	ret = p_strdup(unsafe_data_stack_pool, name);
+	for (p = ret; *p != '\0'; p++) {
+		if (*p == ns->sep)
+			*p = ns->real_sep;
+	}
+	return ret;
+}
+
+static struct mail_namespace *
+mail_namespace_find_int(struct mail_namespace *namespaces, const char **mailbox,
+			bool show_hidden)
+{
+#define CHECK_VISIBILITY(ns, show_hidden) \
+	((!(ns)->hidden) || (show_hidden))
+        struct mail_namespace *ns = namespaces;
+	const char *box = *mailbox;
+	struct mail_namespace *best = NULL;
+	size_t best_len = 0;
+	bool inbox;
+
+	inbox = strncasecmp(box, "INBOX", 5) == 0;
+	if (inbox && box[5] == '\0') {
+		/* find the INBOX namespace */
+		*mailbox = "INBOX";
+		while (ns != NULL) {
+			if (ns->inbox && CHECK_VISIBILITY(ns, show_hidden))
+				return ns;
+			if (*ns->prefix == '\0')
+				best = ns;
+			ns = ns->next;
+		}
+		return best;
+	}
+
+	for (; ns != NULL; ns = ns->next) {
+		if (ns->prefix_len >= best_len &&
+		    (strncmp(ns->prefix, box, ns->prefix_len) == 0 ||
+		     (inbox && strncmp(ns->prefix, "INBOX", 5) == 0 &&
+		      strncmp(ns->prefix+5, box+5, ns->prefix_len-5) == 0)) &&
+		    CHECK_VISIBILITY(ns, show_hidden)) {
+			best = ns;
+			best_len = ns->prefix_len;
+		}
+	}
+
+	if (best != NULL) {
+		if (best_len > 0)
+			*mailbox += best_len;
+		else if (inbox && (box[5] == best->sep || box[5] == '\0'))
+			*mailbox = t_strconcat("INBOX", box+5, NULL);
+
+		*mailbox = mail_namespace_fix_sep(best, *mailbox);
+	}
+
+	return best;
+}
+
+struct mail_namespace *
+mail_namespace_find(struct mail_namespace *namespaces, const char **mailbox)
+{
+	return mail_namespace_find_int(namespaces, mailbox, TRUE);
+}
+
+struct mail_namespace *
+mail_namespace_find_visible(struct mail_namespace *namespaces,
+			    const char **mailbox)
+{
+	return mail_namespace_find_int(namespaces, mailbox, FALSE);
+}
+
+struct mail_namespace *
+mail_namespace_find_prefix(struct mail_namespace *namespaces,
+			   const char *prefix)
+{
+        struct mail_namespace *ns;
+	unsigned int len = strlen(prefix);
+
+	for (ns = namespaces; ns != NULL; ns = ns->next) {
+		if (ns->prefix_len == len &&
+		    strcmp(ns->prefix, prefix) == 0)
+			return ns;
+	}
+	return NULL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-storage/mail-namespace.h	Tue Apr 03 11:34:27 2007 +0300
@@ -0,0 +1,39 @@
+#ifndef __MAIL_NAMESPACE_H
+#define __MAIL_NAMESPACE_H
+
+enum namespace_type {
+	NAMESPACE_PRIVATE,
+	NAMESPACE_SHARED,
+	NAMESPACE_PUBLIC
+};
+
+struct mail_namespace {
+	struct mail_namespace *next;
+
+        enum namespace_type type;
+	char sep, real_sep, sep_str[3];
+
+	const char *prefix;
+	size_t prefix_len;
+
+	bool inbox, hidden, subscriptions;
+	struct mail_storage *storage;
+};
+
+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);
+void mail_namespaces_deinit(struct mail_namespace **namespaces);
+
+const char *mail_namespace_fix_sep(struct mail_namespace *ns, const char *name);
+
+struct mail_namespace *
+mail_namespace_find(struct mail_namespace *namespaces, const char **mailbox);
+struct mail_namespace *
+mail_namespace_find_visible(struct mail_namespace *namespaces,
+			    const char **mailbox);
+struct mail_namespace *
+mail_namespace_find_prefix(struct mail_namespace *namespaces,
+			   const char *prefix);
+
+#endif
--- a/src/lib-storage/mail-storage-private.h	Tue Apr 03 10:31:48 2007 +0300
+++ b/src/lib-storage/mail-storage-private.h	Tue Apr 03 11:34:27 2007 +0300
@@ -53,6 +53,7 @@
 	pool_t pool;
 
 	char *error;
+	struct mail_namespace *ns;
 	struct mailbox_list *list;
 
 	const char *user; /* name of user accessing the storage */
--- a/src/lib-storage/mail-storage.c	Tue Apr 03 10:31:48 2007 +0300
+++ b/src/lib-storage/mail-storage.c	Tue Apr 03 11:34:27 2007 +0300
@@ -7,6 +7,7 @@
 #include "mail-index-private.h"
 #include "mailbox-list-private.h"
 #include "mail-storage-private.h"
+#include "mail-namespace.h"
 #include "index/index-storage.h"
 
 #include <stdlib.h>
@@ -149,10 +150,10 @@
 	}
 }
 
-struct mail_storage *
-mail_storage_create(const char *driver, const char *data, const char *user,
-		    enum mail_storage_flags flags,
-		    enum file_lock_method lock_method)
+int mail_storage_create(struct mail_namespace *ns, const char *driver,
+			const char *data, const char *user,
+			enum mail_storage_flags flags,
+			enum file_lock_method lock_method)
 {
 	struct mail_storage *storage_class, *storage;
 	struct mail_storage *const *classes;
@@ -173,14 +174,14 @@
 				"don't know what to do with it: %s "
 				"(try prefixing it with mbox: or maildir:)",
 				data);
-			return NULL;
+			return -1;
 		}
 		classes = &storage_class;
 		count = 1;
 	} else {
 		storage_class = mail_storage_find(driver);
 		if (storage_class == NULL)
-			return NULL;
+			return -1;
 		classes = &storage_class;
 		count = 1;
 	}
@@ -190,6 +191,7 @@
 		storage->flags = flags;
 		storage->lock_method = lock_method;
 		storage->user = p_strdup(storage->pool, user);
+		storage->ns = ns;
 
 		storage->callbacks =
 			p_new(storage->pool, struct mail_storage_callbacks, 1);
@@ -202,11 +204,13 @@
 		pool_unref(storage->pool);
 	}
 	if (i == count)
-		return NULL;
+		return -1;
 
 	if (hook_mail_storage_created != NULL)
 		hook_mail_storage_created(storage);
-	return storage;
+
+	ns->storage = storage;
+	return 0;
 }
 
 void mail_storage_destroy(struct mail_storage **_storage)
@@ -319,6 +323,11 @@
 	return storage->list;
 }
 
+struct mail_namespace *mail_storage_get_namespace(struct mail_storage *storage)
+{
+	return storage->ns;
+}
+
 void mail_storage_set_callbacks(struct mail_storage *storage,
 				struct mail_storage_callbacks *callbacks,
 				void *context)
--- a/src/lib-storage/mail-storage.h	Tue Apr 03 10:31:48 2007 +0300
+++ b/src/lib-storage/mail-storage.h	Tue Apr 03 11:34:27 2007 +0300
@@ -136,6 +136,7 @@
 	MAILBOX_SYNC_TYPE_KEYWORDS	= 0x04
 };
 
+struct mail_namespace;
 struct mail_storage;
 struct mail_search_arg;
 struct mail_keywords;
@@ -204,15 +205,16 @@
 /* Create a new instance of registered mail storage class with given
    storage-specific data. If driver is NULL, it's tried to be autodetected
    from data. If data is NULL, it uses the first storage that exists.
-   May return NULL if anything fails. */
-struct mail_storage *
-mail_storage_create(const char *driver, const char *data, const char *user,
-		    enum mail_storage_flags flags,
-		    enum file_lock_method lock_method);
+   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,
+			enum file_lock_method lock_method);
 void mail_storage_destroy(struct mail_storage **storage);
 
 char mail_storage_get_hierarchy_sep(struct mail_storage *storage);
 struct mailbox_list *mail_storage_get_list(struct mail_storage *storage);
+struct mail_namespace *mail_storage_get_namespace(struct mail_storage *storage);
 void mail_storage_set_list_error(struct mail_storage *storage);
 
 /* Set storage callback functions to use. */
--- a/src/plugins/convert/convert-storage.c	Tue Apr 03 10:31:48 2007 +0300
+++ b/src/plugins/convert/convert-storage.c	Tue Apr 03 11:34:27 2007 +0300
@@ -1,8 +1,10 @@
 /* Copyright (C) 2006 Timo Sirainen */
 
 #include "lib.h"
+#include "file-lock.h"
 #include "file-dotlock.h"
-#include "index-storage.h"
+#include "mail-storage-private.h"
+#include "mail-namespace.h"
 #include "mail-search.h"
 #include "convert-storage.h"
 
@@ -246,25 +248,25 @@
 		    const char *source_data, const char *dest_data,
 		    bool skip_broken_mailboxes)
 {
-	struct mail_storage *source_storage, *dest_storage;
+	struct mail_namespace *source_ns, *dest_ns;
 	struct dotlock *dotlock;
         enum mail_storage_flags flags;
         enum file_lock_method lock_method;
 	const char *path;
 	int ret;
 
+	source_ns = mail_namespaces_init_empty(pool_datastack_create());
 	mail_storage_parse_env(&flags, &lock_method);
 	flags |= MAIL_STORAGE_FLAG_NO_AUTOCREATE | MAIL_STORAGE_FLAG_HAS_INBOX;
-	source_storage = mail_storage_create(NULL, source_data, user,
-					     flags, lock_method);
-	if (source_storage == NULL) {
+	if (mail_storage_create(source_ns, NULL, source_data, user,
+				flags, lock_method) < 0) {
 		/* No need for conversion. */
 		return 0;
 	}
 
         path = t_strconcat(home_dir, "/"CONVERT_LOCK_FILENAME, NULL);
 	dotlock_settings.use_excl_lock =
-		(source_storage->flags &
+		(source_ns->storage->flags &
 		 MAIL_STORAGE_FLAG_DOTLOCK_USE_EXCL) != 0;
 	ret = file_dotlock_create(&dotlock_settings, path, 0, &dotlock);
 	if (ret <= 0) {
@@ -275,27 +277,26 @@
 
 	/* just in case if another process just had converted the mailbox,
 	   reopen the source storage */
-	mail_storage_destroy(&source_storage);
-	source_storage = mail_storage_create(NULL, source_data, user,
-					     flags, lock_method);
-	if (source_storage == NULL) {
+	mail_storage_destroy(&source_ns->storage);
+	if (mail_storage_create(source_ns, NULL, source_data, user,
+				flags, lock_method) < 0) {
 		/* No need for conversion anymore. */
 		file_dotlock_delete(&dotlock);
 		return 0;
 	}
 
-	dest_storage = mail_storage_create(NULL, dest_data, user,
-					   flags, lock_method);
-	if (dest_storage == NULL) {
+	dest_ns = mail_namespaces_init_empty(pool_datastack_create());
+	if (mail_storage_create(dest_ns, NULL, dest_data, user,
+				flags, lock_method) < 0) {
 		i_error("Mailbox conversion: Failed to create destination "
 			"storage with data: %s", dest_data);
 		ret = -1;
 	} else {
-		ret = mailbox_list_copy(source_storage, dest_storage, dotlock,
-					skip_broken_mailboxes);
+		ret = mailbox_list_copy(source_ns->storage, dest_ns->storage,
+					dotlock, skip_broken_mailboxes);
 		if (ret == 0) {
-			ret = mailbox_list_copy_subscriptions(source_storage,
-							      dest_storage);
+			ret = mailbox_list_copy_subscriptions(
+					source_ns->storage, dest_ns->storage);
 		}
 	}
 
@@ -305,7 +306,7 @@
 		const char *src, *dest;
 		bool is_file;
 
-		src = mail_storage_get_mailbox_path(source_storage, "",
+		src = mail_storage_get_mailbox_path(source_ns->storage, "",
 						    &is_file);
 		if (src != NULL) {
 			dest = t_strconcat(src, "-converted", NULL);
@@ -319,8 +320,7 @@
 	}
 
 	file_dotlock_delete(&dotlock);
-	if (dest_storage != NULL)
-		mail_storage_destroy(&dest_storage);
-	mail_storage_destroy(&source_storage);
+	mail_namespaces_deinit(&dest_ns);
+	mail_namespaces_deinit(&source_ns);
 	return ret;
 }
--- a/src/plugins/expire/expire-tool.c	Tue Apr 03 10:31:48 2007 +0300
+++ b/src/plugins/expire/expire-tool.c	Tue Apr 03 11:34:27 2007 +0300
@@ -8,6 +8,7 @@
 #include "dict-client.h"
 #include "mail-search.h"
 #include "mail-storage.h"
+#include "mail-namespace.h"
 #include "auth-client.h"
 #include "expire-env.h"
 
@@ -23,14 +24,12 @@
 	struct auth_connection *auth_conn;
 
 	char *user;
-	struct mail_storage *storage;
+	pool_t namespace_pool;
+	struct mail_namespace *ns;
 };
 
 static int user_init(struct expire_context *ctx, const char *user)
 {
-	enum mail_storage_flags flags;
-	enum file_lock_method lock_method;
-	const char *mail_env;
 	int ret;
 
 	if ((ret = auth_client_put_user_env(ctx->auth_conn, user)) <= 0) {
@@ -41,22 +40,16 @@
 		return 0;
 	}
 
-	mail_env = getenv("MAIL");
-	mail_storage_parse_env(&flags, &lock_method);
-	ctx->storage = mail_storage_create(NULL, mail_env, user,
-					   flags, lock_method);
-	if (ctx->storage == NULL) {
-		i_error("Failed to create storage for '%s' with mail '%s'",
-			user, mail_env == NULL ? "(null)" : mail_env);
+	if (mail_namespaces_init(ctx->namespace_pool, user, &ctx->ns) < 0)
 		return -1;
-	}
 	return 1;
 }
 
 static void user_deinit(struct expire_context *ctx)
 {
-	mail_storage_destroy(&ctx->storage);
+	mail_namespaces_deinit(&ctx->ns);
 	i_free_and_null(ctx->user);
+	p_clear(ctx->namespace_pool);
 }
 
 static int
@@ -64,6 +57,7 @@
 			 const char *mailbox, time_t expire_secs,
 			 time_t *oldest_r)
 {
+	struct mail_namespace *ns;
 	struct mailbox *box;
 	struct mail_search_context *search_ctx;
 	struct mailbox_transaction_context *t;
@@ -86,7 +80,11 @@
 	search_arg.type = SEARCH_ALL;
 	search_arg.next = NULL;
 
-	box = mailbox_open(ctx->storage, mailbox, NULL, 0);
+	ns = mail_namespace_find(ctx->ns, &mailbox);
+	if (ns == NULL)
+		return -1;
+
+	box = mailbox_open(ns->storage, mailbox, NULL, 0);
 	t = mailbox_transaction_begin(box, 0);
 	search_ctx = mailbox_search_init(t, NULL, &search_arg, NULL);
 	mail = mail_alloc(t, 0, NULL);
@@ -150,6 +148,7 @@
 
 	memset(&ctx, 0, sizeof(ctx));
 	ctx.auth_conn = auth_connection_init(auth_socket);
+	ctx.namespace_pool = pool_alloconly_create("namespaces", 1024);
 	env = expire_env_init(getenv("EXPIRE"));
 	dict = dict_init(getenv("EXPIRE_DICT"), DICT_DATA_TYPE_UINT32, "");
 	trans = dict_transaction_begin(dict);
--- a/src/plugins/lazy-expunge/lazy-expunge-plugin.c	Tue Apr 03 10:31:48 2007 +0300
+++ b/src/plugins/lazy-expunge/lazy-expunge-plugin.c	Tue Apr 03 11:34:27 2007 +0300
@@ -7,7 +7,7 @@
 #include "seq-range-array.h"
 #include "maildir-storage.h"
 #include "client.h"
-#include "namespace.h"
+#include "mail-namespace.h"
 #include "lazy-expunge-plugin.h"
 
 #include <stdio.h>
@@ -63,7 +63,7 @@
 static MODULE_CONTEXT_DEFINE_INIT(lazy_expunge_mailbox_list_module,
 				  &mailbox_list_module_register);
 
-static struct namespace *lazy_namespaces[LAZY_NAMESPACE_COUNT];
+static struct mail_namespace *lazy_namespaces[LAZY_NAMESPACE_COUNT];
 
 static struct mailbox *
 mailbox_open_or_create(struct mail_storage *storage, const char *name)
@@ -515,7 +515,7 @@
 			i_fatal("lazy_expunge: Missing namespace #%d", i + 1);
 
 		lazy_namespaces[i] =
-			namespace_find_prefix((*client)->namespaces, name);
+			mail_namespace_find_prefix((*client)->namespaces, name);
 		if (lazy_namespaces[i] == NULL)
 			i_fatal("lazy_expunge: Unknown namespace: '%s'", name);
 		if (strcmp(lazy_namespaces[i]->storage->name, "maildir") != 0) {
--- a/src/pop3/client.c	Tue Apr 03 10:31:48 2007 +0300
+++ b/src/pop3/client.c	Tue Apr 03 11:34:27 2007 +0300
@@ -11,6 +11,7 @@
 #include "mail-storage.h"
 #include "commands.h"
 #include "mail-search.h"
+#include "mail-namespace.h"
 
 #include <stdlib.h>
 #include <unistd.h>
@@ -124,8 +125,10 @@
 }
 
 struct client *client_create(int fd_in, int fd_out,
-			     struct mail_storage *storage)
+			     struct mail_namespace *namespaces)
 {
+	struct mail_storage *storage;
+	const char *inbox;
 	struct client *client;
         enum mailbox_open_flags flags;
 	const char *errmsg;
@@ -146,8 +149,18 @@
 
 	client->io = io_add(fd_in, IO_READ, client_input, client);
         client->last_input = ioloop_time;
-	client->storage = storage;
+
+	client->namespaces = namespaces;
 
+	inbox = "INBOX";
+	client->inbox_ns = mail_namespace_find(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.");
+		return NULL;
+	}
+
+	storage = client->inbox_ns->storage;
 	mail_storage_set_callbacks(storage, &mail_storage_callbacks, client);
 
 	flags = 0;
@@ -237,7 +250,7 @@
 	}
 	if (client->mailbox != NULL)
 		mailbox_close(&client->mailbox);
-	mail_storage_destroy(&client->storage);
+	mail_namespaces_deinit(&client->namespaces);
 
 	i_free(client->message_sizes);
 	i_free(client->deleted_bitmask);
@@ -333,7 +346,7 @@
 		return;
 	}
 
-	error = mail_storage_get_last_error(client->storage, &syntax,
+	error = mail_storage_get_last_error(client->inbox_ns->storage, &syntax,
 					    &temporary_error);
 	client_send_line(client, "-ERR %s", error != NULL ? error :
 			 "BUG: Unknown error");
--- a/src/pop3/client.h	Tue Apr 03 10:31:48 2007 +0300
+++ b/src/pop3/client.h	Tue Apr 03 11:34:27 2007 +0300
@@ -15,7 +15,7 @@
 	command_func_t *cmd;
 	void *cmd_context;
 
-	struct mail_storage *storage;
+	struct mail_namespace *namespaces, *inbox_ns;
 	struct mailbox *mailbox;
 	struct mailbox_transaction_context *trans;
 
@@ -49,7 +49,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_storage *storage);
+			     struct mail_namespace *namespaces);
 void client_destroy(struct client *client, const char *reason);
 
 /* Disconnect client connection */
--- a/src/pop3/main.c	Tue Apr 03 10:31:48 2007 +0300
+++ b/src/pop3/main.c	Tue Apr 03 11:34:27 2007 +0300
@@ -13,6 +13,7 @@
 #include "var-expand.h"
 #include "dict-client.h"
 #include "mail-storage.h"
+#include "mail-namespace.h"
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -38,6 +39,7 @@
 void (*hook_client_created)(struct client **client) = NULL;
 
 static struct module *modules = NULL;
+static pool_t namespace_pool;
 static char log_prefix[128]; /* syslog() needs this to be permanent */
 static struct io *log_io = NULL;
 
@@ -180,10 +182,7 @@
 
 static int main_init(void)
 {
-        enum mail_storage_flags flags;
-        enum file_lock_method lock_method;
-	struct mail_storage *storage;
-	const char *mail;
+	struct mail_namespace *ns;
 
 	lib_signals_init();
         lib_signals_set_handler(SIGINT, TRUE, sig_die, NULL);
@@ -213,14 +212,6 @@
 
 	module_dir_init(modules);
 
-	mail = getenv("MAIL");
-	if (mail == NULL) {
-		/* support also maildir-specific environment */
-		mail = getenv("MAILDIR");
-		if (mail != NULL)
-			mail = t_strconcat("maildir:", mail, NULL);
-	}
-
 	parse_workarounds();
 	enable_last_command = getenv("POP3_ENABLE_LAST") != NULL;
 	no_flag_updates = getenv("POP3_NO_FLAG_UPDATES") != NULL;
@@ -238,25 +229,10 @@
 		i_fatal("pop3_uidl_format setting doesn't contain any "
 			"%% variables.");
 
-	mail_storage_parse_env(&flags, &lock_method);
-	storage = mail_storage_create(NULL, mail, getenv("USER"),
-				      flags, lock_method);
-	if (storage == NULL) {
-		/* failed */
-		if (mail != NULL && *mail != '\0')
-			i_fatal("Failed to create storage with data: %s", mail);
-		else {
-			const char *home;
-
-			home = getenv("HOME");
-			if (home == NULL) home = "not set";
-
-			i_fatal("MAIL environment missing and "
-				"autodetection failed (home %s)", home);
-		}
-	}
-
-	return client_create(0, 1, storage) != NULL;
+	namespace_pool = pool_alloconly_create("namespaces", 1024);
+	if (mail_namespaces_init(namespace_pool, getenv("USER"), &ns) < 0)
+		exit(FATAL_DEFAULT);
+	return client_create(0, 1, ns) != NULL;
 }
 
 static void main_deinit(void)