changeset 12586:a2780b694b2d

lib-storage: mailbox_alloc() now takes a virtual mailbox name and other related API changes. All storage_name <-> vname conversions now go through the same two mailbox_list methods. This has many benefits, such as: * listescape plugin is now much simpler and bugfree * allows changing lib-storage API to use UTF-8 mailbox names in future * allows creation of "mailbox aliases" plugin
author Timo Sirainen <tss@iki.fi>
date Thu, 20 Jan 2011 20:59:07 +0200
parents b748c622e896
children c3a258ee96c4
files TODO src/doveadm/doveadm-mail-import.c src/doveadm/doveadm-mail-iter.c src/doveadm/doveadm-mail-list-iter.c src/doveadm/doveadm-mail-mailbox.c src/doveadm/doveadm-mail.c src/dsync/dsync-worker-local.c src/imap/cmd-create.c src/imap/cmd-delete.c src/imap/cmd-list.c src/imap/cmd-namespace.c src/imap/cmd-rename.c src/imap/cmd-select.c src/imap/cmd-status.c src/imap/cmd-subscribe.c src/imap/imap-commands-util.c src/imap/imap-commands-util.h src/lib-lda/mail-deliver.c src/lib-storage/index/cydir/cydir-storage.c src/lib-storage/index/dbox-multi/mdbox-storage-rebuild.c src/lib-storage/index/dbox-multi/mdbox-storage.c src/lib-storage/index/dbox-multi/mdbox-storage.h src/lib-storage/index/dbox-single/sdbox-storage.c src/lib-storage/index/imapc/imapc-storage.c src/lib-storage/index/index-storage.c src/lib-storage/index/index-storage.h src/lib-storage/index/maildir/maildir-storage.c src/lib-storage/index/mbox/mbox-storage.c src/lib-storage/index/raw/raw-storage.c src/lib-storage/index/shared/shared-list.c src/lib-storage/index/shared/shared-storage.c src/lib-storage/list/index-mailbox-list.c src/lib-storage/list/mailbox-list-fs-iter.c src/lib-storage/list/mailbox-list-fs.c src/lib-storage/list/mailbox-list-maildir-iter.c src/lib-storage/list/mailbox-list-maildir.c src/lib-storage/list/mailbox-list-maildir.h src/lib-storage/list/mailbox-list-none.c src/lib-storage/list/mailbox-list-subscriptions.c src/lib-storage/mail-namespace.c src/lib-storage/mail-namespace.h src/lib-storage/mail-search.c src/lib-storage/mail-storage-private.h src/lib-storage/mail-storage.c src/lib-storage/mail-storage.h src/lib-storage/mailbox-list-private.h src/lib-storage/mailbox-list.c src/lib-storage/mailbox-list.h src/lib-storage/test-mail-storage.h src/lib-storage/test-mailbox.c src/plugins/acl/acl-backend-vfile-acllist.c src/plugins/acl/acl-backend-vfile.c src/plugins/acl/acl-mailbox-list.c src/plugins/autocreate/autocreate-plugin.c src/plugins/fts-solr/fts-backend-solr.c src/plugins/fts/fts-storage.c src/plugins/imap-acl/imap-acl-plugin.c src/plugins/imap-quota/imap-quota-plugin.c src/plugins/listescape/listescape-plugin.c src/plugins/quota/quota-count.c src/plugins/quota/quota-maildir.c src/plugins/quota/quota-storage.c src/plugins/quota/quota.c src/plugins/snarf/snarf-plugin.c src/plugins/trash/trash-plugin.c src/plugins/virtual/virtual-config.c src/plugins/virtual/virtual-storage.c src/pop3/pop3-client.c
diffstat 68 files changed, 911 insertions(+), 1037 deletions(-) [+]
line wrap: on
line diff
--- a/TODO	Thu Jan 20 19:21:20 2011 +0200
+++ b/TODO	Thu Jan 20 20:59:07 2011 +0200
@@ -1,3 +1,5 @@
+ - check:
+    - dsyncing between two namespace separators is probably broken..
  - remove mail_deliver_session after all, do all the stuff transparently
    by hooking into mailbox_copy().
      - use this hook also to do the mail deduplication: 1) sort all destination
--- a/src/doveadm/doveadm-mail-import.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/doveadm/doveadm-mail-import.c	Thu Jan 20 20:59:07 2011 +0200
@@ -24,29 +24,27 @@
 	struct mail_namespace *ns;
 	struct mailbox *box;
 	enum mail_error error;
-	const char *errstr, *storage_name;
+	const char *errstr;
 
 	if (*ctx->dest_parent != '\0') {
 		/* prefix destination mailbox name with given parent mailbox */
-		storage_name = ctx->dest_parent;
-		ns = mail_namespace_find(user->namespaces, &storage_name);
+		ns = mail_namespace_find(user->namespaces, ctx->dest_parent);
 		if (ns == NULL) {
 			i_error("Can't find namespace for parent mailbox %s",
 				ctx->dest_parent);
 			return -1;
 		}
 		name = t_strdup_printf("%s%c%s", ctx->dest_parent,
-				       ns->sep, name);
+				       mail_namespace_get_sep(ns), name);
 	}
 
-	storage_name = name;
-	ns = mail_namespace_find(user->namespaces, &storage_name);
+	ns = mail_namespace_find(user->namespaces, name);
 	if (ns == NULL) {
 		i_error("Can't find namespace for mailbox %s", name);
 		return -1;
 	}
 
-	box = mailbox_alloc(ns->list, storage_name, MAILBOX_FLAG_SAVEONLY |
+	box = mailbox_alloc(ns->list, name, MAILBOX_FLAG_SAVEONLY |
 			    MAILBOX_FLAG_KEEP_RECENT);
 	if (mailbox_create(box, NULL, FALSE) < 0) {
 		errstr = mailbox_get_last_error(box, &error);
--- a/src/doveadm/doveadm-mail-iter.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/doveadm/doveadm-mail-iter.c	Thu Jan 20 20:59:07 2011 +0200
@@ -20,12 +20,9 @@
 			   struct doveadm_mail_iter **iter_r)
 {
 	struct doveadm_mail_iter *iter;
-	const char *storage_name;
-
-	storage_name = mail_namespace_get_storage_name(info->ns, info->name);
 
 	iter = i_new(struct doveadm_mail_iter, 1);
-	iter->box = mailbox_alloc(info->ns->list, storage_name,
+	iter->box = mailbox_alloc(info->ns->list, info->name,
 				  MAILBOX_FLAG_KEEP_RECENT |
 				  MAILBOX_FLAG_IGNORE_ACLS);
 	iter->search_args = search_args;
--- a/src/doveadm/doveadm-mail-list-iter.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/doveadm/doveadm-mail-list-iter.c	Thu Jan 20 20:59:07 2011 +0200
@@ -119,19 +119,22 @@
 	unsigned int len;
 
 	while ((info = mailbox_list_iter_next(iter->iter)) != NULL) {
+		char sep = mail_namespace_get_sep(info->ns);
+
 		if ((info->flags & (MAILBOX_NOSELECT |
 				    MAILBOX_NONEXISTENT)) != 0) {
 			if (iter->only_selectable)
 				continue;
 		}
 		len = strlen(info->name);
-		if (len > 0 && info->name[len-1] == info->ns->sep) {
+		if (len > 0 &&
+		    info->name[len-1] == sep) {
 			/* when listing "foo/%" it lists "foo/". skip it. */
 			continue;
 		}
 
 		if (mail_search_args_match_mailbox(iter->search_args,
-						   info->name, info->ns->sep))
+						   info->name, sep))
 			break;
 	}
 	return info;
--- a/src/doveadm/doveadm-mail-mailbox.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/doveadm/doveadm-mail-mailbox.c	Thu Jan 20 20:59:07 2011 +0200
@@ -184,33 +184,34 @@
 	struct mailbox_cmd_context *ctx = (struct mailbox_cmd_context *)_ctx;
 	struct mail_namespace *ns;
 	struct mailbox *box;
+	struct mail_storage *storage;
 	const char *const *namep;
 
 	array_foreach(&ctx->mailboxes, namep) {
-		const char *storage_name = *namep;
+		const char *name = *namep;
 		unsigned int len;
 		bool directory = FALSE;
 
-		ns = mail_namespace_find(user->namespaces, &storage_name);
+		ns = mail_namespace_find(user->namespaces, name);
 		if (ns == NULL)
-			i_fatal("Can't find namespace for: %s", *namep);
+			i_fatal("Can't find namespace for: %s", name);
 
-		len = strlen(storage_name);
-		if (len > 0 && storage_name[len-1] == ns->real_sep) {
-			storage_name = t_strndup(storage_name, len-1);
+		len = strlen(name);
+		if (len > 0 && name[len-1] == mail_namespace_get_sep(ns)) {
+			name = t_strndup(name, len-1);
 			directory = TRUE;
 		}
 
-		box = mailbox_alloc(ns->list, storage_name, 0);
+		box = mailbox_alloc(ns->list, name, 0);
+		storage = mailbox_get_storage(box);
 		if (mailbox_create(box, NULL, directory) < 0) {
-			i_error("Can't create mailbox %s: %s", *namep,
+			i_error("Can't create mailbox %s: %s", name,
 				mailbox_get_last_error(box, NULL));
 		}
 		if (ctx->ctx.subscriptions) {
-			if (mailbox_list_set_subscribed(ns->list, storage_name,
-							TRUE) < 0) {
-				i_error("Can't subscribe to mailbox %s: %s", *namep,
-					mailbox_list_get_last_error(ns->list, NULL));
+			if (mailbox_set_subscribed(box, TRUE) < 0) {
+				i_error("Can't subscribe to mailbox %s: %s", name,
+					mail_storage_get_last_error(storage, NULL));
 			}
 		}
 		mailbox_free(&box);
@@ -252,25 +253,26 @@
 	struct mailbox_cmd_context *ctx = (struct mailbox_cmd_context *)_ctx;
 	struct mail_namespace *ns;
 	struct mailbox *box;
+	struct mail_storage *storage;
 	const char *const *namep;
 
 	array_foreach(&ctx->mailboxes, namep) {
-		const char *storage_name = *namep;
+		const char *name = *namep;
 
-		ns = mail_namespace_find(user->namespaces, &storage_name);
+		ns = mail_namespace_find(user->namespaces, name);
 		if (ns == NULL)
-			i_fatal("Can't find namespace for: %s", *namep);
+			i_fatal("Can't find namespace for: %s", name);
 
-		box = mailbox_alloc(ns->list, storage_name, 0);
+		box = mailbox_alloc(ns->list, name, 0);
+		storage = mailbox_get_storage(box);
 		if (mailbox_delete(box) < 0) {
-			i_error("Can't delete mailbox %s: %s", *namep,
+			i_error("Can't delete mailbox %s: %s", name,
 				mailbox_get_last_error(box, NULL));
 		}
 		if (ctx->ctx.subscriptions) {
-			if (mailbox_list_set_subscribed(ns->list, storage_name,
-							FALSE) < 0) {
-				i_error("Can't unsubscribe mailbox %s: %s", *namep,
-					mailbox_list_get_last_error(ns->list, NULL));
+			if (mailbox_set_subscribed(box, FALSE) < 0) {
+				i_error("Can't unsubscribe mailbox %s: %s", name,
+					mail_storage_get_last_error(storage, NULL));
 			}
 		}
 		mailbox_free(&box);
@@ -315,10 +317,10 @@
 	const char *oldname = ctx->oldname;
 	const char *newname = ctx->newname;
 
-	oldns = mail_namespace_find(user->namespaces, &oldname);
+	oldns = mail_namespace_find(user->namespaces, oldname);
 	if (oldns == NULL)
 		i_fatal("Can't find namespace for: %s", oldname);
-	newns = mail_namespace_find(user->namespaces, &newname);
+	newns = mail_namespace_find(user->namespaces, newname);
 	if (newns == NULL)
 		i_fatal("Can't find namespace for: %s", newname);
 
@@ -329,13 +331,13 @@
 			mailbox_get_last_error(oldbox, NULL));
 	}
 	if (ctx->ctx.subscriptions) {
-		if (mailbox_list_set_subscribed(oldns->list, oldname, FALSE) < 0) {
+		if (mailbox_set_subscribed(oldbox, FALSE) < 0) {
 			i_error("Can't unsubscribe mailbox %s: %s", ctx->oldname,
-				mailbox_list_get_last_error(oldns->list, NULL));
+				mailbox_get_last_error(oldbox, NULL));
 		}
-		if (mailbox_list_set_subscribed(newns->list, newname, TRUE) < 0) {
+		if (mailbox_set_subscribed(newbox, TRUE) < 0) {
 			i_error("Can't subscribe to mailbox %s: %s", ctx->newname,
-				mailbox_list_get_last_error(newns->list, NULL));
+				mailbox_get_last_error(newbox, NULL));
 		}
 	}
 
@@ -376,19 +378,18 @@
 	const char *const *namep;
 
 	array_foreach(&ctx->mailboxes, namep) {
-		const char *storage_name = *namep;
+		const char *name = *namep;
 
-		ns = mail_namespace_find(user->namespaces, &storage_name);
+		ns = mail_namespace_find(user->namespaces, name);
 		if (ns == NULL)
-			i_fatal("Can't find namespace for: %s", *namep);
+			i_fatal("Can't find namespace for: %s", name);
 
-		box = mailbox_alloc(ns->list, storage_name, 0);
-		if (mailbox_list_set_subscribed(ns->list, storage_name,
-						ctx->ctx.subscriptions) < 0) {
-			i_error("Can't %s mailbox %s: %s", *namep,
+		box = mailbox_alloc(ns->list, name, 0);
+		if (mailbox_set_subscribed(box, ctx->ctx.subscriptions) < 0) {
+			i_error("Can't %s mailbox %s: %s", name,
 				ctx->ctx.subscriptions ? "subscribe to" :
 				"unsubscribe",
-				mailbox_list_get_last_error(ns->list, NULL));
+				mail_storage_get_last_error(mailbox_get_storage(box), NULL));
 		}
 		mailbox_free(&box);
 	}
--- a/src/doveadm/doveadm-mail.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/doveadm/doveadm-mail.c	Thu Jan 20 20:59:07 2011 +0200
@@ -82,7 +82,7 @@
 		i_fatal("Mailbox name not valid UTF-8: %s", mailbox);
 	mailbox = str_c(str);
 
-	ns = mail_namespace_find(user->namespaces, &mailbox);
+	ns = mail_namespace_find(user->namespaces, mailbox);
 	if (ns == NULL)
 		i_fatal("Can't find namespace for mailbox %s", mailbox);
 
--- a/src/dsync/dsync-worker-local.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/dsync/dsync-worker-local.c	Thu Jan 20 20:59:07 2011 +0200
@@ -13,6 +13,7 @@
 #include "mail-namespace.h"
 #include "mail-storage.h"
 #include "mail-search-build.h"
+#include "mailbox-list-private.h"
 #include "dsync-worker-private.h"
 
 #include <ctype.h>
@@ -48,7 +49,7 @@
 struct local_dsync_mailbox {
 	struct mail_namespace *ns;
 	mailbox_guid_t guid;
-	const char *storage_name;
+	const char *name;
 };
 
 struct local_dsync_mailbox_change {
@@ -442,8 +443,7 @@
 
 static void
 local_dsync_worker_add_mailbox(struct local_dsync_worker *worker,
-			       struct mail_namespace *ns,
-			       const char *storage_name,
+			       struct mail_namespace *ns, const char *name,
 			       const mailbox_guid_t *guid)
 {
 	struct local_dsync_mailbox *lbox;
@@ -451,7 +451,7 @@
 	lbox = p_new(worker->pool, struct local_dsync_mailbox, 1);
 	lbox->ns = ns;
 	memcpy(lbox->guid.guid, guid->guid, sizeof(lbox->guid.guid));
-	lbox->storage_name = p_strdup(worker->pool, storage_name);
+	lbox->name = p_strdup(worker->pool, name);
 
 	hash_table_insert(worker->mailbox_hash, &lbox->guid, lbox);
 }
@@ -535,9 +535,9 @@
 		return iter_next_deleted(iter, worker, dsync_box_r);
 
 	dsync_box_r->name = info->name;
-	dsync_box_r->name_sep = info->ns->sep;
+	dsync_box_r->name_sep = mail_namespace_get_sep(info->ns);
 
-	storage_name = mail_namespace_get_storage_name(info->ns, info->name);
+	storage_name = mailbox_list_get_storage_name(info->ns->list, info->name);
 	dsync_str_sha_to_guid(storage_name, &dsync_box_r->name_sha1);
 
 	/* get last change timestamp */
@@ -553,12 +553,12 @@
 
 	if ((info->flags & MAILBOX_NOSELECT) != 0) {
 		dsync_box_r->flags |= DSYNC_MAILBOX_FLAG_NOSELECT;
-		local_dsync_worker_add_mailbox(worker, info->ns, storage_name,
+		local_dsync_worker_add_mailbox(worker, info->ns, info->name,
 					       &dsync_box_r->name_sha1);
 		return 1;
 	}
 
-	box = mailbox_alloc(info->ns->list, storage_name, flags);
+	box = mailbox_alloc(info->ns->list, info->name, flags);
 	if (mailbox_get_status(box, status_items, &status) < 0 ||
 	    mailbox_get_metadata(box, metadata_items, &metadata) < 0) {
 		i_error("Failed to sync mailbox %s: %s", info->name,
@@ -596,12 +596,12 @@
 		i_error("Mailboxes don't have unique GUIDs: "
 			"%s is shared by %s and %s",
 			dsync_guid_to_str(&dsync_box_r->mailbox_guid),
-			old_lbox->storage_name, storage_name);
+			old_lbox->name, info->name);
 		mailbox_free(&box);
 		_iter->failed = TRUE;
 		return -1;
 	}
-	local_dsync_worker_add_mailbox(worker, info->ns, storage_name,
+	local_dsync_worker_add_mailbox(worker, info->ns, info->name,
 				       &dsync_box_r->mailbox_guid);
 	mailbox_free(&box);
 	return 1;
@@ -642,18 +642,6 @@
 	return &iter->iter;
 }
 
-static struct mail_namespace *
-find_subscription_ns(struct local_dsync_worker *worker, const char *vname)
-{
-	struct mail_namespace *const *nsp;
-
-	array_foreach(&worker->subs_namespaces, nsp) {
-		if (strncmp((*nsp)->prefix, vname, (*nsp)->prefix_len) == 0)
-			return *nsp;
-	}
-	return NULL;
-}
-
 static int
 local_worker_subs_iter_next(struct dsync_worker_subs_iter *_iter,
 			    struct dsync_worker_subscription *rec_r)
@@ -664,7 +652,6 @@
 		(struct local_dsync_worker *)_iter->worker;
 	struct local_dsync_dir_change *change, change_lookup;
 	const struct mailbox_info *info;
-	struct mail_namespace *subs_ns;
 	const char *storage_name;
 
 	memset(rec_r, 0, sizeof(*rec_r));
@@ -673,13 +660,7 @@
 	if (info == NULL)
 		return -1;
 
-	subs_ns = find_subscription_ns(worker, info->name);
-	if (subs_ns == NULL)
-		subs_ns = info->ns;
-	storage_name = mail_namespace_get_storage_name(subs_ns, info->name);
-	if (subs_ns != info->ns)
-		storage_name = t_strconcat(subs_ns->prefix, storage_name, NULL);
-
+	storage_name = mailbox_list_get_storage_name(info->ns->list, info->name);
 	dsync_str_sha_to_guid(storage_name, &change_lookup.name_sha1);
 	change_lookup.list = info->ns->list;
 
@@ -748,36 +729,27 @@
 {
 	struct local_dsync_worker *worker =
 		(struct local_dsync_worker *)_worker;
-	struct mail_namespace *ns, *subs_ns;
-	const char *storage_name;
+	struct mail_namespace *ns;
+	struct mailbox *box;
 
-	storage_name = name;
-	ns = mail_namespace_find(worker->user->namespaces,
-				 &storage_name);
+	ns = mail_namespace_find(worker->user->namespaces, name);
 	if (ns == NULL) {
 		i_error("Can't find namespace for mailbox %s", name);
 		return;
 	}
 
-	subs_ns = find_subscription_ns(worker, name);
-	if (subs_ns != NULL) {
-		/* subscription is being written to a different namespace
-		   than where the mailbox exists. */
-		storage_name = mail_namespace_get_storage_name(subs_ns, name);
-		storage_name = t_strconcat(subs_ns->prefix, storage_name, NULL);
-		/* drop the common prefix */
-		i_assert(strncmp(ns->prefix, storage_name,
-				 strlen(ns->prefix)) == 0);
-		storage_name += strlen(ns->prefix);
-	}
+	box = mailbox_alloc(ns->list, name, 0);
+	ns = mailbox_get_namespace(box);
 
 	mailbox_list_set_changelog_timestamp(ns->list, last_change);
-	if (mailbox_list_set_subscribed(ns->list, storage_name, set) < 0) {
+	if (mailbox_set_subscribed(box, set) < 0) {
 		dsync_worker_set_failure(_worker);
 		i_error("Can't update subscription %s: %s", name,
-			mailbox_list_get_last_error(ns->list, NULL));
+			mail_storage_get_last_error(mailbox_get_storage(box),
+						    NULL));
 	}
 	mailbox_list_set_changelog_timestamp(ns->list, (time_t)-1);
+	mailbox_free(&box);
 }
 
 static int local_mailbox_open(struct local_dsync_worker *worker,
@@ -796,10 +768,10 @@
 		return -1;
 	}
 
-	box = mailbox_alloc(lbox->ns->list, lbox->storage_name, flags);
+	box = mailbox_alloc(lbox->ns->list, lbox->name, flags);
 	if (mailbox_sync(box, 0) < 0 ||
 	    mailbox_get_metadata(box, MAILBOX_METADATA_GUID, &metadata) < 0) {
-		i_error("Failed to sync mailbox %s: %s", lbox->storage_name,
+		i_error("Failed to sync mailbox %s: %s", lbox->name,
 			mailbox_get_last_error(box, NULL));
 		mailbox_free(&box);
 		return -1;
@@ -807,7 +779,7 @@
 
 	if (memcmp(metadata.guid, guid->guid, sizeof(guid->guid)) != 0) {
 		i_error("Mailbox %s changed its GUID (%s -> %s)",
-			lbox->storage_name, dsync_guid_to_str(guid),
+			lbox->name, dsync_guid_to_str(guid),
 			mail_guid_128_to_string(metadata.guid));
 		mailbox_free(&box);
 		return -1;
@@ -1071,16 +1043,19 @@
 				  const struct dsync_mailbox *dsync_box,
 				  bool creating)
 {
-	if (dsync_box->name_sep != ns->sep) {
+	char list_sep, ns_sep = mail_namespace_get_sep(ns);
+
+	if (dsync_box->name_sep != ns_sep) {
 		/* mailbox names use different separators. convert them. */
 		name = mailbox_name_convert(worker, name,
-					    dsync_box->name_sep, ns->sep);
+					    dsync_box->name_sep, ns_sep);
 	}
 	if (creating) {
+		list_sep = mailbox_list_get_hierarchy_sep(ns->list);
 		if (!mailbox_list_is_valid_create_name(ns->list, name)) {
 			/* change any real separators to alt separators,
 			   drop any potentially invalid characters */
-			name = mailbox_name_cleanup(name, ns->real_sep,
+			name = mailbox_name_cleanup(name, list_sep,
 						    worker->alt_char);
 		}
 		if (!mailbox_list_is_valid_create_name(ns->list, name)) {
@@ -1119,17 +1094,16 @@
 				  &dsync_box->mailbox_guid);
 	if (lbox != NULL) {
 		/* use the existing known mailbox name */
-		return mailbox_alloc(lbox->ns->list, lbox->storage_name, 0);
+		return mailbox_alloc(lbox->ns->list, lbox->name, 0);
 	}
 
-	name = dsync_box->name;
-	ns = mail_namespace_find(worker->user->namespaces, &name);
+	ns = mail_namespace_find(worker->user->namespaces, dsync_box->name);
 	if (ns == NULL) {
 		i_error("Can't find namespace for mailbox %s", dsync_box->name);
 		return NULL;
 	}
 
-	name = local_worker_convert_mailbox_name(worker, name, ns,
+	name = local_worker_convert_mailbox_name(worker, dsync_box->name, ns,
 						 dsync_box, creating);
 	if (!dsync_mailbox_is_noselect(dsync_box)) {
 		local_dsync_worker_add_mailbox(worker, ns, name,
@@ -1261,9 +1235,9 @@
 
 	mailbox_list_set_changelog_timestamp(lbox->ns->list,
 					     dsync_box->last_change);
-	box = mailbox_alloc(lbox->ns->list, lbox->storage_name, 0);
+	box = mailbox_alloc(lbox->ns->list, lbox->name, 0);
 	if (mailbox_delete(box) < 0) {
-		i_error("Can't delete mailbox %s: %s", lbox->storage_name,
+		i_error("Can't delete mailbox %s: %s", lbox->name,
 			mailbox_get_last_error(box, NULL));
 		dsync_worker_set_failure(_worker);
 	}
@@ -1280,8 +1254,8 @@
 	struct mail_namespace *ns;
 	const char *storage_name;
 
-	storage_name = dsync_box->name;
-	ns = mail_namespace_find(worker->user->namespaces, &storage_name);
+	ns = mail_namespace_find(worker->user->namespaces, dsync_box->name);
+	storage_name = mailbox_list_get_storage_name(ns->list, dsync_box->name);
 
 	mailbox_list_set_changelog_timestamp(ns->list, dsync_box->last_change);
 	if (mailbox_list_delete_dir(ns->list, storage_name) < 0) {
@@ -1315,21 +1289,21 @@
 	list = lbox->ns->list;
 	newname = local_worker_convert_mailbox_name(worker, dsync_box->name,
 						    lbox->ns, dsync_box, TRUE);
-	if (strcmp(lbox->storage_name, newname) == 0) {
+	if (strcmp(lbox->name, newname) == 0) {
 		/* nothing changed after all. probably because some characters
 		   in mailbox name weren't valid. */
 		return;
 	}
 
 	mailbox_list_set_changelog_timestamp(list, dsync_box->last_change);
-	old_box = mailbox_alloc(list, lbox->storage_name, 0);
+	old_box = mailbox_alloc(list, lbox->name, 0);
 	new_box = mailbox_alloc(list, newname, 0);
 	if (mailbox_rename(old_box, new_box, FALSE) < 0) {
-		i_error("Can't rename mailbox %s to %s: %s", lbox->storage_name,
+		i_error("Can't rename mailbox %s to %s: %s", lbox->name,
 			newname, mailbox_get_last_error(old_box, NULL));
 		dsync_worker_set_failure(_worker);
 	} else {
-		lbox->storage_name = p_strdup(worker->pool, newname);
+		lbox->name = p_strdup(worker->pool, newname);
 	}
 	mailbox_free(&old_box);
 	mailbox_free(&new_box);
--- a/src/imap/cmd-create.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/imap/cmd-create.c	Thu Jan 20 20:59:07 2011 +0200
@@ -8,7 +8,7 @@
 bool cmd_create(struct client_command_context *cmd)
 {
 	struct mail_namespace *ns;
-	const char *mailbox, *storage_name;
+	const char *mailbox, *orig_mailbox;
 	struct mailbox *box;
 	bool directory;
 	size_t len;
@@ -17,36 +17,27 @@
 	if (!client_read_string_args(cmd, 1, &mailbox))
 		return FALSE;
 
-	ns = client_find_namespace(cmd, mailbox, &storage_name);
+	orig_mailbox = mailbox;
+	ns = client_find_namespace(cmd, &mailbox);
 	if (ns == NULL)
 		return TRUE;
 
-	len = strlen(mailbox);
-	if (len == 0 || mailbox[len-1] != ns->sep)
+	len = strlen(orig_mailbox);
+	if (len == 0 || orig_mailbox[len-1] != mail_namespace_get_sep(ns))
 		directory = FALSE;
-	else if (*storage_name == '\0') {
-		client_send_tagline(cmd, "NO ["IMAP_RESP_CODE_ALREADYEXISTS
-				    "] Namespace already exists.");
-		return TRUE;
-	} else {
+	else {
 		/* name ends with hierarchy separator - client is just
 		   informing us that it wants to create children under this
 		   mailbox. */
                 directory = TRUE;
-		mailbox = t_strndup(mailbox, len-1);
 
-		/* drop also from storage_name. it's already dropped when
+		/* drop separator from mailbox. it's already dropped when
 		   WORKAROUND_TB_EXTRA_MAILBOX_SEP is enabled */
-		len = strlen(storage_name);
-		if (storage_name[len-1] == ns->real_sep)
-			storage_name = t_strndup(storage_name, len-1);
+		if (len == strlen(mailbox))
+			mailbox = t_strndup(mailbox, len-1);
 	}
 
-	ns = client_find_namespace(cmd, mailbox, &storage_name);
-	if (ns == NULL)
-		return TRUE;
-
-	box = mailbox_alloc(ns->list, storage_name, 0);
+	box = mailbox_alloc(ns->list, mailbox, 0);
 	if (mailbox_create(box, NULL, directory) < 0)
 		client_send_storage_error(cmd, mailbox_get_storage(box));
 	else
--- a/src/imap/cmd-delete.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/imap/cmd-delete.c	Thu Jan 20 20:59:07 2011 +0200
@@ -8,7 +8,7 @@
 	struct client *client = cmd->client;
 	struct mail_namespace *ns;
 	struct mailbox *box;
-	const char *name, *storage_name;
+	const char *name;
 
 	/* <mailbox> */
 	if (!client_read_string_args(cmd, 1, &name))
@@ -20,11 +20,11 @@
 		return TRUE;
 	}
 
-	ns = client_find_namespace(cmd, name, &storage_name);
+	ns = client_find_namespace(cmd, &name);
 	if (ns == NULL)
 		return TRUE;
 
-	box = mailbox_alloc(ns->list, storage_name, 0);
+	box = mailbox_alloc(ns->list, name, 0);
 	if (client->mailbox != NULL &&
 	    mailbox_backends_equal(box, client->mailbox)) {
 		/* deleting selected mailbox. close it first */
--- a/src/imap/cmd-list.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/imap/cmd-list.c	Thu Jan 20 20:59:07 2011 +0200
@@ -225,10 +225,10 @@
 	bool inboxcase;
 
 	inboxcase = strncasecmp(ctx->ns->prefix, "INBOX", 5) == 0 &&
-		ctx->ns->prefix[5] == ctx->ns->sep;
+		ctx->ns->prefix[5] == mail_namespace_get_sep(ctx->ns);
 	glob = imap_match_init_multiple(pool_datastack_create(),
 					ctx->patterns, inboxcase,
-					ctx->ns->sep);
+					mail_namespace_get_sep(ctx->ns));
 	ns_prefix = ctx->ns->prefix;
 	match = imap_match(glob, ns_prefix);
 	if (match == IMAP_MATCH_YES) {
@@ -237,7 +237,7 @@
 	}
 
 	while ((match & IMAP_MATCH_PARENT) != 0) {
-		p = strrchr(ns_prefix, ctx->ns->sep);
+		p = strrchr(ns_prefix, mail_namespace_get_sep(ctx->ns));
 		i_assert(p != NULL);
 		ns_prefix = t_strdup_until(ns_prefix, p);
 		match = imap_match(glob, ns_prefix);
@@ -246,6 +246,16 @@
 	return ns_prefix;
 }
 
+static void list_reply_append_ns_sep_param(string_t *str, char sep)
+{
+	str_append_c(str, '"');
+	if (sep == '\\')
+		str_append(str, "\\\\");
+	else
+		str_append_c(str, sep);
+	str_append_c(str, '"');
+}
+
 static void
 list_namespace_send_prefix(struct cmd_list_context *ctx, bool have_children)
 {
@@ -255,6 +265,7 @@
 	const char *name;
 	string_t *str;
 	bool same_ns, ends_with_sep;
+	char ns_sep = mail_namespace_get_sep(ctx->ns);
 
 	ctx->cur_ns_send_prefix = FALSE;
 
@@ -267,7 +278,7 @@
 
 	name = ns_get_listed_prefix(ctx);
 	len = strlen(ctx->ns->prefix);
-	ends_with_sep = ctx->ns->prefix[len-1] == ctx->ns->sep;
+	ends_with_sep = ctx->ns->prefix[len-1] == ns_sep;
 
 	/* we may be listing namespace's parent. in such case we always want to
 	   set the name as nonexistent. */
@@ -314,9 +325,13 @@
 	}
 
 	str = t_str_new(128);
-	str_append(str, "* LIST (");
+	str_printfa(str, "* %s (", ctx->lsub ? "LSUB" : "LIST");
+	if (ctx->lsub)
+		flags |= MAILBOX_NONEXISTENT;
 	mailbox_flags2str(ctx, str, flags);
-	str_printfa(str, ") \"%s\" ", ctx->ns->sep_str);
+	str_append(str, ") ");
+	list_reply_append_ns_sep_param(str, ns_sep);
+	str_append_c(str, ' ');
 	imap_quote_append_string(str, name, FALSE);
 	mailbox_childinfo2str(ctx, str, flags);
 
@@ -328,7 +343,7 @@
 {
 	struct imap_status_result result;
 	struct mail_namespace *ns;
-	const char *storage_name, *error;
+	const char *error;
 
 	if ((flags & (MAILBOX_NONEXISTENT | MAILBOX_NOSELECT)) != 0) {
 		/* doesn't exist, don't even try to get STATUS */
@@ -342,9 +357,8 @@
 
 	/* if we're listing subscriptions and there are subscriptions=no
 	   namespaces, ctx->ns may not point to correct one */
-	storage_name = name;
-	ns = mail_namespace_find(ctx->ns->user->namespaces, &storage_name);
-	if (imap_status_get(ctx->cmd, ns, storage_name,
+	ns = mail_namespace_find(ctx->ns->user->namespaces, name);
+	if (imap_status_get(ctx->cmd, ns, name,
 			    &ctx->status_items, &result, &error) < 0) {
 		client_send_line(ctx->cmd->client,
 				 t_strconcat("* ", error, NULL));
@@ -427,7 +441,10 @@
 		str_truncate(str, 0);
 		str_printfa(str, "* %s (", ctx->lsub ? "LSUB" : "LIST");
 		mailbox_flags2str(ctx, str, flags);
-		str_printfa(str, ") \"%s\" ", ctx->ns->sep_str);
+		str_append(str, ") ");
+		list_reply_append_ns_sep_param(str,
+			mail_namespace_get_sep(ctx->ns));
+		str_append_c(str, ' ');
 		imap_quote_append_string(str, name, FALSE);
 		mailbox_childinfo2str(ctx, str, flags);
 
@@ -506,7 +523,7 @@
 		     -> cur_ns_prefix="", cur_ref="baz"
 		   */
 		skip_namespace_prefix(&cur_ns_prefix, &cur_ref, TRUE,
-				      ctx->ns->sep);
+				      mail_namespace_get_sep(ctx->ns));
 
 		if (*cur_ref != '\0' && *cur_ns_prefix != '\0') {
 			/* reference parameter didn't match with
@@ -537,7 +554,8 @@
 	i_assert(*cur_ref == '\0');
 
 	skip_namespace_prefix(&cur_ns_prefix, &cur_pattern,
-			      cur_ref == ctx->ref, ctx->ns->sep);
+			      cur_ref == ctx->ref,
+			      mail_namespace_get_sep(ctx->ns));
 
 	if (*cur_pattern == '\0' && *cur_ns_prefix == '\0') {
 		/* trying to list the namespace prefix itself. */
@@ -567,7 +585,7 @@
 		inbox_glob =
 			imap_match_init(pool_datastack_create(),
 					t_strconcat(ctx->ref, *pat, NULL),
-					TRUE, ctx->ns->sep);
+					TRUE, mail_namespace_get_sep(ctx->ns));
 		match = imap_match(inbox_glob, "INBOX");
 
 		if (match == IMAP_MATCH_YES)
@@ -582,16 +600,8 @@
 list_want_send_prefix(struct cmd_list_context *ctx, const char *pattern)
 {
 	/* don't send the prefix if we're listing subscribed mailboxes */
-	if ((ctx->list_flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) != 0) {
-		if ((ctx->ns->flags & NAMESPACE_FLAG_SUBSCRIPTIONS) == 0) {
-			/* using parent's subscriptions file. it'll handle
-			   this internally */
-			return FALSE;
-		}
-		/* send prefix if namespace has at least some subscriptions,
-		   but pattern doesn't match any children (e.g. "%") */
-		return TRUE;
-	}
+	if ((ctx->list_flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) != 0)
+		return FALSE;
 
 	/* send the prefix if namespace is listable. if children are listable
 	   we may or may not need to send it. */
@@ -644,7 +654,7 @@
 	   don't do it if we're listing only the prefix itself
 	   (LIST "" foo/ needs to return "foo/" entry) */
 	len = strlen(cur_ns_prefix);
-	if (cur_ns_prefix[len-1] == ns->sep &&
+	if (cur_ns_prefix[len-1] == mail_namespace_get_sep(ns) &&
 	    strcmp(cur_pattern, cur_ns_prefix) != 0) {
 		ctx->cur_ns_skip_trailing_sep = TRUE;
 		cur_ns_prefix = t_strndup(cur_ns_prefix, len-1);
@@ -658,7 +668,7 @@
 
 	/* check if this namespace prefix matches the current pattern */
 	pat_glob = imap_match_init(pool_datastack_create(), orig_cur_pattern,
-				   inboxcase, ns->sep);
+				   inboxcase, mail_namespace_get_sep(ns));
 	match = imap_match(pat_glob, cur_ns_prefix);
 	if (match == IMAP_MATCH_YES) {
 		if (list_want_send_prefix(ctx, orig_cur_pattern))
@@ -670,9 +680,14 @@
 			if (*p == '*')
 				return TRUE;
 		}
+		if ((ctx->list_flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) != 0) {
+			/* the namespace prefix itself may be subscribed. */
+			return TRUE;
+		}
+		return FALSE;
 	} else {
 		while ((match & IMAP_MATCH_PARENT) != 0) {
-			p = strrchr(cur_ns_prefix, ns->sep);
+			p = strrchr(cur_ns_prefix, mail_namespace_get_sep(ns));
 			if (p == NULL)
 				break;
 			cur_ns_prefix = t_strdup_until(cur_ns_prefix, p);
@@ -685,9 +700,8 @@
 			if (list_want_send_prefix(ctx, orig_cur_pattern))
 				ctx->cur_ns_send_prefix = TRUE;
 		}
+		return (match & IMAP_MATCH_CHILDREN) != 0;
 	}
-
-	return (match & IMAP_MATCH_CHILDREN) != 0;
 }
 
 static void list_namespace_init(struct cmd_list_context *ctx)
@@ -701,12 +715,6 @@
 	cur_ns_prefix = ns->prefix;
 	cur_ref = ctx->ref;
 
-	if ((ns->flags & NAMESPACE_FLAG_SUBSCRIPTIONS) == 0 &&
-	    (ctx->list_flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) != 0) {
-		/* ignore namespaces which don't have subscriptions */
-		return;
-	}
-
 	ctx->cur_ns_skip_trailing_sep = FALSE;
 
 	if ((ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0)
@@ -750,22 +758,24 @@
 	(void)array_append_space(&used_patterns); /* NULL-terminate */
 	pat = array_idx(&used_patterns, 0);
 
-	cur_ref = mail_namespace_fix_sep(ns, cur_ref);
 	ctx->list_iter = mailbox_list_iter_init_multiple(ns->list, pat,
 							 ctx->list_flags);
 }
 
 static void list_inbox(struct cmd_list_context *ctx)
 {
-	const char *str;
+	string_t *str;
 
 	/* INBOX always exists */
 	if (!ctx->inbox_found && ctx->cur_ns_match_inbox &&
 	    (ctx->ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0 &&
 	    (ctx->list_flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) == 0) {
-		str = t_strdup_printf("* LIST (\\Unmarked) \"%s\" \"INBOX\"",
-				      ctx->ns->sep_str);
-		client_send_line(ctx->cmd->client, str);
+		str = t_str_new(64);
+		str_append(str, "* LIST (\\Unmarked) ");
+		list_reply_append_ns_sep_param(str,
+			mail_namespace_get_sep(ctx->ns));
+		str_append(str, " \"INBOX\"");
+		client_send_line(ctx->cmd->client, str_c(str));
 	}
 }
 
@@ -821,10 +831,10 @@
 	/* 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->user->namespaces, &ref);
+	ns = mail_namespace_find_visible(client->user->namespaces, ref);
 	if (ns != NULL) {
 		ns_prefix = ns->prefix;
-		ns_sep = ns->sep;
+		ns_sep = mail_namespace_get_sep(ns);
 	} else {
 		ns_prefix = "";
 		ns_sep = mail_namespaces_get_root_sep(client->user->namespaces);
--- a/src/imap/cmd-namespace.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/imap/cmd-namespace.c	Thu Jan 20 20:59:07 2011 +0200
@@ -9,6 +9,7 @@
 static void list_namespaces(struct mail_namespace *ns,
 			    enum namespace_type type, string_t *str)
 {
+	char ns_sep;
 	bool found = FALSE;
 
 	while (ns != NULL) {
@@ -18,10 +19,13 @@
 				str_append_c(str, '(');
 				found = TRUE;
 			}
+			ns_sep = mail_namespace_get_sep(ns);
 			str_append_c(str, '(');
 			imap_quote_append_string(str, ns->prefix, FALSE);
 			str_append(str, " \"");
-			str_append(str, ns->sep_str);
+			if (ns_sep == '\\')
+				str_append_c(str, '\\');
+			str_append_c(str, ns_sep);
 			str_append(str, "\")");
 		}
 
--- a/src/imap/cmd-rename.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/imap/cmd-rename.c	Thu Jan 20 20:59:07 2011 +0200
@@ -8,17 +8,17 @@
 {
 	struct mail_namespace *old_ns, *new_ns;
 	struct mailbox *old_box, *new_box;
-	const char *oldname, *newname, *storage_oldname, *storage_newname;
+	const char *oldname, *newname;
 	unsigned int oldlen;
 
 	/* <old name> <new name> */
 	if (!client_read_string_args(cmd, 2, &oldname, &newname))
 		return FALSE;
 
-	old_ns = client_find_namespace(cmd, oldname, &storage_oldname);
+	old_ns = client_find_namespace(cmd, &oldname);
 	if (old_ns == NULL)
 		return TRUE;
-	new_ns = client_find_namespace(cmd, newname, &storage_newname);
+	new_ns = client_find_namespace(cmd, &newname);
 	if (new_ns == NULL)
 		return TRUE;
 
@@ -26,17 +26,17 @@
 		/* disallow box -> box/child, because it may break clients and
 		   there's really no point in doing it anyway. */
 		old_ns = mailbox_list_get_namespace(old_ns->list);
-		oldlen = strlen(storage_oldname);
-		if (strncmp(storage_oldname, storage_newname, oldlen) == 0 &&
-		    storage_newname[oldlen] == old_ns->real_sep) {
+		oldlen = strlen(oldname);
+		if (strncmp(oldname, newname, oldlen) == 0 &&
+		    newname[oldlen] == mail_namespace_get_sep(old_ns)) {
 			client_send_tagline(cmd,
 				"NO Can't rename mailbox under its own child.");
 			return TRUE;
 		}
 	}
 
-	old_box = mailbox_alloc(old_ns->list, storage_oldname, 0);
-	new_box = mailbox_alloc(new_ns->list, storage_newname, 0);
+	old_box = mailbox_alloc(old_ns->list, oldname, 0);
+	new_box = mailbox_alloc(new_ns->list, newname, 0);
 	if (mailbox_rename(old_box, new_box, TRUE) < 0)
 		client_send_storage_error(cmd, mailbox_get_storage(old_box));
 	else
--- a/src/imap/cmd-select.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/imap/cmd-select.c	Thu Jan 20 20:59:07 2011 +0200
@@ -373,7 +373,7 @@
 	struct client *client = cmd->client;
 	struct imap_select_context *ctx;
 	const struct imap_arg *args, *list_args;
-	const char *mailbox, *storage_name;
+	const char *mailbox;
 	int ret;
 
 	/* <mailbox> [(optional parameters)] */
@@ -388,7 +388,7 @@
 
 	ctx = p_new(cmd->pool, struct imap_select_context, 1);
 	ctx->cmd = cmd;
-	ctx->ns = client_find_namespace(cmd, mailbox, &storage_name);
+	ctx->ns = client_find_namespace(cmd, &mailbox);
 	if (ctx->ns == NULL) {
 		close_selected_mailbox(client);
 		return TRUE;
@@ -413,7 +413,7 @@
 		(void)client_enable(client, MAILBOX_FEATURE_CONDSTORE);
 	}
 
-	ret = select_open(ctx, storage_name, readonly);
+	ret = select_open(ctx, mailbox, readonly);
 	if (ret == 0)
 		return FALSE;
 	cmd_select_finish(ctx, ret);
--- a/src/imap/cmd-status.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/imap/cmd-status.c	Thu Jan 20 20:59:07 2011 +0200
@@ -13,7 +13,7 @@
 	struct imap_status_items items;
 	struct imap_status_result result;
 	struct mail_namespace *ns;
-	const char *mailbox, *storage_name, *error;
+	const char *mailbox, *error;
 	bool selected_mailbox;
 
 	/* <mailbox> <status items> */
@@ -30,13 +30,13 @@
 	if (imap_status_parse_items(cmd, list_args, &items) < 0)
 		return TRUE;
 
-	ns = client_find_namespace(cmd, mailbox, &storage_name);
+	ns = client_find_namespace(cmd, &mailbox);
 	if (ns == NULL)
 		return TRUE;
 
 	selected_mailbox = client->mailbox != NULL &&
-		mailbox_equals(client->mailbox, ns, storage_name);
-	if (imap_status_get(cmd, ns, storage_name, &items,
+		mailbox_equals(client->mailbox, ns, mailbox);
+	if (imap_status_get(cmd, ns, mailbox, &items,
 			    &result, &error) < 0) {
 		client_send_tagline(cmd, error);
 		return TRUE;
--- a/src/imap/cmd-subscribe.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/imap/cmd-subscribe.c	Thu Jan 20 20:59:07 2011 +0200
@@ -4,58 +4,19 @@
 #include "imap-commands.h"
 #include "mail-namespace.h"
 
-static bool have_listable_namespace_prefix(struct mail_namespace *ns,
-					   const char *name)
+static bool
+subscribe_is_valid_name(struct client_command_context *cmd, struct mailbox *box)
 {
-	unsigned int name_len = strlen(name);
-
-	for (; ns != NULL; ns = ns->next) {
-		if ((ns->flags & (NAMESPACE_FLAG_LIST_PREFIX |
-				  NAMESPACE_FLAG_LIST_CHILDREN)) == 0)
-			continue;
-
-		if (ns->prefix_len <= name_len)
-			continue;
-
-		/* if prefix has multiple hierarchies, allow subscribing to
-		   any of the hierarchies */
-		if (strncmp(ns->prefix, name, name_len) == 0 &&
-		    ns->prefix[name_len] == ns->sep)
-			return TRUE;
-	}
-	return FALSE;
-}
-
-static bool
-subscribe_is_valid_name(struct client_command_context *cmd, const char *mailbox)
-{
-	struct mail_namespace *ns;
-	struct mailbox *box;
-	const char *storage_name;
 	int ret;
 
-	if (have_listable_namespace_prefix(cmd->client->user->namespaces,
-					   mailbox)) {
-		/* subscribing to a listable namespace prefix, allow it. */
-		return TRUE;
-	}
-
-	/* see if the mailbox exists */
-	ns = client_find_namespace(cmd, mailbox, &storage_name);
-	if (ns == NULL)
-		return FALSE;
-
-	box = mailbox_alloc(ns->list, storage_name, 0);
 	if ((ret = mailbox_exists(box)) < 0) {
 		client_send_storage_error(cmd, mailbox_get_storage(box));
-		mailbox_free(&box);
 		return FALSE;
 	}
-	mailbox_free(&box);
-
 	if (ret == 0) {
 		client_send_tagline(cmd, t_strdup_printf(
-			"NO "MAIL_ERRSTR_MAILBOX_NOT_FOUND, mailbox));
+			"NO "MAIL_ERRSTR_MAILBOX_NOT_FOUND,
+			mailbox_get_vname(box)));
 		return FALSE;
 	}
 	return TRUE;
@@ -63,71 +24,46 @@
 
 bool cmd_subscribe_full(struct client_command_context *cmd, bool subscribe)
 {
-	struct mail_namespace *ns, *box_ns;
-	const char *mailbox, *storage_name, *subs_name, *subs_name2 = NULL;
+	struct mail_namespace *ns;
+	struct mailbox *box, *box2;
+	const char *mailbox, *orig_mailbox;
 	bool unsubscribed_mailbox2;
 
 	/* <mailbox> */
 	if (!client_read_string_args(cmd, 1, &mailbox))
 		return FALSE;
-
-	box_ns = client_find_namespace(cmd, mailbox, &storage_name);
-	if (box_ns == NULL)
-		return TRUE;
-	if (!mailbox_list_is_valid_existing_name(box_ns->list, storage_name)) {
-		client_send_tagline(cmd, "NO [CANNOT] Invalid mailbox name");
-		return TRUE;
-	}
+	orig_mailbox = mailbox;
 
-	/* now find a namespace where the subscription can be added to */
-	subs_name = mailbox;
-	ns = mail_namespace_find_subscribable(cmd->client->user->namespaces,
-					      &subs_name);
-	if (ns == NULL) {
-		client_send_tagline(cmd, "NO Unknown subscription namespace.");
+	ns = client_find_namespace(cmd, &mailbox);
+	if (ns == NULL)
 		return TRUE;
-	}
 
-	if (ns != box_ns) {
-		/* subscription is being written to a different namespace
-		   than where the mailbox exists. */
-		subs_name = t_strconcat(box_ns->prefix, storage_name, NULL);
-		/* drop the common prefix */
-		i_assert(strncmp(ns->prefix, subs_name, strlen(ns->prefix)) == 0);
-		subs_name += strlen(ns->prefix);
-	}
-
-	if ((cmd->client->set->parsed_workarounds &
-	     WORKAROUND_TB_EXTRA_MAILBOX_SEP) != 0 &&
-	    *subs_name != '\0' &&
-	    subs_name[strlen(subs_name)-1] == ns->real_sep) {
-		/* verify the validity without the trailing '/' */
-		mailbox = t_strndup(mailbox, strlen(mailbox)-1);
-		subs_name2 = subs_name;
-		subs_name = t_strndup(subs_name, strlen(subs_name)-1);
-	}
-
+	box = mailbox_alloc(ns->list, mailbox, 0);
 	if (subscribe) {
-		if (!subscribe_is_valid_name(cmd, mailbox))
+		if (!subscribe_is_valid_name(cmd, box)) {
+			mailbox_free(&box);
 			return TRUE;
+		}
 	}
 
 	unsubscribed_mailbox2 = FALSE;
-	if (!subscribe && subs_name2 != NULL) {
+	if (!subscribe && mailbox != orig_mailbox) {
 		/* try to unsubscribe both "box" and "box/" */
-		if (mailbox_list_set_subscribed(ns->list, subs_name2,
-						FALSE) == 0)
+		box2 = mailbox_alloc(ns->list, orig_mailbox, 0);
+		if (mailbox_set_subscribed(box2, FALSE) == 0)
 			unsubscribed_mailbox2 = TRUE;
+		mailbox_free(&box2);
 	}
 
-	if (mailbox_list_set_subscribed(ns->list, subs_name, subscribe) < 0 &&
+	if (mailbox_set_subscribed(box, subscribe) < 0 &&
 	    !unsubscribed_mailbox2) {
-		client_send_list_error(cmd, ns->list);
+		client_send_storage_error(cmd, mailbox_get_storage(box));
 	} else {
 		client_send_tagline(cmd, subscribe ?
 				    "OK Subscribe completed." :
 				    "OK Unsubscribe completed.");
 	}
+	mailbox_free(&box);
 	return TRUE;
 }
 
--- a/src/imap/imap-commands-util.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/imap/imap-commands-util.c	Thu Jan 20 20:59:07 2011 +0200
@@ -14,16 +14,13 @@
 #include "imap-commands-util.h"
 
 struct mail_namespace *
-client_find_namespace(struct client_command_context *cmd, const char *mailbox,
-		      const char **storage_name_r)
+client_find_namespace(struct client_command_context *cmd, const char **mailbox)
 {
 	struct mail_namespace *namespaces = cmd->client->user->namespaces;
 	struct mail_namespace *ns;
-	const char *storage_name, *p;
-	unsigned int storage_name_len;
+	unsigned int name_len;
 
-	storage_name = mailbox;
-	ns = mail_namespace_find(namespaces, &storage_name);
+	ns = mail_namespace_find(namespaces, *mailbox);
 	if (ns == NULL) {
 		client_send_tagline(cmd, t_strdup_printf(
 			"NO Client tried to access nonexistent namespace. "
@@ -32,31 +29,14 @@
 		return NULL;
 	}
 
-	storage_name_len = strlen(storage_name);
+	name_len = strlen(*mailbox);
 	if ((cmd->client->set->parsed_workarounds &
 	     		WORKAROUND_TB_EXTRA_MAILBOX_SEP) != 0 &&
-	    storage_name_len > 0 &&
-	    storage_name[storage_name_len-1] == ns->real_sep) {
+	    name_len > 0 &&
+	    (*mailbox)[name_len-1] == mail_namespace_get_sep(ns)) {
 		/* drop the extra trailing hierarchy separator */
-		storage_name = t_strndup(storage_name, storage_name_len-1);
+		*mailbox = t_strndup(*mailbox, name_len-1);
 	}
-
-	if (ns->real_sep != ns->sep && ns->prefix_len < strlen(mailbox)) {
-		/* make sure there are no real separators used in the mailbox
-		   name. */
-		mailbox += ns->prefix_len;
-		for (p = mailbox; *p != '\0'; p++) {
-			if (*p == ns->real_sep) {
-				client_send_tagline(cmd, t_strdup_printf(
-					"NO Character not allowed "
-					"in mailbox name: '%c'",
-					ns->real_sep));
-				return NULL;
-			}
-		}
-	}
-
-	*storage_name_r = storage_name;
 	return ns;
 }
 
@@ -75,19 +55,19 @@
 {
 	struct mail_namespace *ns;
 	struct mailbox *box;
-	const char *storage_name, *error_string;
+	const char *error_string;
 	enum mail_error error;
 
-	ns = client_find_namespace(cmd, name, &storage_name);
+	ns = client_find_namespace(cmd, &name);
 	if (ns == NULL)
 		return -1;
 
 	if (cmd->client->mailbox != NULL &&
-	    mailbox_equals(cmd->client->mailbox, ns, storage_name)) {
+	    mailbox_equals(cmd->client->mailbox, ns, name)) {
 		*destbox_r = cmd->client->mailbox;
 		return 0;
 	}
-	box = mailbox_alloc(ns->list, storage_name,
+	box = mailbox_alloc(ns->list, name,
 			    MAILBOX_FLAG_SAVEONLY | MAILBOX_FLAG_KEEP_RECENT);
 	if (mailbox_open(box) < 0) {
 		error_string = mailbox_get_last_error(box, &error);
@@ -335,7 +315,7 @@
 	if (ns1 != ns2)
 		return FALSE;
 
-        name1 = mailbox_get_name(box1);
+        name1 = mailbox_get_vname(box1);
 	if (strcmp(name1, name2) == 0)
 		return TRUE;
 
--- a/src/imap/imap-commands-util.h	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/imap/imap-commands-util.h	Thu Jan 20 20:59:07 2011 +0200
@@ -12,8 +12,7 @@
 /* Finds namespace for given mailbox from namespaces. If namespace isn't found
    or mailbox name is invalid, sends a tagged NO reply to client. */
 struct mail_namespace *
-client_find_namespace(struct client_command_context *cmd, const char *mailbox,
-		      const char **storage_name_r);
+client_find_namespace(struct client_command_context *cmd, const char **mailbox);
 
 /* Returns TRUE if mailbox is selected. If not, sends "No mailbox selected"
    error message to client. */
--- a/src/lib-lda/mail-deliver.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/lib-lda/mail-deliver.c	Thu Jan 20 20:59:07 2011 +0200
@@ -141,14 +141,15 @@
 	*error_str_r = NULL;
 
 	name = mailbox_name_to_mutf7(name);
-	ns = mail_namespace_find(ctx->user->namespaces, &name);
+	ns = mail_namespace_find(ctx->user->namespaces, name);
 	if (ns == NULL) {
 		*error_str_r = "Unknown namespace";
 		*error_r = MAIL_ERROR_PARAMS;
 		return -1;
 	}
 
-	if (*name == '\0' && (ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0) {
+	if (strcmp(name, ns->prefix) == 0 &&
+	    (ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0) {
 		/* delivering to a namespace prefix means we actually want to
 		   deliver to the INBOX instead */
 		name = "INBOX";
@@ -178,7 +179,7 @@
 	}
 	if (ctx->lda_mailbox_autosubscribe) {
 		/* (try to) subscribe to it */
-		(void)mailbox_list_set_subscribed(ns->list, name, TRUE);
+		(void)mailbox_set_subscribed(box, TRUE);
 	}
 
 	/* and try opening again */
--- a/src/lib-storage/index/cydir/cydir-storage.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/lib-storage/index/cydir/cydir-storage.c	Thu Jan 20 20:59:07 2011 +0200
@@ -36,7 +36,7 @@
 
 static struct mailbox *
 cydir_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
-		    const char *name, enum mailbox_flags flags)
+		    const char *vname, enum mailbox_flags flags)
 {
 	struct cydir_mailbox *mbox;
 	struct index_mailbox_context *ibox;
@@ -53,7 +53,7 @@
 	mbox->box.list = list;
 	mbox->box.mail_vfuncs = &cydir_mail_vfuncs;
 
-	index_storage_mailbox_alloc(&mbox->box, name, flags,
+	index_storage_mailbox_alloc(&mbox->box, vname, flags,
 				    CYDIR_INDEX_PREFIX);
 
 	ibox = INDEX_STORAGE_CONTEXT(&mbox->box);
--- a/src/lib-storage/index/dbox-multi/mdbox-storage-rebuild.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/lib-storage/index/dbox-multi/mdbox-storage-rebuild.c	Thu Jan 20 20:59:07 2011 +0200
@@ -495,11 +495,9 @@
 	struct mail_index_transaction *trans;
 	struct dbox_sync_rebuild_context *rebuild_ctx;
 	enum mail_error error;
-	const char *name;
 	int ret;
 
-	name = mail_namespace_get_storage_name(ns, vname);
-	box = mailbox_alloc(ns->list, name, MAILBOX_FLAG_READONLY |
+	box = mailbox_alloc(ns->list, vname, MAILBOX_FLAG_READONLY |
 			    MAILBOX_FLAG_KEEP_RECENT |
 			    MAILBOX_FLAG_IGNORE_ACLS);
 	i_assert(box->storage == &ctx->storage->storage.storage);
--- a/src/lib-storage/index/dbox-multi/mdbox-storage.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/lib-storage/index/dbox-multi/mdbox-storage.c	Thu Jan 20 20:59:07 2011 +0200
@@ -81,9 +81,9 @@
 	dbox_storage_destroy(_storage);
 }
 
-struct mailbox *
+static struct mailbox *
 mdbox_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
-		    const char *name, enum mailbox_flags flags)
+		    const char *vname, enum mailbox_flags flags)
 {
 	struct mdbox_mailbox *mbox;
 	struct index_mailbox_context *ibox;
@@ -100,7 +100,8 @@
 	mbox->box.list = list;
 	mbox->box.mail_vfuncs = &mdbox_mail_vfuncs;
 
-	index_storage_mailbox_alloc(&mbox->box, name, flags, DBOX_INDEX_PREFIX);
+	index_storage_mailbox_alloc(&mbox->box, vname,
+				    flags, DBOX_INDEX_PREFIX);
 
 	ibox = INDEX_STORAGE_CONTEXT(&mbox->box);
 	ibox->save_commit_pre = mdbox_transaction_save_commit_pre;
--- a/src/lib-storage/index/dbox-multi/mdbox-storage.h	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/lib-storage/index/dbox-multi/mdbox-storage.h	Thu Jan 20 20:59:07 2011 +0200
@@ -61,10 +61,6 @@
 
 extern struct mail_vfuncs mdbox_mail_vfuncs;
 
-struct mailbox *
-mdbox_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
-		    const char *name, enum mailbox_flags flags);
-
 int mdbox_mail_open(struct dbox_mail *mail, uoff_t *offset_r,
 		    struct dbox_file **file_r);
 
--- a/src/lib-storage/index/dbox-single/sdbox-storage.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/lib-storage/index/dbox-single/sdbox-storage.c	Thu Jan 20 20:59:07 2011 +0200
@@ -30,7 +30,7 @@
 
 static struct mailbox *
 sdbox_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
-		    const char *name, enum mailbox_flags flags)
+		    const char *vname, enum mailbox_flags flags)
 {
 	struct sdbox_mailbox *mbox;
 	struct index_mailbox_context *ibox;
@@ -47,7 +47,8 @@
 	mbox->box.list = list;
 	mbox->box.mail_vfuncs = &sdbox_mail_vfuncs;
 
-	index_storage_mailbox_alloc(&mbox->box, name, flags, DBOX_INDEX_PREFIX);
+	index_storage_mailbox_alloc(&mbox->box, vname,
+				    flags, DBOX_INDEX_PREFIX);
 
 	ibox = INDEX_STORAGE_CONTEXT(&mbox->box);
 	ibox->save_commit_pre = sdbox_transaction_save_commit_pre;
--- a/src/lib-storage/index/imapc/imapc-storage.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/lib-storage/index/imapc/imapc-storage.c	Thu Jan 20 20:59:07 2011 +0200
@@ -305,7 +305,7 @@
 
 static struct mailbox *
 imapc_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
-		    const char *name, enum mailbox_flags flags)
+		    const char *vname, enum mailbox_flags flags)
 {
 	struct imapc_mailbox *mbox;
 	struct index_mailbox_context *ibox;
@@ -321,7 +321,7 @@
 	mbox->box.list = list;
 	mbox->box.mail_vfuncs = &imapc_mail_vfuncs;
 
-	index_storage_mailbox_alloc(&mbox->box, name, flags, NULL);
+	index_storage_mailbox_alloc(&mbox->box, vname, flags, NULL);
 
 	ibox = INDEX_STORAGE_CONTEXT(&mbox->box);
 	ibox->save_commit_pre = imapc_transaction_save_commit_pre;
--- a/src/lib-storage/index/index-storage.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/lib-storage/index/index-storage.c	Thu Jan 20 20:59:07 2011 +0200
@@ -250,20 +250,17 @@
 	return 0;
 }
 
-void index_storage_mailbox_alloc(struct mailbox *box, const char *name,
+void index_storage_mailbox_alloc(struct mailbox *box, const char *vname,
 				 enum mailbox_flags flags,
 				 const char *index_prefix)
 {
 	struct index_mailbox_context *ibox;
-	string_t *vname;
 
-	i_assert(name != NULL);
+	i_assert(vname != NULL);
 
-	box->name = p_strdup(box->pool, name);
-	vname = t_str_new(128);
-	mail_namespace_get_vname(box->list->ns, vname, name);
-	box->vname = p_strdup(box->pool, str_c(vname));
-
+	box->vname = p_strdup(box->pool, vname);
+	box->name = p_strdup(box->pool,
+			     mailbox_list_get_storage_name(box->list, vname));
 	box->flags = flags;
 	box->index_prefix = p_strdup(box->pool, index_prefix);
 
@@ -277,9 +274,9 @@
 	ibox->next_lock_notify = time(NULL) + LOCK_NOTIFY_INTERVAL;
 	MODULE_CONTEXT_SET(box, index_storage_module, ibox);
 
-	box->inbox_user = strcmp(name, "INBOX") == 0 &&
+	box->inbox_user = strcmp(box->name, "INBOX") == 0 &&
 		(box->list->ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0;
-	box->inbox_any = strcmp(name, "INBOX") == 0 &&
+	box->inbox_any = strcmp(box->name, "INBOX") == 0 &&
 		(box->list->ns->flags & NAMESPACE_FLAG_INBOX_ANY) != 0;
 }
 
--- a/src/lib-storage/index/index-storage.h	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/lib-storage/index/index-storage.h	Thu Jan 20 20:59:07 2011 +0200
@@ -60,7 +60,7 @@
 			       unsigned int secs_left);
 void index_storage_lock_notify_reset(struct mailbox *box);
 
-void index_storage_mailbox_alloc(struct mailbox *box, const char *name,
+void index_storage_mailbox_alloc(struct mailbox *box, const char *vname,
 				 enum mailbox_flags flags,
 				 const char *index_prefix);
 int index_storage_mailbox_exists(struct mailbox *box);
--- a/src/lib-storage/index/maildir/maildir-storage.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/lib-storage/index/maildir/maildir-storage.c	Thu Jan 20 20:59:07 2011 +0200
@@ -263,7 +263,7 @@
 
 static struct mailbox *
 maildir_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
-		      const char *name, enum mailbox_flags flags)
+		      const char *vname, enum mailbox_flags flags)
 {
 	struct maildir_mailbox *mbox;
 	struct index_mailbox_context *ibox;
@@ -277,7 +277,7 @@
 	mbox->box.list = list;
 	mbox->box.mail_vfuncs = &maildir_mail_vfuncs;
 
-	index_storage_mailbox_alloc(&mbox->box, name, flags,
+	index_storage_mailbox_alloc(&mbox->box, vname, flags,
 				    MAILDIR_INDEX_PREFIX);
 
 	ibox = INDEX_STORAGE_CONTEXT(&mbox->box);
--- a/src/lib-storage/index/mbox/mbox-storage.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/lib-storage/index/mbox/mbox-storage.c	Thu Jan 20 20:59:07 2011 +0200
@@ -345,7 +345,7 @@
 
 static struct mailbox *
 mbox_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
-		   const char *name, enum mailbox_flags flags)
+		   const char *vname, enum mailbox_flags flags)
 {
 	struct mbox_mailbox *mbox;
 	struct index_mailbox_context *ibox;
@@ -359,7 +359,8 @@
 	mbox->box.list = list;
 	mbox->box.mail_vfuncs = &mbox_mail_vfuncs;
 
-	index_storage_mailbox_alloc(&mbox->box, name, flags, MBOX_INDEX_PREFIX);
+	index_storage_mailbox_alloc(&mbox->box, vname,
+				    flags, MBOX_INDEX_PREFIX);
 
 	ibox = INDEX_STORAGE_CONTEXT(&mbox->box);
 	ibox->save_commit_pre = mbox_transaction_save_commit_pre;
--- a/src/lib-storage/index/raw/raw-storage.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/lib-storage/index/raw/raw-storage.c	Thu Jan 20 20:59:07 2011 +0200
@@ -36,7 +36,7 @@
 
 static struct mailbox *
 raw_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
-		  const char *name, enum mailbox_flags flags)
+		  const char *vname, enum mailbox_flags flags)
 {
 	struct raw_mailbox *mbox;
 	pool_t pool;
@@ -51,7 +51,7 @@
 	mbox->box.list = list;
 	mbox->box.mail_vfuncs = &raw_mail_vfuncs;
 
-	index_storage_mailbox_alloc(&mbox->box, name, flags, NULL);
+	index_storage_mailbox_alloc(&mbox->box, vname, flags, NULL);
 
 	mbox->mtime = mbox->ctime = (time_t)-1;
 	mbox->storage = (struct raw_storage *)storage;
--- a/src/lib-storage/index/shared/shared-list.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/lib-storage/index/shared/shared-list.c	Thu Jan 20 20:59:07 2011 +0200
@@ -43,12 +43,13 @@
 }
 
 static int
-shared_get_storage(struct mailbox_list **list, const char **name,
+shared_get_storage(struct mailbox_list **list, const char *vname,
 		   struct mail_storage **storage_r)
 {
 	struct mail_namespace *ns = (*list)->ns;
+	const char *name = vname;
 
-	if (shared_storage_get_namespace(&ns, name) < 0)
+	if (shared_storage_get_namespace(&ns, &name) < 0)
 		return -1;
 	*list = ns->list;
 	*storage_r = ns->storage;
@@ -85,6 +86,11 @@
 	return mailbox_list_is_valid_create_name(ns->list, name);
 }
 
+static char shared_list_get_hierarchy_sep(struct mailbox_list *list ATTR_UNUSED)
+{
+	return '/';
+}
+
 static const char *
 shared_list_get_path(struct mailbox_list *list, const char *name,
 		     enum mailbox_list_path_type type)
@@ -145,6 +151,7 @@
 		      enum mailbox_list_iter_flags flags)
 {
 	struct shared_mailbox_list_iterate_context *ctx;
+	char sep = mail_namespace_get_sep(list->ns);
 
 	ctx = i_new(struct shared_mailbox_list_iterate_context, 1);
 	ctx->ctx.list = list;
@@ -153,7 +160,7 @@
 	ctx->info.ns = list->ns;
 	ctx->info.flags = MAILBOX_NONEXISTENT;
 	ctx->glob = imap_match_init_multiple(default_pool, patterns,
-					     FALSE, list->ns->sep);
+					     FALSE, sep);
 	return &ctx->ctx;
 }
 
@@ -299,7 +306,6 @@
 
 struct mailbox_list shared_mailbox_list = {
 	.name = "shared",
-	.hierarchy_sep = '/',
 	.props = 0,
 	.mailbox_name_max_length = MAILBOX_LIST_NAME_MAX_LENGTH,
 
@@ -310,6 +316,9 @@
 		shared_is_valid_pattern,
 		shared_is_valid_existing_name,
 		shared_is_valid_create_name,
+		shared_list_get_hierarchy_sep,
+		mailbox_list_default_get_vname,
+		mailbox_list_default_get_storage_name,
 		shared_list_get_path,
 		shared_list_get_temp_prefix,
 		shared_list_join_refpattern,
--- a/src/lib-storage/index/shared/shared-storage.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/lib-storage/index/shared/shared-storage.c	Thu Jan 20 20:59:07 2011 +0200
@@ -130,6 +130,7 @@
 	const char *domain = NULL, *username = NULL, *userdomain = NULL;
 	const char *name, *p, *next, **dest, *error;
 	string_t *prefix, *location;
+	char ns_sep = mail_namespace_get_sep(ns);
 	int ret;
 
 	p = storage->ns_prefix_pattern;
@@ -156,7 +157,7 @@
 		}
 		p++;
 
-		next = strchr(name, *p != '\0' ? *p : ns->sep);
+		next = strchr(name, *p != '\0' ? *p : ns_sep);
 		if (next == NULL) {
 			*dest = name;
 			name = "";
@@ -167,7 +168,7 @@
 	}
 	if (*p != '\0') {
 		if (*name == '\0' ||
-		    (name[1] == '\0' && *name == ns->sep)) {
+		    (name[1] == '\0' && *name == ns_sep)) {
 			/* trying to open <prefix>/<user> mailbox */
 			name = "INBOX";
 		} else {
@@ -223,7 +224,8 @@
 
 	*_ns = mail_namespace_find_prefix(user->namespaces, str_c(prefix));
 	if (*_ns != NULL) {
-		*_name = mail_namespace_fix_sep(ns, name);
+		*_name = mailbox_list_get_storage_name(ns->list,
+				t_strconcat(ns->prefix, name, NULL));
 		return 0;
 	}
 
@@ -259,7 +261,6 @@
 	new_ns->flags = (NAMESPACE_FLAG_SUBSCRIPTIONS & ns->flags) |
 		NAMESPACE_FLAG_LIST_PREFIX | NAMESPACE_FLAG_HIDDEN |
 		NAMESPACE_FLAG_AUTOCREATED | NAMESPACE_FLAG_INBOX_ANY;
-	new_ns->sep = ns->sep;
 	new_ns->mail_set = _storage->set;
 
 	location = t_str_new(256);
@@ -276,7 +277,7 @@
 
 	ns_set = p_new(user->pool, struct mail_namespace_settings, 1);
 	ns_set->type = "shared";
-	ns_set->separator = p_strdup_printf(user->pool, "%c", new_ns->sep);
+	ns_set->separator = p_strdup_printf(user->pool, "%c", ns_sep);
 	ns_set->prefix = new_ns->prefix;
 	ns_set->location = p_strdup(user->pool, str_c(location));
 	ns_set->hidden = TRUE;
@@ -298,7 +299,8 @@
 		return -1;
 	}
 	ns->flags |= NAMESPACE_FLAG_USABLE;
-	*_name = mail_namespace_fix_sep(new_ns, name);
+	*_name = mailbox_list_get_storage_name(new_ns->list,
+				t_strconcat(new_ns->prefix, name, NULL));
 	*_ns = new_ns;
 
 	mail_user_add_namespace(user, &new_ns);
--- a/src/lib-storage/list/index-mailbox-list.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/lib-storage/list/index-mailbox-list.c	Thu Jan 20 20:59:07 2011 +0200
@@ -100,7 +100,7 @@
 static void pattern_parse(struct mailbox_list *list, const char *pattern,
 			  const char **prefix_r, int *recurse_level_r)
 {
-	char sep = list->hierarchy_sep;
+	char sep = mailbox_list_get_hierarchy_sep(list);
 	const char *prefix_start, *prefix_end;
 	bool seen_wildcards = FALSE;
 	int recurse_level = 0;
@@ -188,6 +188,7 @@
 	const char *prefix, *cur_prefix, *const *tmp;
 	enum mailbox_list_iter_flags subs_flags;
 	int cur_recurse_level;
+	char sep;
 
 	subs_flags = MAILBOX_LIST_ITER_SELECT_SUBSCRIBED |
 		MAILBOX_LIST_ITER_RETURN_NO_FLAGS;
@@ -198,12 +199,12 @@
 		return FALSE;
 	}
 
-	ctx->glob = imap_match_init_multiple(default_pool, patterns, TRUE,
-					     list->hierarchy_sep);
+	sep = mailbox_list_get_hierarchy_sep(list);
+	ctx->glob = imap_match_init_multiple(default_pool, patterns, TRUE, sep);
 	if ((flags & (MAILBOX_LIST_ITER_SELECT_SUBSCRIBED |
 		      MAILBOX_LIST_ITER_RETURN_SUBSCRIBED)) != 0) {
 		/* we'll need to know the subscriptions */
-		ctx->subs_tree = mailbox_tree_init(list->hierarchy_sep);
+		ctx->subs_tree = mailbox_tree_init(sep);
 		if (mailbox_list_subscriptions_fill(&ctx->ctx, ctx->subs_tree,
 						    ctx->glob, FALSE) < 0) {
 			/* let the backend handle this failure */
@@ -261,8 +262,7 @@
 			mailbox_list_index_iterate_init(ctx->view, prefix,
 							ctx->recurse_level);
 		ctx->prefix = *prefix == '\0' ? i_strdup(ctx->ns_prefix) :
-			i_strdup_printf("%s%s%c", ctx->ns_prefix, prefix,
-					list->hierarchy_sep);
+			i_strdup_printf("%s%s%c", ctx->ns_prefix, prefix, sep);
 	}
 	return TRUE;
 }
@@ -457,6 +457,7 @@
 	struct index_mailbox_list *ilist = INDEX_LIST_CONTEXT(list);
 	const char *path;
 	enum mail_index_open_flags index_flags = 0;
+	char sep;
 	int ret;
 
 	index_flags = mail_storage_settings_to_index_flags(list->mail_set);
@@ -479,7 +480,8 @@
 	}
 
 	path = t_strconcat(dir, "/"MAILBOX_LIST_INDEX_NAME, NULL);
-	ilist->list_index = mailbox_list_index_alloc(path, list->hierarchy_sep,
+	sep = mailbox_list_get_hierarchy_sep(list);
+	ilist->list_index = mailbox_list_index_alloc(path, sep,
 						     ilist->mail_index);
 	if (mailbox_list_index_open_or_create(ilist->list_index) < 0) {
 		/* skip indexing */
--- a/src/lib-storage/list/mailbox-list-fs-iter.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/lib-storage/list/mailbox-list-fs-iter.c	Thu Jan 20 20:59:07 2011 +0200
@@ -223,7 +223,7 @@
 	ctx->ctx.flags = flags;
 	ctx->info_pool = pool_alloconly_create("fs list", 1024);
 	ctx->next = fs_list_next;
-	ctx->sep = _list->ns->sep;
+	ctx->sep = mail_namespace_get_sep(_list->ns);
 	ctx->info.ns = _list->ns;
 
 	prefix_len = strlen(_list->ns->prefix);
@@ -238,7 +238,8 @@
 			test_pattern += prefix_len;
 		/* check pattern also when it's converted to use real
 		   separators. */
-		real_pattern = mail_namespace_fix_sep(_list->ns, test_pattern);
+		real_pattern =
+			mailbox_list_get_storage_name(_list, test_pattern);
 		if (mailbox_list_is_valid_pattern(_list, test_pattern) &&
 		    mailbox_list_is_valid_pattern(_list, real_pattern)) {
 			if (strcasecmp(*patterns, "INBOX") == 0) {
@@ -649,7 +650,7 @@
 	struct mailbox_node *node;
 	enum mailbox_info_flags flags;
 	struct mail_namespace *ns;
-	const char *path, *dir, *fname, *storage_name;
+	const char *path, *dir, *fname, *subs_name, *storage_name;
 	unsigned int len;
 	struct stat st;
 
@@ -667,19 +668,18 @@
 	}
 
 	/* see if this is for another subscriptions=no namespace */
-	storage_name = ctx->info.name;
+	subs_name = ctx->info.name;
 	ns = mail_namespace_find_unsubscribable(ctx->info.ns->user->namespaces,
-						&storage_name);
-	if (ns == NULL) {
+						subs_name);
+	if (ns == NULL)
 		ns = ctx->info.ns;
-		storage_name = mail_namespace_get_storage_name(ns, storage_name);
-	}
 
 	/* if name ends with hierarchy separator, drop the separator */
-	len = strlen(storage_name);
-	if (len > 0 && storage_name[len-1] == ns->real_sep)
-		storage_name = t_strndup(storage_name, len-1);
+	len = strlen(subs_name);
+	if (len > 0 && subs_name[len-1] == mail_namespace_get_sep(ns))
+		subs_name = t_strndup(subs_name, len-1);
 
+	storage_name = mailbox_list_get_storage_name(ns->list, subs_name);
 	if (!mailbox_list_is_valid_pattern(ns->list, storage_name)) {
 		/* broken entry in subscriptions file */
 		ctx->info.flags = MAILBOX_NONEXISTENT;
--- a/src/lib-storage/list/mailbox-list-fs.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/lib-storage/list/mailbox-list-fs.c	Thu Jan 20 20:59:07 2011 +0200
@@ -135,6 +135,11 @@
 	return fs_list_is_valid_common_nonfs(list, name);
 }
 
+static char fs_list_get_hierarchy_sep(struct mailbox_list *list ATTR_UNUSED)
+{
+	return '/';
+}
+
 static const char *
 fs_list_get_path(struct mailbox_list *_list, const char *name,
 		 enum mailbox_list_path_type type)
@@ -368,6 +373,7 @@
 static int fs_list_delete_dir(struct mailbox_list *list, const char *name)
 {
 	const char *path, *child_name, *child_path, *p;
+	char sep;
 
 	path = mailbox_list_get_path(list, name, MAILBOX_LIST_PATH_TYPE_DIR);
 	if (fs_list_rmdir(list, name, path) == 0)
@@ -379,8 +385,8 @@
 	} else if (errno == ENOTEMPTY || errno == EEXIST) {
 		/* mbox workaround: if only .imap/ directory is preventing the
 		   deletion, remove it */
-		child_name = t_strdup_printf("%s%cchild", name,
-					     list->ns->real_sep);
+		sep = mailbox_list_get_hierarchy_sep(list);
+		child_name = t_strdup_printf("%s%cchild", name, sep);
 		child_path = mailbox_list_get_path(list, child_name,
 						   MAILBOX_LIST_PATH_TYPE_INDEX);
 		if (strncmp(path, child_path, strlen(path)) == 0) {
@@ -438,7 +444,7 @@
 				  const char *newname, bool rename_children)
 {
 	struct mail_storage *oldstorage;
-	const char *oldpath, *newpath, *alt_newpath, *root_path;
+	const char *oldvname, *oldpath, *newpath, *alt_newpath, *root_path;
 	const char *p, *origin;
 	enum mailbox_list_path_type path_type, alt_path_type;
 	struct stat st;
@@ -446,7 +452,8 @@
 	gid_t gid;
 	bool rmdir_parent = FALSE;
 
-	if (mailbox_list_get_storage(&oldlist, &oldname, &oldstorage) < 0)
+	oldvname = mailbox_list_get_vname(oldlist, oldname);
+	if (mailbox_list_get_storage(&oldlist, oldvname, &oldstorage) < 0)
 		return -1;
 
 	if (rename_children) {
@@ -564,7 +571,6 @@
 
 struct mailbox_list fs_mailbox_list = {
 	.name = MAILBOX_LIST_NAME_FS,
-	.hierarchy_sep = '/',
 	.props = 0,
 	.mailbox_name_max_length = MAILBOX_LIST_NAME_MAX_LENGTH,
 
@@ -575,6 +581,9 @@
 		fs_is_valid_pattern,
 		fs_is_valid_existing_name,
 		fs_is_valid_create_name,
+		fs_list_get_hierarchy_sep,
+		mailbox_list_default_get_vname,
+		mailbox_list_default_get_storage_name,
 		fs_list_get_path,
 		fs_list_get_temp_prefix,
 		fs_list_join_refpattern,
--- a/src/lib-storage/list/mailbox-list-maildir-iter.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/lib-storage/list/mailbox-list-maildir-iter.c	Thu Jan 20 20:59:07 2011 +0200
@@ -43,31 +43,30 @@
 static void
 maildir_fill_parents(struct maildir_list_iterate_context *ctx,
 		     struct imap_match_glob *glob, bool update_only,
-		     string_t *mailbox)
+		     const char *vname)
 {
 	struct mail_namespace *ns = ctx->ctx.list->ns;
 	struct mailbox_node *node;
-	const char *p, *mailbox_c;
-	bool created;
+	const char *p;
+	unsigned int vname_len = strlen(vname);
+	bool created, ns_sep = mail_namespace_get_sep(ns);
 
-	mailbox_c = str_c(mailbox);
-	while ((p = strrchr(mailbox_c, ns->sep)) != NULL) {
-		str_truncate(mailbox, (size_t) (p-mailbox_c));
-		mailbox_c = str_c(mailbox);
-		if (imap_match(glob, mailbox_c) != IMAP_MATCH_YES)
+	while ((p = strrchr(vname, ns_sep)) != NULL) {
+		vname = t_strdup_until(vname, p);
+		if (imap_match(glob, vname) != IMAP_MATCH_YES)
 			continue;
 
-		if (ns->prefix_len > 0 && str_len(mailbox) == ns->prefix_len-1 &&
-		    strncmp(mailbox_c, ns->prefix, ns->prefix_len - 1) == 0 &&
-		    mailbox_c[ns->prefix_len-1] == ns->sep) {
+		if (ns->prefix_len > 0 && vname_len == ns->prefix_len-1 &&
+		    strncmp(vname, ns->prefix, ns->prefix_len - 1) == 0 &&
+		    vname[ns->prefix_len-1] == ns_sep) {
 			/* don't return matches to namespace prefix itself */
 			continue;
 		}
 
 		created = FALSE;
 		node = update_only ?
-			mailbox_tree_lookup(ctx->tree_ctx, mailbox_c) :
-			mailbox_tree_get(ctx->tree_ctx, mailbox_c, &created);
+			mailbox_tree_lookup(ctx->tree_ctx, vname) :
+			mailbox_tree_get(ctx->tree_ctx, vname, &created);
 		if (node != NULL) {
 			if (created) {
 				/* we haven't yet seen this mailbox,
@@ -84,21 +83,19 @@
 }
 
 static void maildir_set_children(struct maildir_list_iterate_context *ctx,
-				 string_t *mailbox)
+				 const char *vname)
 {
 	struct mailbox_node *node;
-	const char *p, *mailbox_c;
+	const char *p;
 	char hierarchy_sep;
 
-	hierarchy_sep = ctx->ctx.list->ns->sep;
+	hierarchy_sep = mail_namespace_get_sep(ctx->ctx.list->ns);
 
 	/* mark the first existing parent as containing children */
-	mailbox_c = str_c(mailbox);
-	while ((p = strrchr(mailbox_c, hierarchy_sep)) != NULL) {
-		str_truncate(mailbox, (size_t) (p-mailbox_c));
-		mailbox_c = str_c(mailbox);
+	while ((p = strrchr(vname, hierarchy_sep)) != NULL) {
+		vname = t_strdup_until(vname, p);
 
-		node = mailbox_tree_lookup(ctx->tree_ctx, mailbox_c);
+		node = mailbox_tree_lookup(ctx->tree_ctx, vname);
 		if (node != NULL) {
 			node->flags &= ~MAILBOX_NOCHILDREN;
 			node->flags |= MAILBOX_CHILDREN;
@@ -263,6 +260,81 @@
 }
 
 static int
+maildir_fill_readdir_entry(struct maildir_list_iterate_context *ctx,
+			   struct imap_match_glob *glob, const struct dirent *d,
+			   bool update_only)
+{
+	struct mailbox_list *list = ctx->ctx.list;
+	const char *fname, *storage_name, *vname;
+	enum mailbox_info_flags flags;
+	enum imap_match_result match;
+	struct mailbox_node *node;
+	bool created;
+	struct stat st;
+	int ret;
+
+	fname = d->d_name;
+	if (fname[0] == ctx->prefix_char)
+		storage_name = fname + 1;
+	else {
+		if (ctx->prefix_char != '\0' || fname[0] == '.')
+			return 0;
+		storage_name = fname;
+	}
+
+	/* skip . and .. */
+	if (fname[0] == '.' &&
+	    (fname[1] == '\0' || (fname[1] == '.' && fname[2] == '\0')))
+		return 0;
+
+	vname = mailbox_list_get_vname(list, storage_name);
+
+	/* make sure the pattern matches */
+	match = imap_match(glob, vname);
+	if ((match & (IMAP_MATCH_YES | IMAP_MATCH_PARENT)) == 0)
+		return 0;
+
+	/* check if this is an actual mailbox */
+	if (maildir_delete_trash_dir(ctx, fname))
+		return 0;
+
+	T_BEGIN {
+		ret = list->v.get_mailbox_flags(list, ctx->dir, fname,
+				mailbox_list_get_file_type(d), &st, &flags);
+	} T_END;
+	if (ret <= 0)
+		return ret;
+
+	/* we know the children flags ourself, so ignore if any of
+	   them were set. */
+	flags &= ~(MAILBOX_NOINFERIORS | MAILBOX_CHILDREN | MAILBOX_NOCHILDREN);
+
+	if ((match & IMAP_MATCH_PARENT) != 0)
+		maildir_fill_parents(ctx, glob, update_only, vname);
+	else {
+		created = FALSE;
+		node = update_only ?
+			mailbox_tree_lookup(ctx->tree_ctx, vname) :
+			mailbox_tree_get(ctx->tree_ctx, vname, &created);
+
+		if (node != NULL) {
+			if (created)
+				node->flags = MAILBOX_NOCHILDREN;
+			else
+				node->flags &= ~MAILBOX_NONEXISTENT;
+			if (!update_only)
+				node->flags |= MAILBOX_MATCHED;
+			node->flags |= flags;
+			node_fix_parents(node);
+		} else {
+			i_assert(update_only);
+			maildir_set_children(ctx, vname);
+		}
+	}
+	return 0;
+}
+
+static int
 maildir_fill_readdir(struct maildir_list_iterate_context *ctx,
 		     struct imap_match_glob *glob, bool update_only)
 {
@@ -270,14 +342,7 @@
 	struct mail_namespace *ns = list->ns;
 	DIR *dirp;
 	struct dirent *d;
-	const char *mailbox_name;
-	string_t *mailbox;
-	enum mailbox_info_flags flags;
-	enum imap_match_result match;
-	struct mailbox_node *node;
-	bool created;
-	struct stat st;
-	int ret;
+	int ret = 0;
 
 	dirp = opendir(ctx->dir);
 	if (dirp == NULL) {
@@ -292,77 +357,13 @@
 		return 0;
 	}
 
-	mailbox = t_str_new(MAILBOX_LIST_NAME_MAX_LENGTH);
 	while ((d = readdir(dirp)) != NULL) {
-		const char *fname = d->d_name;
-
-		if (fname[0] == ctx->prefix_char)
-			mailbox_name = fname + 1;
-		else {
-			if (ctx->prefix_char != '\0' || fname[0] == '.')
-				continue;
-			mailbox_name = fname;
-		}
-
-		/* skip . and .. */
-		if (fname[0] == '.' &&
-		    (fname[1] == '\0' || (fname[1] == '.' && fname[2] == '\0')))
-			continue;
-
-		mailbox_name = mail_namespace_get_vname(ns, mailbox,
-							mailbox_name);
-
-		/* make sure the pattern matches */
-		match = imap_match(glob, mailbox_name);
-		if ((match & (IMAP_MATCH_YES | IMAP_MATCH_PARENT)) == 0)
-			continue;
-
-		/* check if this is an actual mailbox */
-		if (maildir_delete_trash_dir(ctx, fname))
-			continue;
-
 		T_BEGIN {
-			ret = list->v.get_mailbox_flags(list, ctx->dir, fname,
-				mailbox_list_get_file_type(d), &st, &flags);
+			ret = maildir_fill_readdir_entry(ctx, glob, d,
+							 update_only);
 		} T_END;
-		if (ret <= 0) {
-			if (ret < 0)
-				return -1;
-			continue;
-		}
-
-		/* we know the children flags ourself, so ignore if any of
-		   them were set. */
-		flags &= ~(MAILBOX_NOINFERIORS |
-			   MAILBOX_CHILDREN | MAILBOX_NOCHILDREN);
-
-		if ((match & IMAP_MATCH_PARENT) != 0) {
-			T_BEGIN {
-				maildir_fill_parents(ctx, glob, update_only,
-						     mailbox);
-			} T_END;
-		} else {
-			created = FALSE;
-			node = update_only ?
-				mailbox_tree_lookup(ctx->tree_ctx,
-						    mailbox_name) :
-				mailbox_tree_get(ctx->tree_ctx,
-						 mailbox_name, &created);
-
-			if (node != NULL) {
-				if (created)
-					node->flags = MAILBOX_NOCHILDREN;
-				else
-					node->flags &= ~MAILBOX_NONEXISTENT;
-				if (!update_only)
-					node->flags |= MAILBOX_MATCHED;
-				node->flags |= flags;
-				node_fix_parents(node);
-			} else {
-				i_assert(update_only);
-				maildir_set_children(ctx, mailbox);
-			}
-		}
+		if (ret < 0)
+			break;
 	}
 
 	if (closedir(dirp) < 0) {
@@ -370,6 +371,8 @@
 					  ctx->dir);
 		return -1;
 	}
+	if (ret < 0)
+		return -1;
 
 	if ((ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0) {
 		/* make sure INBOX is listed */
@@ -436,9 +439,12 @@
 maildir_list_iter_init(struct mailbox_list *_list, const char *const *patterns,
 		       enum mailbox_list_iter_flags flags)
 {
+	struct maildir_mailbox_list *list =
+		(struct maildir_mailbox_list *)_list;
 	struct maildir_list_iterate_context *ctx;
         struct imap_match_glob *glob;
 	pool_t pool;
+	char ns_sep = mail_namespace_get_sep(_list->ns);
 	int ret;
 
 	pool = pool_alloconly_create("maildir_list", 1024);
@@ -446,12 +452,12 @@
 	ctx->ctx.list = _list;
 	ctx->ctx.flags = flags;
 	ctx->pool = pool;
-	ctx->tree_ctx = mailbox_tree_init(_list->ns->sep);
+	ctx->tree_ctx = mailbox_tree_init(ns_sep);
 	ctx->info.ns = _list->ns;
 	ctx->prefix_char = strcmp(_list->name, MAILBOX_LIST_NAME_IMAPDIR) == 0 ?
-		'\0' : _list->hierarchy_sep;
+		'\0' : list->sep;
 
-	glob = imap_match_init_multiple(pool, patterns, TRUE, _list->ns->sep);
+	glob = imap_match_init_multiple(pool, patterns, TRUE, ns_sep);
 
 	ctx->dir = _list->set.root_dir;
 
--- a/src/lib-storage/list/mailbox-list-maildir.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/lib-storage/list/mailbox-list-maildir.c	Thu Jan 20 20:59:07 2011 +0200
@@ -29,6 +29,7 @@
 	list = p_new(pool, struct maildir_mailbox_list, 1);
 	list->list = maildir_mailbox_list;
 	list->list.pool = pool;
+	list->sep = '.';
 
 	list->global_temp_prefix = MAILDIR_GLOBAL_TEMP_PREFIX;
 	list->temp_prefix = p_strconcat(pool, list->global_temp_prefix,
@@ -69,7 +70,8 @@
 	else if (list->name == imapdir_mailbox_list.name)
 		return t_strdup_printf("%s/%s", dir, name);
 
-	return t_strdup_printf("%s/%c%s", dir, list->hierarchy_sep, name);
+	return t_strdup_printf("%s/%c%s", dir,
+			       mailbox_list_get_hierarchy_sep(list), name);
 }
 
 static const char *
@@ -90,23 +92,23 @@
 }
 
 static bool
-maildir_list_is_valid_common(struct mailbox_list *list, const char *name,
-			     size_t *len_r)
+maildir_list_is_valid_common(struct maildir_mailbox_list *list,
+			     const char *name, size_t *len_r)
 {
 	size_t len;
 
 	/* check that there are no adjacent hierarchy separators */
 	for (len = 0; name[len] != '\0'; len++) {
-		if (name[len] == list->hierarchy_sep &&
-		    name[len+1] == list->hierarchy_sep)
+		if (name[len] == list->sep &&
+		    name[len+1] == list->sep)
 			return FALSE;
 	}
 
 	if (len == 0 || name[len-1] == '/')
 		return FALSE;
 
-	if (name[0] == list->hierarchy_sep ||
-	    name[len-1] == list->hierarchy_sep)
+	if (name[0] == list->sep ||
+	    name[len-1] == list->sep)
 		return FALSE;
 
 	*len_r = len;
@@ -137,22 +139,26 @@
 }
 
 static bool
-maildir_is_valid_existing_name(struct mailbox_list *list, const char *name)
+maildir_is_valid_existing_name(struct mailbox_list *_list, const char *name)
 {
+	struct maildir_mailbox_list *list =
+		(struct maildir_mailbox_list *)_list;
 	size_t len;
 
 	if (!maildir_list_is_valid_common(list, name, &len))
 		return FALSE;
 
-	if (list->mail_set->mail_full_filesystem_access)
+	if (_list->mail_set->mail_full_filesystem_access)
 		return TRUE;
 
 	return maildir_list_is_valid_common_nonfs(name);
 }
 
 static bool
-maildir_is_valid_create_name(struct mailbox_list *list, const char *name)
+maildir_is_valid_create_name(struct mailbox_list *_list, const char *name)
 {
+	struct maildir_mailbox_list *list =
+		(struct maildir_mailbox_list *)_list;
 	size_t len;
 
 	if (!maildir_list_is_valid_common(list, name, &len))
@@ -160,17 +166,25 @@
 	if (len > MAILDIR_MAX_CREATE_MAILBOX_NAME_LENGTH)
 		return FALSE;
 
-	if (list->mail_set->mail_full_filesystem_access)
+	if (_list->mail_set->mail_full_filesystem_access)
 		return TRUE;
 
 	if (!maildir_list_is_valid_common_nonfs(name))
 		return FALSE;
-	if (mailbox_list_name_is_too_large(name, list->hierarchy_sep))
+	if (mailbox_list_name_is_too_large(name, list->sep))
 		return FALSE;
 
 	return TRUE;
 }
 
+static char maildir_list_get_hierarchy_sep(struct mailbox_list *_list)
+{
+	struct maildir_mailbox_list *list =
+		(struct maildir_mailbox_list *)_list;
+
+	return list->sep;
+}
+
 static const char *
 maildir_list_get_path(struct mailbox_list *_list, const char *name,
 		      enum mailbox_list_path_type type)
@@ -348,15 +362,17 @@
 		maildir_list_create_maildirfolder_file(list, path);
 }
 
-static const char *mailbox_list_maildir_get_trash_dir(struct mailbox_list *list)
+static const char *
+mailbox_list_maildir_get_trash_dir(struct mailbox_list *_list)
 {
+	struct maildir_mailbox_list *list =
+		(struct maildir_mailbox_list *)_list;
 	const char *root_dir;
 
-	root_dir = mailbox_list_get_path(list, NULL,
+	root_dir = mailbox_list_get_path(_list, NULL,
 					 MAILBOX_LIST_PATH_TYPE_DIR);
 	return t_strdup_printf("%s/%c%c"MAILBOX_LIST_MAILDIR_TRASH_DIR_NAME,
-			       root_dir, list->hierarchy_sep,
-			       list->hierarchy_sep);
+			       root_dir, list->sep, list->sep);
 }
 
 static int
@@ -448,7 +464,7 @@
 	const char *const *names, *old_vname, *new_vname;
 	unsigned int i, count, old_vnamelen;
 	pool_t pool;
-	string_t *str;
+	char old_ns_sep;
 	int ret;
 
 	ret = 0;
@@ -460,14 +476,13 @@
 	pool = pool_alloconly_create("Maildir++ children list", 1024);
 	i_array_init(&names_arr, 64);
 
-	str = t_str_new(256);
-	old_vname = t_strdup(mail_namespace_get_vname(oldlist->ns, str, oldname));
+	old_vname = mailbox_list_get_vname(oldlist, oldname);
 	old_vnamelen = strlen(oldname);
 
-	str_truncate(str, 0);
-	new_vname = t_strdup(mail_namespace_get_vname(newlist->ns, str, newname));
+	new_vname = mailbox_list_get_vname(newlist, newname);
 
-	pattern = t_strdup_printf("%s%c*", old_vname, oldlist->ns->sep);
+	old_ns_sep = mail_namespace_get_sep(oldlist->ns);
+	pattern = t_strdup_printf("%s%c*", old_vname, old_ns_sep);
 	iter = mailbox_list_iter_init(oldlist, pattern,
 				      MAILBOX_LIST_ITER_RETURN_NO_FLAGS |
 				      MAILBOX_LIST_ITER_RAW_LIST);
@@ -477,7 +492,7 @@
 		/* verify that the prefix matches, otherwise we could have
 		   problems with mailbox names containing '%' and '*' chars */
 		if (strncmp(info->name, old_vname, old_vnamelen) == 0 &&
-		    info->name[old_vnamelen] == oldlist->ns->sep) {
+		    info->name[old_vnamelen] == old_ns_sep) {
 			name = p_strdup(pool, info->name + old_vnamelen);
 			array_append(&names_arr, &name, 1);
 		}
@@ -490,7 +505,7 @@
 	}
 
 	for (i = 0; i < count; i++) {
-		old_childname = mail_namespace_get_storage_name(oldlist->ns,
+		old_childname = mailbox_list_get_storage_name(oldlist,
 					t_strconcat(old_vname, names[i], NULL));
 		if (strcmp(old_childname, new_vname) == 0) {
 			/* When doing RENAME "a" "a.b" we see "a.b" here.
@@ -498,7 +513,7 @@
 			continue;
 		}
 
-		new_childname = mail_namespace_get_storage_name(newlist->ns,
+		new_childname = mailbox_list_get_storage_name(newlist,
 					t_strconcat(new_vname, names[i], NULL));
 		oldpath = mailbox_list_get_path(oldlist, old_childname,
 						MAILBOX_LIST_PATH_TYPE_MAILBOX);
@@ -596,7 +611,6 @@
 
 struct mailbox_list maildir_mailbox_list = {
 	.name = MAILBOX_LIST_NAME_MAILDIRPLUSPLUS,
-	.hierarchy_sep = '.',
 	.props = MAILBOX_LIST_PROP_NO_MAILDIR_NAME |
 		MAILBOX_LIST_PROP_NO_ALT_DIR |
 		MAILBOX_LIST_PROP_NO_NOSELECT,
@@ -609,6 +623,9 @@
 		maildir_is_valid_pattern,
 		maildir_is_valid_existing_name,
 		maildir_is_valid_create_name,
+		maildir_list_get_hierarchy_sep,
+		mailbox_list_default_get_vname,
+		mailbox_list_default_get_storage_name,
 		maildir_list_get_path,
 		maildir_list_get_temp_prefix,
 		NULL,
@@ -627,7 +644,6 @@
 
 struct mailbox_list imapdir_mailbox_list = {
 	.name = MAILBOX_LIST_NAME_IMAPDIR,
-	.hierarchy_sep = '.',
 	.props = MAILBOX_LIST_PROP_NO_MAILDIR_NAME |
 		MAILBOX_LIST_PROP_NO_ALT_DIR |
 		MAILBOX_LIST_PROP_NO_NOSELECT,
@@ -640,6 +656,9 @@
 		maildir_is_valid_pattern,
 		maildir_is_valid_existing_name,
 		maildir_is_valid_create_name,
+		maildir_list_get_hierarchy_sep,
+		mailbox_list_default_get_vname,
+		mailbox_list_default_get_storage_name,
 		maildir_list_get_path,
 		maildir_list_get_temp_prefix,
 		NULL,
--- a/src/lib-storage/list/mailbox-list-maildir.h	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/lib-storage/list/mailbox-list-maildir.h	Thu Jan 20 20:59:07 2011 +0200
@@ -15,6 +15,7 @@
 	struct mailbox_list list;
 
 	const char *global_temp_prefix, *temp_prefix;
+	char sep;
 };
 
 struct mailbox_list_iterate_context *
--- a/src/lib-storage/list/mailbox-list-none.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/lib-storage/list/mailbox-list-none.c	Thu Jan 20 20:59:07 2011 +0200
@@ -47,6 +47,11 @@
 	return FALSE;
 }
 
+static char none_list_get_hierarchy_sep(struct mailbox_list *list ATTR_UNUSED)
+{
+	return '/';
+}
+
 static const char *
 none_list_get_path(struct mailbox_list *list ATTR_UNUSED,
 		   const char *name ATTR_UNUSED,
@@ -147,7 +152,6 @@
 
 struct mailbox_list none_mailbox_list = {
 	.name = MAILBOX_LIST_NAME_NONE,
-	.hierarchy_sep = '/',
 	.props = MAILBOX_LIST_PROP_NO_ROOT,
 	.mailbox_name_max_length = MAILBOX_LIST_NAME_MAX_LENGTH,
 
@@ -158,6 +162,9 @@
 		none_is_valid_pattern,
 		none_is_valid_existing_name,
 		none_is_valid_create_name,
+		none_list_get_hierarchy_sep,
+		mailbox_list_default_get_vname,
+		mailbox_list_default_get_storage_name,
 		none_list_get_path,
 		none_list_get_temp_prefix,
 		NULL,
--- a/src/lib-storage/list/mailbox-list-subscriptions.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/lib-storage/list/mailbox-list-subscriptions.c	Thu Jan 20 20:59:07 2011 +0200
@@ -1,31 +1,95 @@
 /* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */
 
 #include "lib.h"
-#include "str.h"
 #include "subscription-file.h"
 #include "mailbox-list-private.h"
 #include "mailbox-list-subscriptions.h"
 
 static int
+mailbox_list_subscription_fill_one(struct mailbox_list_iter_update_context *update_ctx,
+				   struct mail_namespace *default_ns,
+				   const char *name)
+{
+	struct mail_namespace *namespaces = default_ns->user->namespaces;
+	struct mail_namespace *ns;
+	const char *vname;
+
+	/* default_ns is whatever namespace we're currently listing.
+	   if we have e.g. prefix="" and prefix=pub/ namespaces with
+	   pub/ namespace having subscriptions=no, we want to:
+
+	   1) when listing "" namespace we want to skip over any names
+	   that begin with pub/. */
+	ns = mail_namespace_find_unsubscribable(namespaces, name);
+	if (ns != NULL && ns != default_ns)
+		return 0;
+
+	/* 2) when listing pub/ namespace, skip over entries that don't
+	   begin with pub/. */
+	if (ns == NULL &&
+	    (default_ns->flags & NAMESPACE_FLAG_SUBSCRIPTIONS) == 0)
+		return 0;
+
+	/* When listing shared namespace's subscriptions, we need to
+	   autocreate all the visible child namespaces and use the
+	   child namespace. */
+	if (ns != NULL && ns->type == NAMESPACE_SHARED &&
+	    (ns->flags & NAMESPACE_FLAG_AUTOCREATED) == 0) {
+		/* we'll need to get the namespace autocreated.
+		   one easy way is to just ask if a mailbox name under
+		   it is valid, and it gets created */
+		(void)mailbox_list_is_valid_existing_name(ns->list, name);
+		ns = mail_namespace_find_unsubscribable(namespaces, name);
+		i_assert(ns != NULL &&
+			 (ns->flags & NAMESPACE_FLAG_AUTOCREATED) != 0);
+	}
+
+	/* When listing pub/ namespace, skip over the namespace
+	   prefix in the name. the rest of the name is storage_name. */
+	if (ns != NULL) {
+		i_assert(strncmp(name, ns->prefix, ns->prefix_len) == 0);
+		name += ns->prefix_len;
+	} else {
+		ns = default_ns;
+	}
+
+	if (!mailbox_list_is_valid_existing_name(ns->list, name)) {
+		/* we'll only get into trouble if we show this */
+		return -1;
+	} else {
+		vname = mailbox_list_get_vname(ns->list, name);
+		mailbox_list_iter_update(update_ctx, vname);
+	}
+	return 0;
+}
+
+static int
 mailbox_list_subscriptions_fill_real(struct mailbox_list_iterate_context *ctx,
 				     struct mailbox_tree_context *tree_ctx,
 				     struct imap_match_glob *glob,
 				     bool update_only)
 {
-	struct mail_namespace *default_ns = ctx->list->ns;
-	struct mail_namespace *namespaces = default_ns->user->namespaces;
+	struct mail_namespace *ns, *default_ns = ctx->list->ns;
+	struct mailbox_list *list = ctx->list;
 	struct mailbox_list_iter_update_context update_ctx;
 	struct subsfile_list_context *subsfile_ctx;
-	struct mail_namespace *ns;
-	const char *path, *name, *name2, *full_name, *orig_name;
-	string_t *vname;
+	const char *path, *name;
 
-	vname = str_new(default_pool, 256);
-	path = t_strconcat(ctx->list->set.control_dir != NULL ?
-			   ctx->list->set.control_dir :
-			   ctx->list->set.root_dir,
-			   "/", ctx->list->set.subscription_fname, NULL);
-	subsfile_ctx = subsfile_list_init(ctx->list, path);
+	if ((ctx->list->ns->flags & NAMESPACE_FLAG_SUBSCRIPTIONS) == 0) {
+		/* need to list these using another namespace */
+		ns = mail_namespace_find_subscribable(default_ns->user->namespaces,
+						      default_ns->prefix);
+		if (ns == NULL) {
+			/* no subscriptions */
+			return 0;
+		}
+		list = ns->list;
+	}
+
+	path = t_strconcat(list->set.control_dir != NULL ?
+			   list->set.control_dir : list->set.root_dir,
+			   "/", list->set.subscription_fname, NULL);
+	subsfile_ctx = subsfile_list_init(list, path);
 
 	memset(&update_ctx, 0, sizeof(update_ctx));
 	update_ctx.iter_ctx = ctx;
@@ -38,37 +102,13 @@
 		(ctx->flags & MAILBOX_LIST_ITER_SELECT_RECURSIVEMATCH) != 0;
 
 	while ((name = subsfile_list_next(subsfile_ctx)) != NULL) T_BEGIN {
-		orig_name = name;
-		full_name = name2 =
-			t_strconcat(default_ns->prefix, name, NULL);
-		ns = mail_namespace_find_unsubscribable(namespaces, &name2);
-		if (ns == NULL)
-			ns = default_ns;
-		else if (ns->type == NAMESPACE_SHARED &&
-			 (ns->flags & NAMESPACE_FLAG_AUTOCREATED) == 0) {
-			/* we'll need to get the namespace autocreated.
-			   one easy way is to just ask if a mailbox name under
-			   it is valid, and it gets created */
-			(void)mailbox_list_is_valid_existing_name(ns->list,
-								  name2);
-			name = full_name;
-			ns = mail_namespace_find_unsubscribable(namespaces,
-								&name);
-		} else {
-			name = name2;
-		}
-
-		if (!mailbox_list_is_valid_existing_name(ns->list, name)) {
-			/* we'll only get into trouble if we show this */
+		if (mailbox_list_subscription_fill_one(&update_ctx, default_ns,
+						       name) < 0) {
 			i_warning("Subscriptions file %s: "
 				  "Ignoring invalid entry: %s",
-				  path, orig_name);
-		} else {
-			name = mail_namespace_get_vname(ns, vname, name);
-			mailbox_list_iter_update(&update_ctx, name);
+				  path, name);
 		}
 	} T_END;
-	str_free(&vname);
 	return subsfile_list_deinit(subsfile_ctx);
 }
 
--- a/src/lib-storage/mail-namespace.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/lib-storage/mail-namespace.c	Thu Jan 20 20:59:07 2011 +0200
@@ -27,22 +27,7 @@
 				     struct mailbox_list *list)
 {
 	ns->list = list;
-
-	/* allow plugins to override real_sep */
-	if (ns->real_sep == '\0')
-		ns->real_sep = list->hierarchy_sep;
 	ns->prefix_len = strlen(ns->prefix);
-
-	if (ns->set->separator != NULL)
-		ns->sep = *ns->set->separator;
-	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 void mail_namespace_free(struct mail_namespace *ns)
@@ -203,9 +188,10 @@
 {
 	struct mail_namespace *ns, *inbox_ns = NULL;
 	unsigned int subscriptions_count = 0;
-	char list_sep = '\0';
+	char ns_sep, list_sep = '\0';
 
 	for (ns = namespaces; ns != NULL; ns = ns->next) {
+		ns_sep = mail_namespace_get_sep(ns);
 		if (mail_namespace_find_prefix(ns->next, ns->prefix) != NULL) {
 			*error_r = t_strdup_printf(
 				"Duplicate namespace prefix: \"%s\"",
@@ -225,7 +211,7 @@
 		if (*ns->prefix != '\0' &&
 		    (ns->flags & (NAMESPACE_FLAG_LIST_PREFIX |
 				  NAMESPACE_FLAG_LIST_CHILDREN)) != 0 &&
-		    ns->prefix[strlen(ns->prefix)-1] != ns->sep) {
+		    ns->prefix[strlen(ns->prefix)-1] != ns_sep) {
 			*error_r = t_strdup_printf(
 				"list=yes requires prefix=%s "
 				"to end with separator", ns->prefix);
@@ -234,7 +220,7 @@
 		if (*ns->prefix != '\0' &&
 		    (ns->flags & (NAMESPACE_FLAG_LIST_PREFIX |
 				  NAMESPACE_FLAG_LIST_CHILDREN)) != 0 &&
-		    ns->prefix[0] == ns->sep) {
+		    ns->prefix[0] == ns_sep) {
 			*error_r = t_strdup_printf(
 				"list=yes requires prefix=%s "
 				"not to start with separator", ns->prefix);
@@ -243,8 +229,8 @@
 		if ((ns->flags & (NAMESPACE_FLAG_LIST_PREFIX |
 				  NAMESPACE_FLAG_LIST_CHILDREN)) != 0) {
 			if (list_sep == '\0')
-				list_sep = ns->sep;
-			else if (list_sep != ns->sep) {
+				list_sep = ns_sep;
+			else if (list_sep != ns_sep) {
 				*error_r = "All list=yes namespaces must use "
 					"the same separator";
 				return FALSE;
@@ -472,60 +458,6 @@
 	mail_namespace_unref(&ns);
 }
 
-const char *mail_namespace_fix_sep(struct mail_namespace *ns, const char *name)
-{
-	char *ret, *p;
-
-	if (ns->sep == ns->real_sep)
-		return name;
-	if (ns->type == NAMESPACE_SHARED &&
-	    (ns->flags & NAMESPACE_FLAG_AUTOCREATED) == 0) {
-		/* shared namespace root. the backend storage's hierarchy
-		   separator isn't known yet, so do nothing. */
-		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;
-}
-
-const char *mail_namespace_get_storage_name(struct mail_namespace *ns,
-					    const char *name)
-{
-	unsigned int len = strlen(ns->prefix);
-
-	if (len > 0) {
-		if (strncmp(ns->prefix, name, len) == 0)
-			name += len;
-		else {
-			i_assert(strcasecmp(name, "INBOX") == 0);
-		}
-	}
-	return mail_namespace_fix_sep(ns, name);
-}
-
-const char *mail_namespace_get_vname(struct mail_namespace *ns, string_t *dest,
-				     const char *name)
-{
-	str_truncate(dest, 0);
-	if ((ns->flags & NAMESPACE_FLAG_INBOX_USER) == 0 ||
-	    strcasecmp(name, "INBOX") != 0 ||
-	    ns->user != ns->owner)
-		str_append(dest, ns->prefix);
-
-	for (; *name != '\0'; name++) {
-		if (*name == ns->real_sep)
-			str_append_c(dest, ns->sep);
-		else
-			str_append_c(dest, *name);
-	}
-	return str_c(dest);
-}
-
 struct mail_storage *
 mail_namespace_get_default_storage(struct mail_namespace *ns)
 {
@@ -533,11 +465,17 @@
 	return ns->storage;
 }
 
-char mail_namespaces_get_root_sep(const struct mail_namespace *namespaces)
+char mail_namespace_get_sep(struct mail_namespace *ns)
+{
+	return *ns->set->separator != '\0' ? *ns->set->separator :
+		mailbox_list_get_hierarchy_sep(ns->list);
+}
+
+char mail_namespaces_get_root_sep(struct mail_namespace *namespaces)
 {
 	while ((namespaces->flags & NAMESPACE_FLAG_LIST_PREFIX) == 0)
 		namespaces = namespaces->next;
-	return namespaces->sep;
+	return mail_namespace_get_sep(namespaces);
 }
 
 static bool mail_namespace_is_usable_prefix(struct mail_namespace *ns,
@@ -558,7 +496,7 @@
 
 	if (strncmp(ns->prefix, mailbox, ns->prefix_len-1) == 0 &&
 	    mailbox[ns->prefix_len-1] == '\0' &&
-	    ns->prefix[ns->prefix_len-1] == ns->sep) {
+	    ns->prefix[ns->prefix_len-1] == mail_namespace_get_sep(ns)) {
 		/* we're trying to access the namespace prefix itself */
 		return TRUE;
 	}
@@ -566,21 +504,18 @@
 }
 
 static struct mail_namespace *
-mail_namespace_find_mask(struct mail_namespace *namespaces,
-			 const char **mailbox,
+mail_namespace_find_mask(struct mail_namespace *namespaces, const char *box,
 			 enum namespace_flags flags,
 			 enum namespace_flags mask)
 {
         struct mail_namespace *ns = namespaces;
-	const char *box = *mailbox;
 	struct mail_namespace *best = NULL;
-	unsigned int len, best_len = 0;
+	unsigned int 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->flags & NAMESPACE_FLAG_INBOX_USER) != 0 &&
 			    (ns->flags & mask) == flags)
@@ -599,21 +534,11 @@
 			best_len = ns->prefix_len;
 		}
 	}
-
-	if (best != NULL) {
-		if (best_len > 0) {
-			len = strlen(*mailbox);
-			*mailbox += I_MIN(len, 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;
 }
 
 static struct mail_namespace *
-mail_namespace_find_shared(struct mail_namespace *ns, const char **mailbox)
+mail_namespace_find_shared(struct mail_namespace *ns, const char *mailbox)
 {
 	struct mailbox_list *list = ns->list;
 	struct mail_storage *storage;
@@ -625,7 +550,7 @@
 }
 
 struct mail_namespace *
-mail_namespace_find(struct mail_namespace *namespaces, const char **mailbox)
+mail_namespace_find(struct mail_namespace *namespaces, const char *mailbox)
 {
 	struct mail_namespace *ns;
 
@@ -633,7 +558,7 @@
 	if (ns != NULL && ns->type == NAMESPACE_SHARED &&
 	    (ns->flags & NAMESPACE_FLAG_AUTOCREATED) == 0) {
 		/* see if we need to autocreate a namespace for shared user */
-		if (strchr(*mailbox, ns->sep) != NULL)
+		if (strchr(mailbox, mail_namespace_get_sep(ns)) != NULL)
 			return mail_namespace_find_shared(ns, mailbox);
 	}
 	return ns;
@@ -641,7 +566,7 @@
 
 struct mail_namespace *
 mail_namespace_find_visible(struct mail_namespace *namespaces,
-			    const char **mailbox)
+			    const char *mailbox)
 {
 	return mail_namespace_find_mask(namespaces, mailbox, 0,
 					NAMESPACE_FLAG_HIDDEN);
@@ -649,7 +574,7 @@
 
 struct mail_namespace *
 mail_namespace_find_subscribable(struct mail_namespace *namespaces,
-				 const char **mailbox)
+				 const char *mailbox)
 {
 	return mail_namespace_find_mask(namespaces, mailbox,
 					NAMESPACE_FLAG_SUBSCRIPTIONS,
@@ -658,7 +583,7 @@
 
 struct mail_namespace *
 mail_namespace_find_unsubscribable(struct mail_namespace *namespaces,
-				   const char **mailbox)
+				   const char *mailbox)
 {
 	return mail_namespace_find_mask(namespaces, mailbox,
 					0, NAMESPACE_FLAG_SUBSCRIPTIONS);
@@ -672,16 +597,6 @@
 	return namespaces;
 }
 
-bool mail_namespace_update_name(const struct mail_namespace *ns,
-				const char **mailbox)
-{
-	struct mail_namespace tmp_ns = *ns;
-
-	/* FIXME: a bit kludgy.. */
-	tmp_ns.next = NULL;
-	return mail_namespace_find_mask(&tmp_ns, mailbox, 0, 0) != NULL;
-}
-
 struct mail_namespace *
 mail_namespace_find_prefix(struct mail_namespace *namespaces,
 			   const char *prefix)
@@ -707,7 +622,7 @@
 	for (ns = namespaces; ns != NULL; ns = ns->next) {
 		if (ns->prefix_len == len + 1 &&
 		    strncmp(ns->prefix, prefix, len) == 0 &&
-		    ns->prefix[len] == ns->sep)
+		    ns->prefix[len] == mail_namespace_get_sep(ns))
 			return ns;
 	}
 	return NULL;
--- a/src/lib-storage/mail-namespace.h	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/lib-storage/mail-namespace.h	Thu Jan 20 20:59:07 2011 +0200
@@ -46,7 +46,6 @@
 	int refcount;
 
         enum namespace_type type;
-	char sep, real_sep, sep_str[3];
 	enum namespace_flags flags;
 
 	char *prefix;
@@ -93,48 +92,35 @@
 /* Destroy a single namespace and remove it from user's namespaces list. */
 void mail_namespace_destroy(struct mail_namespace *ns);
 
-/* Update hierarchy separators in given name to real_sep characters. */
-const char *mail_namespace_fix_sep(struct mail_namespace *ns, const char *name);
-/* Skip namespace prefix and change hierarchy separators. */
-const char *mail_namespace_get_storage_name(struct mail_namespace *ns,
-					    const char *name);
-/* Write virtual mailbox name to dest and return it. Separators are changed to
-   virtual ones and namespace prefix is inserted except for INBOX. */
-const char *mail_namespace_get_vname(struct mail_namespace *ns, string_t *dest,
-				     const char *name);
 /* Returns the default storage to use for newly created mailboxes. */
 struct mail_storage *
 mail_namespace_get_default_storage(struct mail_namespace *ns);
 
+/* Return namespace's hierarchy separator. */
+char mail_namespace_get_sep(struct mail_namespace *ns);
 /* Returns the hierarchy separator for mailboxes that are listed at root. */
-char mail_namespaces_get_root_sep(const struct mail_namespace *namespaces)
+char mail_namespaces_get_root_sep(struct mail_namespace *namespaces)
 	ATTR_PURE;
 
-/* Returns namespace based on the mailbox name's prefix. Updates mailbox to
-   be a valid name inside the namespace (prefix is skipped, hierarchy separator
-   is changed to real_sep). If no namespaces were found, returns NULL. */
+/* Returns namespace based on the mailbox name's prefix, or NULL if no matching
+   namespace could be found. */
 struct mail_namespace *
-mail_namespace_find(struct mail_namespace *namespaces, const char **mailbox);
+mail_namespace_find(struct mail_namespace *namespaces, const char *mailbox);
 /* Like above, but ignore hidden namespaces. */
 struct mail_namespace *
 mail_namespace_find_visible(struct mail_namespace *namespaces,
-			    const char **mailbox);
+			    const char *mailbox);
 /* Like above, but find only from namespaces with subscriptions flag set. */
 struct mail_namespace *
 mail_namespace_find_subscribable(struct mail_namespace *namespaces,
-				 const char **mailbox);
+				 const char *mailbox);
 /* Like above, but find only from namespaces with subscriptions flag not set. */
 struct mail_namespace *
 mail_namespace_find_unsubscribable(struct mail_namespace *namespaces,
-				   const char **mailbox);
+				   const char *mailbox);
 /* Returns the INBOX namespace */
 struct mail_namespace *
 mail_namespace_find_inbox(struct mail_namespace *namespaces);
-/* Returns TRUE if the given namespace matches the mailbox's prefix.
-   Updates mailbox name to be a valid name inside the namespace. */
-bool mail_namespace_update_name(const struct mail_namespace *ns,
-				const char **mailbox);
-
 /* Find a namespace with given prefix. */
 struct mail_namespace *
 mail_namespace_find_prefix(struct mail_namespace *namespaces,
--- a/src/lib-storage/mail-search.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/lib-storage/mail-search.c	Thu Jan 20 20:59:07 2011 +0200
@@ -99,7 +99,7 @@
 
 			arg->value.mailbox_glob =
 				imap_match_init(default_pool, arg->value.str,
-						TRUE, ns->sep);
+						TRUE, mail_namespace_get_sep(ns));
 			break;
 		}
 		case SEARCH_INTHREAD:
--- a/src/lib-storage/mail-storage-private.h	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/lib-storage/mail-storage-private.h	Thu Jan 20 20:59:07 2011 +0200
@@ -38,7 +38,7 @@
 
 	struct mailbox *(*mailbox_alloc)(struct mail_storage *storage,
 					 struct mailbox_list *list,
-					 const char *name,
+					 const char *vname,
 					 enum mailbox_flags flags);
 	int (*purge)(struct mail_storage *storage);
 };
--- a/src/lib-storage/mail-storage.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/lib-storage/mail-storage.c	Thu Jan 20 20:59:07 2011 +0200
@@ -560,20 +560,20 @@
 	return TRUE;
 }
 
-struct mailbox *mailbox_alloc(struct mailbox_list *list, const char *name,
+struct mailbox *mailbox_alloc(struct mailbox_list *list, const char *vname,
 			      enum mailbox_flags flags)
 {
 	struct mailbox_list *new_list = list;
 	struct mail_storage *storage;
 	struct mailbox *box;
 
-	if (mailbox_list_get_storage(&new_list, &name, &storage) < 0) {
+	if (mailbox_list_get_storage(&new_list, vname, &storage) < 0) {
 		/* just use the first storage. FIXME: does this break? */
 		storage = list->ns->storage;
 	}
 
 	T_BEGIN {
-		box = storage->v.mailbox_alloc(storage, new_list, name, flags);
+		box = storage->v.mailbox_alloc(storage, new_list, vname, flags);
 		hook_mailbox_allocated(box);
 	} T_END;
 
@@ -581,6 +581,28 @@
 	return box;
 }
 
+static bool have_listable_namespace_prefix(struct mail_namespace *ns,
+					   const char *name)
+{
+	unsigned int name_len = strlen(name);
+
+	for (; ns != NULL; ns = ns->next) {
+		if ((ns->flags & (NAMESPACE_FLAG_LIST_PREFIX |
+				  NAMESPACE_FLAG_LIST_CHILDREN)) == 0)
+			continue;
+
+		if (ns->prefix_len <= name_len)
+			continue;
+
+		/* if prefix has multiple hierarchies, match
+		   any of the hierarchies */
+		if (strncmp(ns->prefix, name, name_len) == 0 &&
+		    ns->prefix[name_len] == mail_namespace_get_sep(ns))
+			return TRUE;
+	}
+	return FALSE;
+}
+
 int mailbox_exists(struct mailbox *box)
 {
 	if (!mailbox_list_is_valid_existing_name(box->list, box->name)) {
@@ -589,9 +611,49 @@
 		return -1;
 	}
 
+	if (have_listable_namespace_prefix(box->storage->user->namespaces,
+					   box->vname)) {
+		/* listable namespace prefix always exists */
+		return 1;
+	}
+
 	return box->v.exists(box);
 }
 
+static int mailbox_check_mismatching_separators(struct mailbox *box)
+{
+	struct mail_namespace *ns = box->list->ns;
+	const char *p, *vname = box->vname;
+	char list_sep, ns_sep;
+
+	list_sep = mailbox_list_get_hierarchy_sep(box->list);
+	ns_sep = mail_namespace_get_sep(ns);
+
+	if (ns_sep == list_sep)
+		return 0;
+
+	if (ns->prefix_len > 0) {
+		/* vname is prefix with or without separator */
+		i_assert(strncmp(vname, ns->prefix, ns->prefix_len-1) == 0);
+		vname += ns->prefix_len - 1;
+		if (vname[0] != '\0') {
+			i_assert(vname[0] == ns->prefix[ns->prefix_len-1]);
+			vname++;
+		}
+	}
+
+	for (p = vname; *p != '\0'; p++) {
+		if (*p == list_sep) {
+			mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
+				t_strdup_printf("NO Character not allowed "
+						"in mailbox name: '%c'",
+						list_sep));
+			return -1;
+		}
+	}
+	return 0;
+}
+
 static int mailbox_open_full(struct mailbox *box, struct istream *input)
 {
 	int ret;
@@ -599,6 +661,8 @@
 	if (box->opened)
 		return 0;
 
+	if (mailbox_check_mismatching_separators(box) < 0)
+		return -1;
 	if (!mailbox_list_is_valid_existing_name(box->list, box->name)) {
 		mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
 				       "Invalid mailbox name");
@@ -876,6 +940,42 @@
 	return src->v.rename(src, dest, rename_children);
 }
 
+int mailbox_set_subscribed(struct mailbox *box, bool set)
+{
+	struct mail_namespace *ns;
+	struct mailbox_list *list = box->list;
+	const char *subs_name;
+
+	if (!mailbox_list_is_valid_existing_name(list, box->name)) {
+		mail_storage_set_error(box->storage, MAIL_ERROR_PARAMS,
+				       "Invalid mailbox name");
+		return -1;
+	}
+
+	if ((list->ns->flags & NAMESPACE_FLAG_SUBSCRIPTIONS) != 0)
+		subs_name = box->name;
+	else {
+		/* subscriptions=no namespace, find another one where we can
+		   add the subscription to */
+		ns = mail_namespace_find_subscribable(list->ns->user->namespaces,
+						      box->vname);
+		if (ns == NULL) {
+			mail_storage_set_error(box->storage, MAIL_ERROR_NOTPOSSIBLE,
+				"This namespace has no subscriptions");
+			return -1;
+		}
+		/* use <orig ns prefix><orig storage name> as the
+		   subscription name */
+		subs_name = t_strconcat(list->ns->prefix, box->name, NULL);
+		/* drop the common prefix (typically there isn't one) */
+		i_assert(strncmp(ns->prefix, subs_name, strlen(ns->prefix)) == 0);
+		subs_name += strlen(ns->prefix);
+
+		list = ns->list;
+	}
+	return mailbox_list_set_subscribed(list, subs_name, set);
+}
+
 struct mail_storage *mailbox_get_storage(const struct mailbox *box)
 {
 	return box->storage;
--- a/src/lib-storage/mail-storage.h	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/lib-storage/mail-storage.h	Thu Jan 20 20:59:07 2011 +0200
@@ -341,7 +341,7 @@
 /* Initialize mailbox without actually opening any files or verifying that
    it exists. Note that append and copy may open the selected mailbox again
    with possibly different readonly-state. */
-struct mailbox *mailbox_alloc(struct mailbox_list *list, const char *name,
+struct mailbox *mailbox_alloc(struct mailbox_list *list, const char *vname,
 			      enum mailbox_flags flags);
 /* Returns 1 if mailbox exists (even if it's unselectable),
    0 if not and -1 if some error occurred. */
@@ -373,6 +373,9 @@
    fails, the error is set to src's storage. */
 int mailbox_rename(struct mailbox *src, struct mailbox *dest,
 		   bool rename_children);
+/* Subscribe/unsubscribe mailbox. Subscribing to
+   nonexistent mailboxes is optional. */
+int mailbox_set_subscribed(struct mailbox *box, bool set);
 
 /* Enable the given feature for the mailbox. */
 int mailbox_enable(struct mailbox *box, enum mailbox_feature features);
--- a/src/lib-storage/mailbox-list-private.h	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/lib-storage/mailbox-list-private.h	Thu Jan 20 20:59:07 2011 +0200
@@ -34,7 +34,7 @@
 	struct mailbox_list *(*alloc)(void);
 	void (*deinit)(struct mailbox_list *list);
 
-	int (*get_storage)(struct mailbox_list **list, const char **name,
+	int (*get_storage)(struct mailbox_list **list, const char *vname,
 			   struct mail_storage **storage_r);
 	bool (*is_valid_pattern)(struct mailbox_list *list,
 				 const char *pattern);
@@ -43,6 +43,11 @@
 	bool (*is_valid_create_name)(struct mailbox_list *list,
 				     const char *name);
 
+	char (*get_hierarchy_sep)(struct mailbox_list *list);
+	const char *(*get_vname)(struct mailbox_list *list,
+				 const char *storage_name);
+	const char *(*get_storage_name)(struct mailbox_list *list,
+					const char *vname);
 	const char *(*get_path)(struct mailbox_list *list, const char *name,
 				enum mailbox_list_path_type type);
 
@@ -89,7 +94,6 @@
 
 struct mailbox_list {
 	const char *name;
-	char hierarchy_sep;
 	enum mailbox_list_properties props;
 	size_t mailbox_name_max_length;
 
@@ -147,8 +151,15 @@
 int mailbox_list_settings_parse(struct mail_user *user, const char *data,
 				struct mailbox_list_settings *set_r,
 				const char **error_r);
+const char *mailbox_list_default_get_storage_name(struct mailbox_list *list,
+						  const char *vname);
+const char *mailbox_list_default_get_vname(struct mailbox_list *list,
+					   const char *storage_name);
 const char *mailbox_list_get_unexpanded_path(struct mailbox_list *list,
 					     enum mailbox_list_path_type type);
+const char *mailbox_list_get_storage_name(struct mailbox_list *list,
+					  const char *vname);
+const char *mailbox_list_get_vname(struct mailbox_list *list, const char *name);
 const char *
 mailbox_list_get_root_path(const struct mailbox_list_settings *set,
 			   enum mailbox_list_path_type type);
--- a/src/lib-storage/mailbox-list.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/lib-storage/mailbox-list.c	Thu Jan 20 20:59:07 2011 +0200
@@ -345,6 +345,98 @@
 	return mailbox_list_get_root_path(&set, type);
 }
 
+const char *mailbox_list_default_get_storage_name(struct mailbox_list *list,
+						  const char *vname)
+{
+	struct mail_namespace *ns = list->ns;
+	unsigned int prefix_len = strlen(ns->prefix);
+	char list_sep, ns_sep, *ret, *p;
+
+	if (prefix_len > 0) {
+		/* skip namespace prefix, except if this is INBOX */
+		if (strncmp(ns->prefix, vname, prefix_len) == 0)
+			vname += prefix_len;
+		else if (strncmp(ns->prefix, vname, prefix_len-1) == 0 &&
+			 ns->prefix[prefix_len-1] == mail_namespace_get_sep(ns)) {
+			/* trying to access the namespace prefix itself */
+			vname = "";
+		} else {
+			i_assert(strcasecmp(vname, "INBOX") == 0);
+		}
+	}
+
+	list_sep = mailbox_list_get_hierarchy_sep(list);
+	ns_sep = mail_namespace_get_sep(ns);
+
+	if (list_sep == ns_sep)
+		return vname;
+	if (ns->type == NAMESPACE_SHARED &&
+	    (ns->flags & NAMESPACE_FLAG_AUTOCREATED) == 0) {
+		/* shared namespace root. the backend storage's hierarchy
+		   separator isn't known yet, so do nothing. */
+		return vname;
+	}
+
+	ret = p_strdup(unsafe_data_stack_pool, vname);
+	for (p = ret; *p != '\0'; p++) {
+		if (*p == ns_sep)
+			*p = list_sep;
+	}
+	return ret;
+}
+
+const char *mailbox_list_get_storage_name(struct mailbox_list *list,
+					  const char *vname)
+{
+	return list->v.get_storage_name(list, vname);
+}
+
+const char *mailbox_list_default_get_vname(struct mailbox_list *list,
+					   const char *storage_name)
+{
+	unsigned int i, prefix_len, name_len;
+	char list_sep, ns_sep, *ret;
+
+	if ((list->ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0 &&
+	    strcasecmp(storage_name, "INBOX") == 0 &&
+	    list->ns->user == list->ns->owner) {
+		/* user's INBOX - use as-is */
+		return "INBOX";
+	}
+	if (*storage_name == '\0') {
+		/* return namespace prefix without the separator */
+		if (list->ns->prefix_len == 0)
+			return list->ns->prefix;
+		else {
+			return t_strndup(list->ns->prefix,
+					 list->ns->prefix_len - 1);
+		}
+	}
+
+	prefix_len = strlen(list->ns->prefix);
+	list_sep = mailbox_list_get_hierarchy_sep(list);
+	ns_sep = mail_namespace_get_sep(list->ns);
+
+	if (list_sep == ns_sep && prefix_len == 0)
+		return storage_name;
+
+	/* @UNSAFE */
+	name_len = strlen(storage_name);
+	ret = t_malloc(prefix_len + name_len + 1);
+	memcpy(ret, list->ns->prefix, prefix_len);
+	for (i = 0; i < name_len; i++) {
+		ret[i + prefix_len] = storage_name[i] == list_sep ? ns_sep :
+			storage_name[i];
+	}
+	ret[i + prefix_len] = '\0';
+	return ret;
+}
+
+const char *mailbox_list_get_vname(struct mailbox_list *list, const char *name)
+{
+	return list->v.get_vname(list, name);
+}
+
 void mailbox_list_destroy(struct mailbox_list **_list)
 {
 	struct mailbox_list *list = *_list;
@@ -388,11 +480,11 @@
 	return list->ns->user;
 }
 
-int mailbox_list_get_storage(struct mailbox_list **list, const char **name,
+int mailbox_list_get_storage(struct mailbox_list **list, const char *vname,
 			     struct mail_storage **storage_r)
 {
 	if ((*list)->v.get_storage != NULL)
-		return (*list)->v.get_storage(list, name, storage_r);
+		return (*list)->v.get_storage(list, vname, storage_r);
 	else {
 		*storage_r = (*list)->ns->storage;
 		return 0;
@@ -405,6 +497,11 @@
 	*storage = list->ns->storage;
 }
 
+char mailbox_list_get_hierarchy_sep(struct mailbox_list *list)
+{
+	return list->v.get_hierarchy_sep(list);
+}
+
 static void
 mailbox_list_get_permissions_full(struct mailbox_list *list, const char *name,
 				  mode_t *file_mode_r, mode_t *dir_mode_r,
@@ -818,7 +915,7 @@
 		return FALSE;
 
 	glob = imap_match_init(pool_datastack_create(), pattern,
-			       TRUE, ns->sep);
+			       TRUE, mail_namespace_get_sep(ns));
 	return imap_match(glob, "INBOX") == IMAP_MATCH_YES;
 }
 
@@ -832,7 +929,7 @@
 	unsigned int len;
 
 	len = ns->prefix_len;
-	if (len > 0 && ns->prefix[len-1] == ns->sep)
+	if (len > 0 && ns->prefix[len-1] == mail_namespace_get_sep(ns))
 		len--;
 
 	if ((ns->flags & (NAMESPACE_FLAG_LIST_PREFIX |
@@ -847,7 +944,7 @@
 		result = IMAP_MATCH_CHILDREN;
 	else {
 		glob = imap_match_init(pool_datastack_create(), pattern,
-				       TRUE, ns->sep);
+				       TRUE, mail_namespace_get_sep(ns));
 		result = imap_match(glob, prefix_without_sep);
 	}
 
@@ -1273,7 +1370,7 @@
 			break;
 
 		/* see if parent matches */
-		p = strrchr(name, ns->sep);
+		p = strrchr(name, mail_namespace_get_sep(ns));
 		if (p == NULL)
 			break;
 
--- a/src/lib-storage/mailbox-list.h	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/lib-storage/mailbox-list.h	Thu Jan 20 20:59:07 2011 +0200
@@ -159,10 +159,11 @@
 mailbox_list_get_namespace(const struct mailbox_list *list) ATTR_PURE;
 struct mail_user *
 mailbox_list_get_user(const struct mailbox_list *list) ATTR_PURE;
-int mailbox_list_get_storage(struct mailbox_list **list, const char **name,
+int mailbox_list_get_storage(struct mailbox_list **list, const char *vname,
 			     struct mail_storage **storage_r);
 void mailbox_list_get_closest_storage(struct mailbox_list *list,
 				      struct mail_storage **storage);
+char mailbox_list_get_hierarchy_sep(struct mailbox_list *list);
 
 /* Returns the mode and GID that should be used when creating new files to
    the specified mailbox or to mailbox list root. (gid_t)-1 is
--- a/src/lib-storage/test-mail-storage.h	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/lib-storage/test-mail-storage.h	Thu Jan 20 20:59:07 2011 +0200
@@ -5,7 +5,7 @@
 
 struct mailbox *
 test_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
-		   const char *name, enum mailbox_flags flags);
+		   const char *vname, enum mailbox_flags flags);
 
 struct mail *
 test_mailbox_mail_alloc(struct mailbox_transaction_context *t,
--- a/src/lib-storage/test-mailbox.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/lib-storage/test-mailbox.c	Thu Jan 20 20:59:07 2011 +0200
@@ -3,6 +3,7 @@
 #include "lib.h"
 #include "array.h"
 #include "mail-storage-private.h"
+#include "mailbox-list-private.h"
 #include "test-mail-storage.h"
 
 #define TEST_UID_VALIDITY 1
@@ -272,7 +273,7 @@
 
 struct mailbox *
 test_mailbox_alloc(struct mail_storage *storage, struct mailbox_list *list,
-		   const char *name, enum mailbox_flags flags)
+		   const char *vname, enum mailbox_flags flags)
 {
 	struct mailbox *box;
 	pool_t pool;
@@ -280,7 +281,8 @@
 	pool = pool_alloconly_create("test mailbox", 1024);
 	box = p_new(pool, struct mailbox, 1);
 	*box = test_mailbox;
-	box->name = p_strdup(pool, name);
+	box->vname = p_strdup(pool, vname);
+	box->name = p_strdup(pool, mailbox_list_get_storage_name(list, vname));
 	box->storage = storage;
 	box->list = list;
 
--- a/src/plugins/acl/acl-backend-vfile-acllist.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/plugins/acl/acl-backend-vfile-acllist.c	Thu Jan 20 20:59:07 2011 +0200
@@ -165,8 +165,7 @@
 	const char *name;
 	int ret;
 
-	name = mail_namespace_get_storage_name(backend->backend.list->ns,
-					       vname);
+	name = mailbox_list_get_storage_name(backend->backend.list, vname);
 	acl_cache_flush(backend->backend.cache, name);
 	aclobj = acl_object_init_from_name(&backend->backend, name);
 
--- a/src/plugins/acl/acl-backend-vfile.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/plugins/acl/acl-backend-vfile.c	Thu Jan 20 20:59:07 2011 +0200
@@ -11,6 +11,7 @@
 #include "file-dotlock.h"
 #include "nfs-workarounds.h"
 #include "mail-storage-private.h"
+#include "mailbox-list-private.h"
 #include "mail-namespace.h"
 #include "acl-cache.h"
 #include "acl-backend-vfile.h"
@@ -161,21 +162,16 @@
 	struct acl_backend_vfile *backend =
 		(struct acl_backend_vfile *)_backend;
 	struct acl_object_vfile *aclobj;
-	const char *dir;
+	const char *dir, *vname;
 
 	aclobj = i_new(struct acl_object_vfile, 1);
 	aclobj->aclobj.backend = _backend;
 	aclobj->aclobj.name = i_strdup(name);
 
 	if (backend->global_dir != NULL) T_BEGIN {
-		struct mail_namespace *ns =
-			mailbox_list_get_namespace(_backend->list);
-		string_t *vname;
-
-		vname = t_str_new(128);
-		mail_namespace_get_vname(ns, vname, name);
+		vname = mailbox_list_get_vname(backend->backend.list, name);
 		aclobj->global_path = i_strconcat(backend->global_dir, "/",
-						  str_c(vname), NULL);
+						  vname, NULL);
 	} T_END;
 
 	dir = acl_backend_vfile_get_local_dir(_backend, name);
@@ -190,7 +186,7 @@
 	struct mail_namespace *ns = mailbox_list_get_namespace(backend->list);
 	const char *p;
 
-	p = strrchr(name, ns->real_sep);
+	p = strrchr(name, mail_namespace_get_sep(ns));
 	return p == NULL ? NULL : t_strdup_until(name, p);
 }
 
--- a/src/plugins/acl/acl-mailbox-list.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/plugins/acl/acl-mailbox-list.c	Thu Jan 20 20:59:07 2011 +0200
@@ -90,7 +90,6 @@
 	struct mail_namespace *ns = ctx->ctx.list->ns;
 	struct mailbox_list_iter_update_context update_ctx;
 	const char *name;
-	string_t *vname = NULL;
 	int ret;
 
 	if ((ctx->ctx.flags & (MAILBOX_LIST_ITER_RAW_LIST |
@@ -111,7 +110,6 @@
 		return;
 
 	/* no LOOKUP right by default, we can optimize this */
-	vname = t_str_new(256);
 	memset(&update_ctx, 0, sizeof(update_ctx));
 	update_ctx.iter_ctx = &ctx->ctx;
 	update_ctx.glob =
@@ -124,9 +122,11 @@
 	nonowner_list_ctx = acl_backend_nonowner_lookups_iter_init(backend);
 	while ((ret = acl_backend_nonowner_lookups_iter_next(nonowner_list_ctx,
 							     &name)) > 0) {
-		if (vname != NULL)
-			name = mail_namespace_get_vname(ns, vname, name);
-		mailbox_list_iter_update(&update_ctx, name);
+		T_BEGIN {
+			const char *vname =
+				mailbox_list_get_vname(ns->list, name);
+			mailbox_list_iter_update(&update_ctx, vname);
+		} T_END;
 	}
 	acl_backend_nonowner_lookups_iter_deinit(&nonowner_list_ctx);
 
@@ -171,7 +171,7 @@
 	ctx->ctx.flags = flags;
 
 	inboxcase = (list->ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0;
-	ctx->sep = list->ns->sep;
+	ctx->sep = mail_namespace_get_sep(list->ns);
 	ctx->glob = imap_match_init_multiple(default_pool, patterns,
 					     inboxcase, ctx->sep);
 	/* see if all patterns have only a single '*' and it's at the end.
@@ -220,14 +220,15 @@
 
 static const char *
 acl_mailbox_list_iter_get_name(struct mailbox_list_iterate_context *ctx,
-			       const char *name)
+			       const char *vname)
 {
 	struct mail_namespace *ns = ctx->list->ns;
+	const char *name;
 	unsigned int len;
 
-	name = mail_namespace_get_storage_name(ns, name);
+	name = mailbox_list_get_storage_name(ns->list, vname);
 	len = strlen(name);
-	if (len > 0 && name[len-1] == ns->real_sep) {
+	if (len > 0 && name[len-1] == mailbox_list_get_hierarchy_sep(ns->list)) {
 		/* name ends with separator. this can happen if doing e.g.
 		   LIST "" foo/% and it lists "foo/". */
 		name = t_strndup(name, len-1);
--- a/src/plugins/autocreate/autocreate-plugin.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/plugins/autocreate/autocreate-plugin.c	Thu Jan 20 20:59:07 2011 +0200
@@ -18,7 +18,7 @@
 	const char *str;
 	enum mail_error error;
 
-	ns = mail_namespace_find(namespaces, &name);
+	ns = mail_namespace_find(namespaces, name);
 	if (ns == NULL) {
 		if (namespaces->mail_set->mail_debug)
 			i_debug("autocreate: No namespace found for %s", name);
@@ -57,24 +57,26 @@
 autosubscribe_mailbox(struct mail_namespace *namespaces, const char *name)
 {
 	struct mail_namespace *ns;
+	struct mailbox *box;
 	const char *str;
 	enum mail_error error;
 
-	ns = mail_namespace_find_subscribable(namespaces, &name);
+	ns = mail_namespace_find_subscribable(namespaces, name);
 	if (ns == NULL) {
 		if (namespaces->mail_set->mail_debug)
 			i_debug("autocreate: No namespace found for %s", name);
 		return;
 	}
 
-	if (mailbox_list_set_subscribed(ns->list, name, TRUE) < 0) {
-		str = mailbox_list_get_last_error(ns->list,
-						  &error);
+	box = mailbox_alloc(ns->list, name, 0);
+	if (mailbox_set_subscribed(box, TRUE) < 0) {
+		str = mailbox_get_last_error(box, &error);
 		if (error != MAIL_ERROR_EXISTS && ns->mail_set->mail_debug) {
 			i_debug("autocreate: Failed to subscribe mailbox "
 				"%s: %s", name, str);
 		}
 	}
+	mailbox_free(&box);
 }
 
 static void autosubscribe_mailboxes(struct mail_namespace *namespaces)
--- a/src/plugins/fts-solr/fts-backend-solr.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/plugins/fts-solr/fts-backend-solr.c	Thu Jan 20 20:59:07 2011 +0200
@@ -6,7 +6,7 @@
 #include "strescape.h"
 #include "unichar.h"
 #include "mail-storage-private.h"
-#include "mail-namespace.h"
+#include "mailbox-list-private.h"
 #include "fts-mailbox.h"
 #include "solr-connection.h"
 #include "fts-solr-plugin.h"
@@ -37,7 +37,6 @@
 struct solr_virtual_uid_map_context {
 	struct fts_backend *backend;
 	struct mailbox *box;
-	string_t *vname;
 };
 
 struct fts_backend_solr_get_last_uids_context {
@@ -46,7 +45,6 @@
 	ARRAY_TYPE(fts_backend_uid_map) *last_uids;
 
 	struct mailbox *box;
-	string_t *vname;
 };
 
 static struct solr_connection *solr_conn = NULL;
@@ -387,16 +385,15 @@
 	struct fts_backend_solr_get_last_uids_context *ctx = context;
 	struct fts_backend_uid_map *map;
 	struct mail_namespace *ns;
-	const char *vname;
 
 	ns = solr_get_namespaces(ctx->backend, ctx->box, ns_prefix);
-	for (; ns != NULL; ns = ns->alias_chain_next) {
-		vname = mail_namespace_get_vname(ns, ctx->vname, mailbox);
+	for (; ns != NULL; ns = ns->alias_chain_next) T_BEGIN {
+		const char *vname = mailbox_list_get_vname(ns->list, mailbox);
 		map = array_append_space(ctx->last_uids);
 		map->mailbox = p_strdup(ctx->pool, vname);
 		map->uidvalidity = uidvalidity;
 		map->uid = *uid;
-	}
+	} T_END;
 	return FALSE;
 }
 
@@ -407,9 +404,6 @@
 	const char *name, *p;
 
 	name = pattern->pattern;
-	if (!mail_namespace_update_name(pattern->ns, &name))
-		name = mail_namespace_fix_sep(pattern->ns, name);
-
 	fts_box_name_get_root(&ns, &name);
 
 	if (strcmp(name, "*") == 0) {
@@ -513,7 +507,6 @@
 	ctx.pool = pool;
 	ctx.last_uids = last_uids;
 	ctx.box = backend->box;
-	ctx.vname = t_str_new(256);
 
 	str = t_str_new(256);
 	str_printfa(str, "fl=uid,box,uidv,ns&rows=%u&q=last_uid:TRUE+user:",
@@ -775,17 +768,20 @@
 {
 	struct solr_virtual_uid_map_context *ctx = context;
 	struct mail_namespace *ns;
-	const char *vname;
-	bool convert_inbox;
+	bool convert_inbox, ret;
 
 	ns = solr_get_namespaces(ctx->backend, ctx->box, ns_prefix);
 	convert_inbox = (ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0 &&
 		strcmp(mailbox, "INBOX") == 0;
 	for (; ns != NULL; ns = ns->alias_chain_next) {
-		vname = convert_inbox ? ns->prefix :
-			mail_namespace_get_vname(ns, ctx->vname, mailbox);
-		if (fts_mailbox_get_virtual_uid(ctx->box, vname, uidvalidity,
-						*uid, uid))
+		T_BEGIN {
+			const char *vname = convert_inbox ? ns->prefix :
+				mailbox_list_get_vname(ns->list, mailbox);
+			ret = fts_mailbox_get_virtual_uid(ctx->box, vname,
+							  uidvalidity,
+							  *uid, uid);
+		} T_END;
+		if (ret)
 			return TRUE;
 	}
 	return FALSE;
@@ -868,7 +864,6 @@
 		memset(&uid_map_ctx, 0, sizeof(uid_map_ctx));
 		uid_map_ctx.backend = ctx->backend;
 		uid_map_ctx.box = box;
-		uid_map_ctx.vname = t_str_new(256);
 		return solr_connection_select(solr_conn, str_c(str),
 					      solr_virtual_uid_map,
 					      &uid_map_ctx,
--- a/src/plugins/fts/fts-storage.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/plugins/fts/fts-storage.c	Thu Jan 20 20:59:07 2011 +0200
@@ -12,6 +12,7 @@
 #include "mail-namespace.h"
 #include "mail-search-build.h"
 #include "mail-storage-private.h"
+#include "mailbox-list-private.h"
 #include "fts-api-private.h"
 #include "fts-mailbox.h"
 #include "fts-storage.h"
@@ -348,13 +349,10 @@
 	int ret;
 
 	T_BEGIN {
-		string_t *tmp1, *tmp2;
 		const char *vname1, *vname2;
 
-		tmp1 = t_str_new(128);
-		tmp2 = t_str_new(128);
-		vname1 = mail_namespace_get_vname(box1->ns, tmp1, box1->name);
-		vname2 = mail_namespace_get_vname(box2->ns, tmp2, box2->name);
+		vname1 = mailbox_list_get_vname(box1->ns->list, box1->name);
+		vname2 = mailbox_list_get_vname(box2->ns->list, box2->name);
 		ret = strcmp(vname1, vname2);
 	} T_END;
 	return ret;
@@ -374,8 +372,6 @@
 	const struct fts_orig_mailboxes *boxes;
 	const struct fts_backend_uid_map *last_uids;
 	unsigned int boxi, uidi, box_count, last_uid_count;
-	const char *vname;
-	string_t *tmp;
 	int ret, vret = 0;
 
 	if (vctx->pool == NULL)
@@ -387,13 +383,16 @@
 	boxes = array_get(&vctx->orig_mailboxes, &box_count);
 	last_uids = array_get(&vctx->last_uids, &last_uid_count);
 
-	tmp = t_str_new(256);
 	boxi = vctx->boxi;
 	uidi = vctx->uidi;
 	while (vret == 0 && boxi < box_count && uidi < last_uid_count) {
-		vname = mail_namespace_get_vname(boxes[boxi].ns, tmp,
-						 boxes[boxi].name);
-		ret = strcmp(vname, last_uids[uidi].mailbox);
+		T_BEGIN {
+			const char *vname;
+
+			vname = mailbox_list_get_vname(boxes[boxi].ns->list,
+						       boxes[boxi].name);
+			ret = strcmp(vname, last_uids[uidi].mailbox);
+		} T_END;
 		if (ret == 0) {
 			/* match. check also that uidvalidity matches. */
 			mailbox_get_open_status(boxes[boxi].box,
--- a/src/plugins/imap-acl/imap-acl-plugin.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/plugins/imap-acl/imap-acl-plugin.c	Thu Jan 20 20:59:07 2011 +0200
@@ -57,7 +57,6 @@
 {
 	struct mail_namespace *ns;
 	struct mailbox *box;
-	const char *storage_name;
 	int ret;
 
 	if (ACL_USER_CONTEXT(cmd->client->user) == NULL) {
@@ -65,13 +64,13 @@
 		return NULL;
 	}
 
-	ns = client_find_namespace(cmd, name, &storage_name);
+	ns = client_find_namespace(cmd, &name);
 	if (ns == NULL)
 		return NULL;
 
 	/* Force opening the mailbox so that we can give a nicer error message
 	   if mailbox isn't selectable but is listable. */
-	box = mailbox_alloc(ns->list, storage_name, ACL_MAILBOX_FLAGS |
+	box = mailbox_alloc(ns->list, name, ACL_MAILBOX_FLAGS |
 			    MAILBOX_FLAG_IGNORE_ACLS);
 	ret = acl_mailbox_right_lookup(box, ACL_STORAGE_RIGHT_ADMIN);
 	if (ret > 0)
@@ -308,7 +307,7 @@
 {
 	struct mail_namespace *ns;
 	struct mailbox *box;
-	const char *mailbox, *storage_name;
+	const char *mailbox;
 	const char *const *rights;
 	string_t *str;
 
@@ -320,11 +319,11 @@
 		return TRUE;
 	}
 
-	ns = client_find_namespace(cmd, mailbox, &storage_name);
+	ns = client_find_namespace(cmd, &mailbox);
 	if (ns == NULL)
 		return TRUE;
 
-	box = mailbox_alloc(ns->list, storage_name,
+	box = mailbox_alloc(ns->list, mailbox,
 			    ACL_MAILBOX_FLAGS | MAILBOX_FLAG_IGNORE_ACLS);
 	if (acl_object_get_my_rights(acl_mailbox_get_aclobj(box),
 				     pool_datastack_create(), &rights) < 0) {
--- a/src/plugins/imap-quota/imap-quota-plugin.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/plugins/imap-quota/imap-quota-plugin.c	Thu Jan 20 20:59:07 2011 +0200
@@ -74,14 +74,14 @@
 	struct mailbox *box;
 	struct quota_root_iter *iter;
         struct quota_root *root;
-	const char *mailbox, *storage_name, *name;
+	const char *mailbox, *name;
 	string_t *quotaroot_reply, *quota_reply;
 
 	/* <mailbox> */
 	if (!client_read_string_args(cmd, 1, &mailbox))
 		return FALSE;
 
-	ns = client_find_namespace(cmd, mailbox, &storage_name);
+	ns = client_find_namespace(cmd, &mailbox);
 	if (ns == NULL)
 		return TRUE;
 
@@ -95,7 +95,7 @@
 		return TRUE;
 	}
 
-	box = mailbox_alloc(ns->list, storage_name, MAILBOX_FLAG_READONLY |
+	box = mailbox_alloc(ns->list, mailbox, MAILBOX_FLAG_READONLY |
 			    MAILBOX_FLAG_KEEP_RECENT);
 
 	/* build QUOTAROOT reply and QUOTA reply for all quota roots */
--- a/src/plugins/listescape/listescape-plugin.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/plugins/listescape/listescape-plugin.c	Thu Jan 20 20:59:07 2011 +0200
@@ -13,38 +13,25 @@
 
 #define DEFAULT_ESCAPE_CHAR '\\'
 
-#define LIST_ESCAPE_CONTEXT(obj) \
-	MODULE_CONTEXT(obj, listescape_storage_module)
 #define LIST_ESCAPE_LIST_CONTEXT(obj) \
 	MODULE_CONTEXT(obj, listescape_list_module)
 
-struct listescape_mail_storage {
-	union mail_storage_module_context module_ctx;
-};
-
-struct listescape_mailbox_list_iter {
-	struct mailbox_list_iterate_context *ctx;
-	string_t *name;
-	struct mailbox_info info;
-};
-
 struct listescape_mailbox_list {
 	union mailbox_list_module_context module_ctx;
-	ARRAY_DEFINE(iters, struct listescape_mailbox_list_iter);
 	char escape_char;
 };
 
 const char *listescape_plugin_version = DOVECOT_VERSION;
 
-static MODULE_CONTEXT_DEFINE_INIT(listescape_storage_module,
-				  &mail_storage_module_register);
 static MODULE_CONTEXT_DEFINE_INIT(listescape_list_module,
 				  &mailbox_list_module_register);
 
 static const char *
 list_escape(struct listescape_mailbox_list *mlist,
-	    struct mail_namespace *ns, const char *str, bool vname)
+	    struct mail_namespace *ns, const char *str)
 {
+	char ns_sep = mail_namespace_get_sep(ns);
+	char list_sep = mailbox_list_get_hierarchy_sep(ns->list);
 	string_t *esc = t_str_new(64);
 	unsigned int i;
 
@@ -55,7 +42,7 @@
 	if (i > ns->prefix_len)
 		i = ns->prefix_len;
 
-	if (vname && i > 0 && strncmp(ns->prefix, str, i) == 0) {
+	if (i > 0 && strncmp(ns->prefix, str, i) == 0) {
 		str_append_n(esc, str, i);
 		str += i;
 	}
@@ -65,13 +52,10 @@
 		str++;
 	}
 	for (; *str != '\0'; str++) {
-		if (*str == ns->sep) {
-			if (!vname)
-				str_append_c(esc, ns->list->hierarchy_sep);
-			else
-				str_append_c(esc, *str);
-		} else if (*str == ns->list->hierarchy_sep ||
-			   *str == mlist->escape_char || *str == '/')
+		if (*str == ns_sep)
+			str_append_c(esc, *str);
+		else if (*str == list_sep ||
+			 *str == mlist->escape_char || *str == '/')
 			str_printfa(esc, "%c%02x", mlist->escape_char, *str);
 		else
 			str_append_c(esc, *str);
@@ -79,10 +63,13 @@
 	return str_c(esc);
 }
 
-static void list_unescape_str(struct listescape_mailbox_list *mlist,
-			      struct mail_namespace *ns,
-			      const char *str, string_t *dest)
+static const char *
+list_unescape(struct listescape_mailbox_list *mlist,
+	      struct mail_namespace *ns, const char *str)
 {
+	char ns_sep = mail_namespace_get_sep(ns);
+	char list_sep = mailbox_list_get_hierarchy_sep(ns->list);
+	string_t *dest = t_str_new(strlen(str));
 	unsigned int num;
 
 	for (; *str != '\0'; str++) {
@@ -100,220 +87,31 @@
 
 			str_append_c(dest, num);
 			str += 2;
-		} else if (*str == ns->list->hierarchy_sep)
-			str_append_c(dest, ns->sep);
+		} else if (*str == list_sep)
+			str_append_c(dest, ns_sep);
 		else
 			str_append_c(dest, *str);
 	}
-}
-
-static struct mail_namespace *
-listescape_find_orig_ns(struct mail_namespace *parent_ns, const char *name)
-{
-	struct mail_namespace *ns, *best = NULL;
-
-	for (ns = parent_ns->user->namespaces; ns != NULL; ns = ns->next) {
-		if ((ns->flags & NAMESPACE_FLAG_SUBSCRIPTIONS) != 0)
-			continue;
-
-		if (strncmp(ns->prefix, parent_ns->prefix,
-			    parent_ns->prefix_len) == 0 &&
-		    strncmp(ns->prefix + parent_ns->prefix_len, name,
-			    ns->prefix_len) == 0) {
-			if (best == NULL || ns->prefix_len > best->prefix_len)
-				best = ns;
-		}
-	}
-	return best != NULL ? best : parent_ns;
-}
-
-static const char *const *
-iter_escape_patterns(struct mailbox_list *list,
-		     const char *const *patterns,
-		     enum mailbox_list_iter_flags flags)
-{
-	struct listescape_mailbox_list *mlist = LIST_ESCAPE_LIST_CONTEXT(list);
-	struct mail_namespace *orig_ns;
-	const char **escaped_patterns;
-	unsigned int i;
-
-	escaped_patterns = t_new(const char *, str_array_length(patterns) + 1);
-	for (i = 0; patterns[i] != NULL; i++) {
-		if ((flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) != 0) {
-			/* we may be listing subscriptions for other namespaces
-			   prefixes. don't escape characters in the namespace
-			   prefixes. */
-			orig_ns = listescape_find_orig_ns(list->ns,
-							  patterns[i]);
-		} else {
-			orig_ns = list->ns;
-		}
-		escaped_patterns[i] = list_escape(mlist, orig_ns,
-						  patterns[i], TRUE);
-	}
-	return escaped_patterns;
-}
-
-static struct mailbox_list_iterate_context *
-listescape_mailbox_list_iter_init(struct mailbox_list *list,
-				  const char *const *patterns,
-				  enum mailbox_list_iter_flags flags)
-{
-	struct listescape_mailbox_list *mlist = LIST_ESCAPE_LIST_CONTEXT(list);
-	struct mailbox_list_iterate_context *ctx;
-	struct listescape_mailbox_list_iter *liter;
-
-	/* this is kind of kludgy. In ACL code we want to convert patterns,
-	   in maildir renaming code we don't. so for now just use the _RAW_LIST
-	   flag.. */
-	if ((flags & MAILBOX_LIST_ITER_RAW_LIST) == 0)
-		patterns = iter_escape_patterns(list, patterns, flags);
-
-	/* Listing breaks if ns->real_sep isn't correct, but with everything
-	   else we need real_sep == virtual_sep. maybe some day lib-storage
-	   API gets changed so that it sees only virtual mailbox names and
-	   convers them internally and we don't have this problem. */
-	list->ns->real_sep = list->hierarchy_sep;
-	ctx = mlist->module_ctx.super.iter_init(list, patterns, flags);
-	list->ns->real_sep = list->ns->sep;
-
-	liter = array_append_space(&mlist->iters);
-	liter->ctx = ctx;
-	liter->name = str_new(default_pool, 256);
-	return ctx;
-}
-
-static struct listescape_mailbox_list_iter *
-listescape_mailbox_list_iter_find(struct listescape_mailbox_list *mlist,
-				 struct mailbox_list_iterate_context *ctx)
-{
-	struct listescape_mailbox_list_iter *liter;
-
-	array_foreach_modifiable(&mlist->iters, liter) {
-		if (liter->ctx == ctx)
-			return liter;
-	}
-	return NULL;
+	return str_c(dest);
 }
 
-static const struct mailbox_info *
-listescape_mailbox_list_iter_next(struct mailbox_list_iterate_context *ctx)
+static const char *listescape_list_get_vname(struct mailbox_list *list,
+					     const char *storage_name)
 {
-	struct listescape_mailbox_list *mlist =
-		LIST_ESCAPE_LIST_CONTEXT(ctx->list);
-	struct mail_namespace *ns;
-	struct listescape_mailbox_list_iter *liter;
-	const struct mailbox_info *info;
-
-	liter = listescape_mailbox_list_iter_find(mlist, ctx);
-	i_assert(liter != NULL);
+	struct listescape_mailbox_list *mlist = LIST_ESCAPE_LIST_CONTEXT(list);
+	const char *vname;
 
-	ctx->list->ns->real_sep = ctx->list->hierarchy_sep;
-	info = mlist->module_ctx.super.iter_next(ctx);
-	ctx->list->ns->real_sep = ctx->list->ns->sep;
-	if (info == NULL)
-		return info;
-
-	ns = (ctx->flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) == 0 ?
-		ctx->list->ns :
-		listescape_find_orig_ns(ctx->list->ns, info->name);
-
-	if ((ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0 &&
-	    strcasecmp(info->name, "INBOX") == 0)
-		return info;
-
-	str_truncate(liter->name, 0);
-	str_append(liter->name, ns->prefix);
-	list_unescape_str(mlist, ns, info->name + ns->prefix_len, liter->name);
-	liter->info = *info;
-	liter->info.name = str_c(liter->name);
-	return &liter->info;
+	vname = mlist->module_ctx.super.get_vname(list, storage_name);
+	return list_unescape(mlist, list->ns, vname);
 }
 
-static int
-listescape_mailbox_list_iter_deinit(struct mailbox_list_iterate_context *ctx)
-{
-	struct mailbox_list *list = ctx->list;
-	struct listescape_mailbox_list *mlist =
-		LIST_ESCAPE_LIST_CONTEXT(ctx->list);
-	struct listescape_mailbox_list_iter *liters;
-	unsigned int i, count;
-	int ret;
-
-	liters = array_get_modifiable(&mlist->iters, &count);
-	for (i = 0; i < count; i++) {
-		if (liters[i].ctx == ctx) {
-			str_free(&liters[i].name);
-			array_delete(&mlist->iters, i, 1);
-		}
-	}
-
-	list->ns->real_sep = list->hierarchy_sep;
-	ret = mlist->module_ctx.super.iter_deinit(ctx);
-	list->ns->real_sep = list->ns->sep;
-	return ret;
-}
-
-static struct mailbox *
-listescape_mailbox_alloc(struct mail_storage *storage,
-			 struct mailbox_list *list,
-			 const char *name, enum mailbox_flags flags)
-{
-	struct listescape_mail_storage *mstorage = LIST_ESCAPE_CONTEXT(storage);
-	struct listescape_mailbox_list *mlist = LIST_ESCAPE_LIST_CONTEXT(list);
-
-	if (list->hierarchy_sep != list->ns->sep)
-		name = list_escape(mlist, list->ns, name, FALSE);
-	return mstorage->module_ctx.super.
-		mailbox_alloc(storage, list, name, flags);
-}
-
-static int listescape_set_subscribed(struct mailbox_list *list, 
-				     const char *name, bool set)
-{
-	struct listescape_mailbox_list *mlist = LIST_ESCAPE_LIST_CONTEXT(list);
-	struct mail_namespace *ns;
-	const char *esc_name;
-
-	ns = listescape_find_orig_ns(list->ns, name);
-	if (ns == list->ns || strncmp(ns->prefix, name, ns->prefix_len) != 0)
-		name = list_escape(mlist, ns, name, FALSE);
-	else {
-		esc_name = list_escape(mlist, ns, name + ns->prefix_len, FALSE);
-		name = t_strconcat(ns->prefix, esc_name, NULL);
-	}
-	return mlist->module_ctx.super.set_subscribed(list, name, set);
-}
-
-static bool listescape_is_valid_existing_name(struct mailbox_list *list,
-					      const char *name)
+static const char *listescape_list_get_storage_name(struct mailbox_list *list,
+						    const char *vname)
 {
 	struct listescape_mailbox_list *mlist = LIST_ESCAPE_LIST_CONTEXT(list);
 
-	name = list_escape(mlist, list->ns, name, FALSE);
-	return mlist->module_ctx.super.is_valid_existing_name(list, name);
-}
-
-static bool listescape_is_valid_create_name(struct mailbox_list *list,
-					    const char *name)
-{
-	struct listescape_mailbox_list *mlist = LIST_ESCAPE_LIST_CONTEXT(list);
-
-	name = list_escape(mlist, list->ns, name, FALSE);
-	return mlist->module_ctx.super.is_valid_create_name(list, name);
-}
-
-static void listescape_mail_storage_created(struct mail_storage *storage)
-{
-	struct listescape_mail_storage *mstorage;
-	struct mail_storage_vfuncs *v = storage->vlast;
-
-	mstorage = p_new(storage->pool, struct listescape_mail_storage, 1);
-	mstorage->module_ctx.super = *v;
-	storage->vlast = &mstorage->module_ctx.super;
-	v->mailbox_alloc = listescape_mailbox_alloc;
-
-	MODULE_CONTEXT_SET(storage, listescape_storage_module, mstorage);
+	return mlist->module_ctx.super.
+		get_storage_name(list, list_escape(mlist, list->ns, vname));
 }
 
 static void listescape_mailbox_list_created(struct mailbox_list *list)
@@ -321,22 +119,17 @@
 	struct mailbox_list_vfuncs *v = list->vlast;
 	struct listescape_mailbox_list *mlist;
 	const char *env;
+	char ns_sep = mail_namespace_get_sep(list->ns);
+	char list_sep = mailbox_list_get_hierarchy_sep(list);
 
-	if (list->hierarchy_sep == list->ns->sep)
+	if (list_sep == ns_sep)
 		return;
 
-	list->ns->real_sep = list->ns->sep;
-
 	mlist = p_new(list->pool, struct listescape_mailbox_list, 1);
 	mlist->module_ctx.super = *v;
 	list->vlast = &mlist->module_ctx.super;
-	p_array_init(&mlist->iters, list->pool, 4);
-	v->iter_init = listescape_mailbox_list_iter_init;
-	v->iter_next = listescape_mailbox_list_iter_next;
-	v->iter_deinit = listescape_mailbox_list_iter_deinit;
-	v->set_subscribed = listescape_set_subscribed;
-	v->is_valid_existing_name = listescape_is_valid_existing_name;
-	v->is_valid_create_name = listescape_is_valid_create_name;
+	v->get_vname = listescape_list_get_vname;
+	v->get_storage_name = listescape_list_get_storage_name;
 
 	env = mail_user_plugin_getenv(list->ns->user, "listescape_char");
 	mlist->escape_char = env != NULL && *env != '\0' ?
@@ -346,7 +139,6 @@
 }
 
 static struct mail_storage_hooks listescape_mail_storage_hooks = {
-	.mail_storage_created = listescape_mail_storage_created,
 	.mailbox_list_created = listescape_mailbox_list_created
 };
 
--- a/src/plugins/quota/quota-count.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/plugins/quota/quota-count.c	Thu Jan 20 20:59:07 2011 +0200
@@ -17,20 +17,17 @@
 	struct mail_search_context *ctx;
 	struct mail *mail;
 	struct mail_search_args *search_args;
-	const char *storage_name;
 	enum mail_error error;
 	uoff_t size;
 	int ret = 0;
 
-	storage_name = mail_namespace_get_storage_name(ns, vname);
-
 	rule = quota_root_rule_find(root->set, vname);
 	if (rule != NULL && rule->ignore) {
 		/* mailbox not included in quota */
 		return 0;
 	}
 
-	box = mailbox_alloc(ns->list, storage_name,
+	box = mailbox_alloc(ns->list, vname,
 			    MAILBOX_FLAG_READONLY | MAILBOX_FLAG_KEEP_RECENT);
 	if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FULL_READ) < 0) {
 		error = mailbox_get_last_mail_error(box);
--- a/src/plugins/quota/quota-maildir.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/plugins/quota/quota-maildir.c	Thu Jan 20 20:59:07 2011 +0200
@@ -10,6 +10,7 @@
 #include "write-full.h"
 #include "str.h"
 #include "maildir-storage.h"
+#include "mailbox-list-private.h"
 #include "quota-private.h"
 
 #include <stdio.h>
@@ -157,8 +158,8 @@
 		T_BEGIN {
 			const char *path, *storage_name;
 
-			storage_name = mail_namespace_get_storage_name(
-				ctx->info->ns, ctx->info->name);
+			storage_name = mailbox_list_get_storage_name(
+				ctx->info->ns->list, ctx->info->name);
 			path = mailbox_list_get_path(ctx->list, storage_name,
 					MAILBOX_LIST_PATH_TYPE_MAILBOX);
 			str_truncate(ctx->path, 0);
@@ -619,7 +620,6 @@
 {
 	struct mailbox_list *list;
 	struct mail_storage *storage;
-	const char *name = "";
 
 	if (root->limits_initialized)
 		return root->maildirsize_path != NULL;
@@ -632,7 +632,7 @@
 	i_assert(root->maildirsize_path != NULL);
 
 	list = root->maildirsize_ns->list;
-	if (mailbox_list_get_storage(&list, &name, &storage) == 0 &&
+	if (mailbox_list_get_storage(&list, "", &storage) == 0 &&
 	    strcmp(storage->name, MAILDIR_STORAGE_NAME) != 0) {
 		/* non-maildir namespace, skip */
 		if ((storage->class_flags &
--- a/src/plugins/quota/quota-storage.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/plugins/quota/quota-storage.c	Thu Jan 20 20:59:07 2011 +0200
@@ -561,7 +561,7 @@
 
 	array_foreach(&root->set->rules, rule) {
 		name = rule->mailbox_name;
-		if (mail_namespace_find(namespaces, &name) == NULL)
+		if (mail_namespace_find(namespaces, name) == NULL)
 			i_error("quota: Unknown namespace: %s", name);
 	}
 }
--- a/src/plugins/quota/quota.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/plugins/quota/quota.c	Thu Jan 20 20:59:07 2011 +0200
@@ -761,10 +761,9 @@
 {
 	struct mailbox_list *list = ns->list;
 	struct mail_storage *storage;
-	const char *name = "";
 
 	/* this check works as long as there is only one storage per list */
-	if (mailbox_list_get_storage(&list, &name, &storage) == 0 &&
+	if (mailbox_list_get_storage(&list, "", &storage) == 0 &&
 	    (storage->class_flags & MAIL_STORAGE_CLASS_FLAG_NOQUOTA) != 0)
 		return FALSE;
 
--- a/src/plugins/snarf/snarf-plugin.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/plugins/snarf/snarf-plugin.c	Thu Jan 20 20:59:07 2011 +0200
@@ -125,7 +125,7 @@
 	if (snarf_name == NULL)
 		return FALSE;
 
-	snarf_ns = mail_namespace_find(user->namespaces, &snarf_name);
+	snarf_ns = mail_namespace_find(user->namespaces, snarf_name);
 	if (snarf_ns == NULL) {
 		i_error("snarf: Namespace not found for mailbox: %s",
 			snarf_name);
@@ -166,8 +166,8 @@
 
 static struct mailbox *
 snarf_mailbox_alloc(struct mail_storage *storage,
-		    struct mailbox_list *list, const char *name,
-		    enum mailbox_flags flags)
+		    struct mailbox_list *list,
+		    const char *vname, enum mailbox_flags flags)
 {
 	struct snarf_mail_storage *sstorage = SNARF_CONTEXT(storage);
 	struct mail_namespace *ns = mailbox_list_get_namespace(list);
@@ -176,7 +176,7 @@
 	const char *snarf_name;
 	struct stat st;
 
-	if (strcmp(name, "INBOX") == 0 &&
+	if (strcmp(vname, "INBOX") == 0 &&
 	    (ns->flags & NAMESPACE_FLAG_INBOX_USER) != 0) {
 		if (stat(sstorage->snarf_path, &st) == 0)
 			sstorage->snarfing_disabled = FALSE;
@@ -191,13 +191,13 @@
 			if (snarf_box_find(storage->user, &snarf_list,
 					   &snarf_name)) {
 				list = snarf_list;
-				name = snarf_name;
+				vname = snarf_name;
 			}
 		}
 	}
 
 	box = sstorage->module_ctx.super.
-		mailbox_alloc(storage, list, name, flags);
+		mailbox_alloc(storage, list, vname, flags);
 	if (sstorage->snarfing_disabled) {
 		box->inbox_user = TRUE;
 		box->inbox_any = TRUE;
--- a/src/plugins/trash/trash-plugin.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/plugins/trash/trash-plugin.c	Thu Jan 20 20:59:07 2011 +0200
@@ -225,16 +225,11 @@
 			       struct trash_mailbox *trash)
 {
 	struct mail_namespace *ns;
-	const char *name;
 
-	for (ns = user->namespaces; ns != NULL; ns = ns->next) {
-		name = trash->name;
-		if (mail_namespace_update_name(ns, &name)) {
-			if (name != trash->name)
-				trash->name = p_strdup(user->pool, name);
-			trash->ns = ns;
-			return TRUE;
-		}
+	ns = mail_namespace_find(user->namespaces, trash->name);
+	if (ns != NULL) {
+		trash->ns = ns;
+		return TRUE;
 	}
 	return FALSE;
 }
--- a/src/plugins/virtual/virtual-config.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/plugins/virtual/virtual-config.c	Thu Jan 20 20:59:07 2011 +0200
@@ -135,7 +135,7 @@
 	if (*line == '-' || *line == '!') line++;
 	bbox->ns = strcasecmp(line, "INBOX") == 0 ?
 		mail_namespace_find_inbox(user->namespaces) :
-		mail_namespace_find(user->namespaces, &line);
+		mail_namespace_find(user->namespaces, line);
 	if (bbox->ns == NULL) {
 		*error_r = t_strdup_printf("Namespace not found for %s",
 					   bbox->name);
--- a/src/plugins/virtual/virtual-storage.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/plugins/virtual/virtual-storage.c	Thu Jan 20 20:59:07 2011 +0200
@@ -49,7 +49,8 @@
 		return box->vname;
 	else {
 		return t_strdup_printf("<hidden>%c%s",
-				       box->list->hierarchy_sep, box->name);
+				       mail_namespace_get_sep(box->list->ns),
+				       box->vname);
 	}
 }
 
@@ -176,7 +177,7 @@
 	flags |= MAILBOX_FLAG_KEEP_RECENT;
 
 	mailbox = bbox->name;
-	ns = mail_namespace_find(user->namespaces, &mailbox);
+	ns = mail_namespace_find(user->namespaces, mailbox);
 	bbox->box = mailbox_alloc(ns->list, mailbox, flags);
 
 	if (mailbox_open(bbox->box) < 0)
@@ -221,7 +222,7 @@
 
 static struct mailbox *
 virtual_mailbox_alloc(struct mail_storage *_storage, struct mailbox_list *list,
-		      const char *name, enum mailbox_flags flags)
+		      const char *vname, enum mailbox_flags flags)
 {
 	struct virtual_storage *storage = (struct virtual_storage *)_storage;
 	struct virtual_mailbox *mbox;
@@ -236,7 +237,7 @@
 	mbox->box.mail_vfuncs = &virtual_mail_vfuncs;
 	mbox->vfuncs = virtual_mailbox_vfuncs;
 
-	index_storage_mailbox_alloc(&mbox->box, name, flags,
+	index_storage_mailbox_alloc(&mbox->box, vname, flags,
 				    VIRTUAL_INDEX_PREFIX);
 
 	mbox->storage = storage;
--- a/src/pop3/pop3-client.c	Thu Jan 20 19:21:20 2011 +0200
+++ b/src/pop3/pop3-client.c	Thu Jan 20 20:59:07 2011 +0200
@@ -236,7 +236,7 @@
 {
 	struct mail_namespace *ns;
 	struct mail_storage *storage;
-	const char *inbox, *ident;
+	const char *ident;
 	struct client *client;
         enum mailbox_flags flags;
 	const char *errmsg;
@@ -269,8 +269,7 @@
 	pop3_client_count++;
 	DLLIST_PREPEND(&pop3_clients, client);
 
-	inbox = "INBOX";
-	ns = mail_namespace_find(user->namespaces, &inbox);
+	ns = mail_namespace_find(user->namespaces, "INBOX");
 	if (ns == NULL) {
 		client_send_line(client, "-ERR No INBOX namespace for user.");
 		client_destroy(client, "No INBOX namespace for user.");