changeset 6639:e1fde9940f7e HEAD

Fixes to handling namespace prefixes and real!=virtual separator. Added a new MAILBOX_LIST_ITER_VIRTUAL_NAMES which specifies if mailbox listing should be using virtual or real mailbox names.
author Timo Sirainen <tss@iki.fi>
date Sun, 28 Oct 2007 01:53:32 +0300
parents e2a4722f1b9b
children 7f2501b3e993
files src/imap/cmd-list.c src/lib-storage/list/mailbox-list-fs-iter.c src/lib-storage/list/mailbox-list-maildir-iter.c src/lib-storage/list/mailbox-list-subscriptions.c src/lib-storage/mail-namespace.c src/lib-storage/mail-namespace.h src/lib-storage/mailbox-list-private.h src/lib-storage/mailbox-list.c src/lib-storage/mailbox-list.h src/plugins/acl/acl-mailbox-list.c
diffstat 10 files changed, 215 insertions(+), 183 deletions(-) [+]
line wrap: on
line diff
--- a/src/imap/cmd-list.c	Sun Oct 28 01:52:00 2007 +0300
+++ b/src/imap/cmd-list.c	Sun Oct 28 01:53:32 2007 +0300
@@ -819,14 +819,15 @@
 		args += 2;
 	}
 
+	ctx->list_flags = MAILBOX_LIST_ITER_VIRTUAL_NAMES;
 	if (lsub) {
 		/* LSUB - we don't care about flags */
-		ctx->list_flags = MAILBOX_LIST_ITER_SELECT_SUBSCRIBED |
+		ctx->list_flags |= MAILBOX_LIST_ITER_SELECT_SUBSCRIBED |
 			MAILBOX_LIST_ITER_SELECT_RECURSIVEMATCH |
 			MAILBOX_LIST_ITER_RETURN_NO_FLAGS;
 	} else if (!ctx->used_listext) {
 		/* non-extended LIST - return children flags always */
-		ctx->list_flags = MAILBOX_LIST_ITER_RETURN_CHILDREN;
+		ctx->list_flags |= MAILBOX_LIST_ITER_RETURN_CHILDREN;
 	}
 
 	if (args[0].type != IMAP_ARG_EOL) {
--- a/src/lib-storage/list/mailbox-list-fs-iter.c	Sun Oct 28 01:52:00 2007 +0300
+++ b/src/lib-storage/list/mailbox-list-fs-iter.c	Sun Oct 28 01:53:32 2007 +0300
@@ -30,6 +30,7 @@
 	struct imap_match_glob *glob;
 	struct mailbox_tree_context *subs_tree;
 	struct mailbox_tree_iterate_context *tree_iter;
+	char sep;
 
 	enum mailbox_info_flags inbox_flags;
 
@@ -50,19 +51,19 @@
 fs_list_next(struct fs_list_iterate_context *ctx);
 
 static int
-pattern_get_path_pos(struct mail_namespace *ns, const char *pattern,
+pattern_get_path_pos(struct fs_list_iterate_context *ctx, const char *pattern,
 		     const char *path, unsigned int *pos_r)
 {
 	unsigned int i, j;
 
-	if (strncasecmp(path, "INBOX", 5) == 0 && path[5] == ns->sep) {
+	if (strncasecmp(path, "INBOX", 5) == 0 && path[5] == ctx->sep) {
 		/* make sure INBOX prefix is matched case-insensitively */
 		char *tmp = t_strdup_noconst(pattern);
 
 		if (strncmp(path, "INBOX", 5) != 0)
-			path = t_strdup_printf("INBOX%c%s", ns->sep, path + 6);
+			path = t_strdup_printf("INBOX%c%s", ctx->sep, path + 6);
 
-		for (i = 0; tmp[i] != ns->sep && tmp[i] != '\0'; i++)
+		for (i = 0; tmp[i] != ctx->sep && tmp[i] != '\0'; i++)
 			tmp[i] = i_toupper(tmp[i]);
 		pattern = tmp;
 	}
@@ -73,13 +74,13 @@
 
 		if (pattern[j] == '%') {
 			/* skip until we're at the next hierarchy separator */
-			if (path[i] == ns->sep) {
+			if (path[i] == ctx->sep) {
 				/* assume that pattern matches. we can't be
 				   sure, but it'll be checked later. */
 				for (j++; pattern[j] != '\0'; j++) {
 					if (pattern[j] == '*')
 						return -1;
-					if (pattern[j] == ns->sep) {
+					if (pattern[j] == ctx->sep) {
 						j++;
 						break;
 					}
@@ -98,18 +99,18 @@
 }
 
 static bool
-pattern_has_wildcard_at(struct mail_namespace *ns, const char *pattern,
-			const char *path)
+pattern_has_wildcard_at(struct fs_list_iterate_context *ctx,
+			const char *pattern, const char *path)
 {
 	unsigned int pos;
 	int ret;
 
-	if ((ret = pattern_get_path_pos(ns, pattern, path, &pos)) < 0)
+	if ((ret = pattern_get_path_pos(ctx, pattern, path, &pos)) < 0)
 		return TRUE;
 	if (ret == 0)
 		return FALSE;
 
-	for (; pattern[pos] != '\0' && pattern[pos] != ns->sep; pos++) {
+	for (; pattern[pos] != '\0' && pattern[pos] != ctx->sep; pos++) {
 		if (pattern[pos] == '%' || pattern[pos] == '*')
 			return TRUE;
 	}
@@ -128,8 +129,7 @@
 	t_push();
 	patterns = array_idx(&ctx->valid_patterns, 0);
 	for (i = 0; patterns[i] != NULL; i++) {
-		if (pattern_has_wildcard_at(ctx->ctx.list->ns,
-					    patterns[i], list_path))
+		if (pattern_has_wildcard_at(ctx, patterns[i], list_path))
 			break;
 	}
 	t_pop();
@@ -164,7 +164,7 @@
 		  enum mailbox_list_iter_flags flags)
 {
 	struct fs_list_iterate_context *ctx;
-	const char *path;
+	const char *path, *vpath;
 	char *pattern;
 	DIR *dirp;
 	int ret;
@@ -174,6 +174,8 @@
 	ctx->ctx.flags = flags;
 	ctx->info_pool = pool_alloconly_create("fs list", 1024);
 	ctx->next = fs_list_next;
+	ctx->sep = (flags & MAILBOX_LIST_ITER_VIRTUAL_NAMES) != 0 ?
+		_list->ns->sep : _list->ns->real_sep;
 
 	i_array_init(&ctx->valid_patterns, 8);
 	for (; *patterns != NULL; patterns++) {
@@ -195,15 +197,14 @@
 	}
 	patterns = (const void *)array_idx(&ctx->valid_patterns, 0);
 	ctx->glob = imap_match_init_multiple(default_pool, patterns, TRUE,
-					     _list->ns->sep);
+					     ctx->sep);
 
 	if ((flags & (MAILBOX_LIST_ITER_SELECT_SUBSCRIBED |
 		      MAILBOX_LIST_ITER_RETURN_SUBSCRIBED)) != 0) {
 		/* we want to return MAILBOX_SUBSCRIBED flags, possibly for all
 		   mailboxes. Build a mailbox tree of all the subscriptions. */
-		ctx->subs_tree = mailbox_tree_init(_list->ns->sep);
-		if (mailbox_list_subscriptions_fill(&ctx->ctx,
-						    ctx->subs_tree,
+		ctx->subs_tree = mailbox_tree_init(ctx->sep);
+		if (mailbox_list_subscriptions_fill(&ctx->ctx, ctx->subs_tree,
 						    ctx->glob, FALSE) < 0) {
 			ctx->ctx.failed = TRUE;
 			return &ctx->ctx;
@@ -217,15 +218,17 @@
 		return &ctx->ctx;
 	}
 
+	vpath = (flags & MAILBOX_LIST_ITER_VIRTUAL_NAMES) != 0 ?
+		_list->ns->prefix : "";
 	path = mailbox_list_get_path(_list, NULL, MAILBOX_LIST_PATH_TYPE_DIR);
-	if ((ret = list_opendir(ctx, path, _list->ns->prefix, &dirp)) < 0)
+	if ((ret = list_opendir(ctx, path, vpath, &dirp)) < 0)
 		return &ctx->ctx;
 
 	if (ret > 0) {
 		ctx->dir = i_new(struct list_dir_context, 1);
 		ctx->dir->dirp = dirp;
 		ctx->dir->real_path = i_strdup(path);
-		ctx->dir->virtual_path = i_strdup(_list->ns->prefix);
+		ctx->dir->virtual_path = i_strdup(vpath);
 	}
 	return &ctx->ctx;
 }
@@ -411,7 +414,7 @@
 
 	if ((ctx->info.flags & MAILBOX_NOINFERIORS) == 0) {
 		/* subdirectory. scan inside it. */
-		vpath = t_strdup_printf("%s%c", list_path, ns->sep);
+		vpath = t_strdup_printf("%s%c", list_path, ctx->sep);
 		match2 = imap_match(ctx->glob, vpath);
 
 		if (match == IMAP_MATCH_YES)
@@ -428,7 +431,7 @@
 			dir->dirp = dirp;
 			dir->real_path = i_strdup(real_path);
 			dir->virtual_path =
-				i_strdup_printf("%s%c", list_path, ns->sep);
+				i_strdup_printf("%s%c", list_path, ctx->sep);
 
 			dir->prev = ctx->dir;
 			ctx->dir = dir;
@@ -480,7 +483,6 @@
 static struct dirent *fs_list_dir_next(struct fs_list_iterate_context *ctx)
 {
 	struct list_dir_context *dir = ctx->dir;
-	struct mail_namespace *ns = ctx->ctx.list->ns;
 	char *const *patterns;
 	const char *fname, *path, *p;
 	unsigned int pos;
@@ -501,14 +503,14 @@
 		patterns += dir->pattern_pos;
 		dir->pattern_pos++;
 
-		ret = pattern_get_path_pos(ns, *patterns, dir->virtual_path,
+		ret = pattern_get_path_pos(ctx, *patterns, dir->virtual_path,
 					   &pos);
 		if (ret == 0)
 			continue;
 		i_assert(ret > 0);
 
 		/* get the filename from the pattern */
-		p = strchr(*patterns + pos, ns->sep);
+		p = strchr(*patterns + pos, ctx->sep);
 		fname = p == NULL ? *patterns + pos :
 			t_strdup_until(*patterns + pos, p);
 
--- a/src/lib-storage/list/mailbox-list-maildir-iter.c	Sun Oct 28 01:52:00 2007 +0300
+++ b/src/lib-storage/list/mailbox-list-maildir-iter.c	Sun Oct 28 01:53:32 2007 +0300
@@ -36,30 +36,37 @@
 	}
 }
 
-static void maildir_fill_parents(struct maildir_list_iterate_context *ctx,
-				 struct imap_match_glob *glob, bool update_only,
-				 string_t *mailbox, const char *mailbox_c,
-				 enum mailbox_info_flags flags)
+static void
+maildir_fill_parents(struct maildir_list_iterate_context *ctx,
+		     struct imap_match_glob *glob, bool update_only,
+		     string_t *mailbox, enum mailbox_info_flags flags)
 {
+	struct mail_namespace *ns = ctx->ctx.list->ns;
 	struct mailbox_node *node;
-	const char *p;
+	const char *p, *mailbox_c;
 	char hierarchy_sep;
 	bool created;
-	const char *ns_prefix = ctx->ctx.list->ns->prefix;
-	unsigned int ns_prefix_len = strlen(ns_prefix);
+	unsigned int prefix_len;
 
-	hierarchy_sep = ctx->ctx.list->ns->sep;
+	if ((ctx->ctx.flags & MAILBOX_LIST_ITER_VIRTUAL_NAMES) != 0) {
+		hierarchy_sep = ns->sep;
+		prefix_len = ns->prefix_len;
+	} else {
+		hierarchy_sep = ns->real_sep;
+		prefix_len = 0;
+	}
 
 	t_push();
+	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);
 		if (imap_match(glob, mailbox_c) != IMAP_MATCH_YES)
 			continue;
 
-		if (*ns_prefix != '\0' && str_len(mailbox) == ns_prefix_len-1 &&
-		    strncmp(mailbox_c, ns_prefix, ns_prefix_len - 1) == 0 &&
-		    mailbox_c[ns_prefix_len-1] == hierarchy_sep) {
+		if (prefix_len > 0 && str_len(mailbox) == prefix_len-1 &&
+		    strncmp(mailbox_c, ns->prefix, prefix_len - 1) == 0 &&
+		    mailbox_c[prefix_len-1] == hierarchy_sep) {
 			/* don't return matches to namespace prefix itself */
 			continue;
 		}
@@ -92,14 +99,12 @@
 	DIR *dirp;
 	struct dirent *d;
 	const char *mailbox_name;
-	char *mailbox_c;
 	string_t *mailbox;
 	enum mailbox_info_flags flags;
 	enum imap_match_result match;
 	struct mailbox_node *node;
-	bool created;
+	bool created, virtual_names;
 	char prefix_char;
-	unsigned int pos;
 	int ret;
 
 	dirp = opendir(ctx->dir);
@@ -112,6 +117,7 @@
 		return 0;
 	}
 
+	virtual_names = (ctx->ctx.flags & MAILBOX_LIST_ITER_VIRTUAL_NAMES) != 0;
 	prefix_char =
 		strcmp(ctx->ctx.list->name, MAILBOX_LIST_NAME_IMAPDIR) != 0 ?
 		ctx->ctx.list->hierarchy_sep : '\0';
@@ -134,22 +140,17 @@
 		    (fname[1] == '\0' || (fname[1] == '.' && fname[2] == '\0')))
 			continue;
 
-		/* make sure the pattern matches */
-		str_truncate(mailbox, 0);
-		if ((ns->flags & NAMESPACE_FLAG_INBOX) == 0 ||
-		    strcasecmp(mailbox_name, "INBOX") != 0)
-			str_append(mailbox, ns->prefix);
-
-		pos = str_len(mailbox);
-		str_append(mailbox, mailbox_name);
-		mailbox_c = str_c_modifiable(mailbox);
-		while (mailbox_c[pos] != '\0') {
-			if (mailbox_c[pos] == ns->real_sep)
-				mailbox_c[pos] = ns->sep;
-			pos++;
+		if (!virtual_names) {
+			str_truncate(mailbox, 0);
+			str_append(mailbox, mailbox_name);
+			mailbox_name = str_c(mailbox);
+		} else {
+			mailbox_name = mail_namespace_get_vname(ns, mailbox,
+								mailbox_name);
 		}
 
-		match = imap_match(glob, mailbox_c);
+		/* make sure the pattern matches */
+		match = imap_match(glob, mailbox_name);
 		if ((match & (IMAP_MATCH_YES | IMAP_MATCH_PARENT)) == 0)
 			continue;
 
@@ -172,13 +173,14 @@
 
 		if ((match & IMAP_MATCH_PARENT) != 0) {
 			maildir_fill_parents(ctx, glob, update_only,
-					     mailbox, mailbox_c, flags);
+					     mailbox, flags);
 		} else {
 			created = FALSE;
 			node = update_only ?
-				mailbox_tree_lookup(ctx->tree_ctx, mailbox_c) :
+				mailbox_tree_lookup(ctx->tree_ctx,
+						    mailbox_name) :
 				mailbox_tree_get(ctx->tree_ctx,
-						 mailbox_c, &created);
+						 mailbox_name, &created);
 
 			if (node != NULL) {
 				if (created)
@@ -237,16 +239,20 @@
 {
 	struct maildir_list_iterate_context *ctx;
         struct imap_match_glob *glob;
+	char sep;
 	pool_t pool;
 
+	sep = (flags & MAILBOX_LIST_ITER_VIRTUAL_NAMES) != 0 ?
+		_list->ns->sep : _list->ns->real_sep;
+
 	pool = pool_alloconly_create("maildir_list", 1024);
 	ctx = p_new(pool, struct maildir_list_iterate_context, 1);
 	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(sep);
 
-	glob = imap_match_init_multiple(pool, patterns, TRUE, _list->ns->sep);
+	glob = imap_match_init_multiple(pool, patterns, TRUE, sep);
 
 	ctx->dir = _list->set.root_dir;
 
--- a/src/lib-storage/list/mailbox-list-subscriptions.c	Sun Oct 28 01:52:00 2007 +0300
+++ b/src/lib-storage/list/mailbox-list-subscriptions.c	Sun Oct 28 01:53:32 2007 +0300
@@ -1,93 +1,11 @@
 /* Copyright (c) 2002-2007 Dovecot authors, see the included COPYING file */
 
 #include "lib.h"
-#include "imap-match.h"
-#include "mailbox-tree.h"
+#include "str.h"
 #include "subscription-file.h"
 #include "mailbox-list-private.h"
 #include "mailbox-list-subscriptions.h"
 
-static void node_fix_parents(struct mailbox_node *node)
-{
-	/* If we happened to create any of the parents, we need to mark them
-	   nonexistent. */
-	node = node->parent;
-	for (; node != NULL; node = node->parent) {
-		if ((node->flags & MAILBOX_MATCHED) == 0)
-			node->flags |= MAILBOX_NONEXISTENT;
-	}
-}
-
-static void
-mailbox_list_subscription_add(struct mailbox_list_iterate_context *ctx,
-			      struct mailbox_tree_context *tree_ctx,
-			      struct imap_match_glob *glob,
-			      bool update_only, const char *name)
-{
-	struct mail_namespace *ns = ctx->list->ns;
-	struct mailbox_node *node;
-	enum mailbox_info_flags create_flags, always_flags;
-	enum imap_match_result match;
-	const char *p;
-	bool created, add_matched;
-
-	if ((ns->flags & NAMESPACE_FLAG_INBOX) == 0 ||
-	    strcasecmp(name, "INBOX") != 0) {
-		/* add namespace prefix to all but INBOX */
-		name = t_strconcat(ns->prefix, name, NULL);
-	}
-
-	create_flags = (update_only ||
-			(ctx->flags & MAILBOX_LIST_ITER_RETURN_NO_FLAGS) == 0) ?
-		(MAILBOX_NONEXISTENT | MAILBOX_NOCHILDREN) : 0;
-	always_flags = MAILBOX_SUBSCRIBED;
-	add_matched = TRUE;
-
-	t_push();
-	for (;;) {
-		created = FALSE;
-		match = imap_match(glob, name);
-		if (match == IMAP_MATCH_YES) {
-			node = update_only ?
-				mailbox_tree_lookup(tree_ctx, name) :
-				mailbox_tree_get(tree_ctx, name, &created);
-			if (created) {
-				node->flags = create_flags;
-				if (create_flags != 0)
-					node_fix_parents(node);
-			}
-			if (node != NULL) {
-				if (!update_only && add_matched)
-					node->flags |= MAILBOX_MATCHED;
-				node->flags |= always_flags;
-			}
-			/* We don't want to show the parent mailboxes unless
-			   something else matches them, but if they are matched
-			   we want to show them having child subscriptions */
-			add_matched = FALSE;
-		} else {
-			if ((match & IMAP_MATCH_PARENT) == 0)
-				break;
-			/* We've a (possibly) non-subscribed parent mailbox
-			   which has a subscribed child mailbox. Make sure we
-			   return the parent mailbox. */
-		}
-
-		if ((ctx->flags & MAILBOX_LIST_ITER_SELECT_RECURSIVEMATCH) == 0)
-			break;
-
-		/* see if parent matches */
-		p = strrchr(name, ns->sep);
-		if (p == NULL)
-			break;
-
-		name = t_strdup_until(name, p);
-		create_flags &= ~MAILBOX_NOCHILDREN;
-		always_flags = MAILBOX_CHILDREN | MAILBOX_CHILD_SUBSCRIBED;
-	}
-	t_pop();
-}
-
 int mailbox_list_subscriptions_fill(struct mailbox_list_iterate_context *ctx,
 				    struct mailbox_tree_context *tree_ctx,
 				    struct imap_match_glob *glob,
@@ -96,27 +14,26 @@
 	struct mail_namespace *ns = ctx->list->ns;
 	struct subsfile_list_context *subsfile_ctx;
 	const char *path, *name;
-	char *p;
+	string_t *vname;
+	bool match_parents;
 
+	t_push();
+	vname = t_str_new(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);
 
+	match_parents =
+		(ctx->flags & MAILBOX_LIST_ITER_SELECT_RECURSIVEMATCH) != 0;
+
 	while ((name = subsfile_list_next(subsfile_ctx)) != NULL) {
-		t_push();
-		if (ns->real_sep != ns->sep) {
-			name = p = t_strdup_noconst(name);
-			for (; *p != '\0'; p++) {
-				if (*p == ns->real_sep)
-					*p = ns->sep;
-			}
-		}
-		mailbox_list_subscription_add(ctx, tree_ctx, glob, update_only,
-					      name);
-		t_pop();
+		name = mail_namespace_get_vname(ns, vname, name);
+		mailbox_list_iter_update(ctx, tree_ctx, glob, update_only,
+					 match_parents, name);
 	}
+	t_pop();
 
 	return subsfile_list_deinit(subsfile_ctx);
 }
--- a/src/lib-storage/mail-namespace.c	Sun Oct 28 01:52:00 2007 +0300
+++ b/src/lib-storage/mail-namespace.c	Sun Oct 28 01:53:32 2007 +0300
@@ -1,6 +1,7 @@
 /* Copyright (c) 2005-2007 Dovecot authors, see the included COPYING file */
 
 #include "lib.h"
+#include "str.h"
 #include "file-lock.h"
 #include "mail-storage.h"
 #include "mail-namespace.h"
@@ -292,6 +293,23 @@
 	return ret;
 }
 
+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) == 0 ||
+	    strcasecmp(name, "INBOX") != 0)
+		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);
+}
+
 char mail_namespace_get_root_sep(struct mail_namespace *namespaces)
 {
 	while ((namespaces->flags & NAMESPACE_FLAG_LIST) == 0)
--- a/src/lib-storage/mail-namespace.h	Sun Oct 28 01:52:00 2007 +0300
+++ b/src/lib-storage/mail-namespace.h	Sun Oct 28 01:53:32 2007 +0300
@@ -47,6 +47,11 @@
 
 /* Update hierarchy separators in given name to real_sep characters. */
 const char *mail_namespace_fix_sep(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 hierarchy separator for mailboxes that are listed at root. */
 char mail_namespace_get_root_sep(struct mail_namespace *namespaces);
 
--- a/src/lib-storage/mailbox-list-private.h	Sun Oct 28 01:52:00 2007 +0300
+++ b/src/lib-storage/mailbox-list-private.h	Sun Oct 28 01:53:32 2007 +0300
@@ -5,6 +5,8 @@
 #include "mailbox-list.h"
 
 struct dirent;
+struct imap_match_glob;
+struct mailbox_tree_context;
 
 struct mailbox_list_vfuncs {
 	struct mailbox_list *(*alloc)(void);
@@ -101,6 +103,11 @@
 int mailbox_list_delete_index_control(struct mailbox_list *list,
 				      const char *name);
 
+void mailbox_list_iter_update(struct mailbox_list_iterate_context *ctx,
+			      struct mailbox_tree_context *tree_ctx,
+			      struct imap_match_glob *glob, bool update_only,
+			      bool match_parents, const char *name);
+
 bool mailbox_list_name_is_too_large(const char *name, char sep);
 enum mailbox_list_file_type mailbox_list_get_file_type(const struct dirent *d);
 
--- a/src/lib-storage/mailbox-list.c	Sun Oct 28 01:52:00 2007 +0300
+++ b/src/lib-storage/mailbox-list.c	Sun Oct 28 01:53:32 2007 +0300
@@ -6,6 +6,8 @@
 #include "home-expand.h"
 #include "mkdir-parents.h"
 #include "unlink-directory.h"
+#include "imap-match.h"
+#include "mailbox-tree.h"
 #include "mailbox-list-private.h"
 
 #include <time.h>
@@ -441,6 +443,80 @@
 	return 0;
 }
 
+static void node_fix_parents(struct mailbox_node *node)
+{
+	/* If we happened to create any of the parents, we need to mark them
+	   nonexistent. */
+	node = node->parent;
+	for (; node != NULL; node = node->parent) {
+		if ((node->flags & MAILBOX_MATCHED) == 0)
+			node->flags |= MAILBOX_NONEXISTENT;
+	}
+}
+
+void mailbox_list_iter_update(struct mailbox_list_iterate_context *ctx,
+			      struct mailbox_tree_context *tree_ctx,
+			      struct imap_match_glob *glob, bool update_only,
+			      bool match_parents, const char *name)
+{
+	struct mail_namespace *ns = ctx->list->ns;
+	struct mailbox_node *node;
+	enum mailbox_info_flags create_flags, always_flags;
+	enum imap_match_result match;
+	const char *p;
+	bool created, add_matched;
+
+	create_flags = (update_only ||
+			(ctx->flags & MAILBOX_LIST_ITER_RETURN_NO_FLAGS) == 0) ?
+		(MAILBOX_NONEXISTENT | MAILBOX_NOCHILDREN) : 0;
+	always_flags = MAILBOX_SUBSCRIBED;
+	add_matched = TRUE;
+
+	t_push();
+	for (;;) {
+		created = FALSE;
+		match = imap_match(glob, name);
+		if (match == IMAP_MATCH_YES) {
+			node = update_only ?
+				mailbox_tree_lookup(tree_ctx, name) :
+				mailbox_tree_get(tree_ctx, name, &created);
+			if (created) {
+				node->flags = create_flags;
+				if (create_flags != 0)
+					node_fix_parents(node);
+			}
+			if (node != NULL) {
+				if (!update_only && add_matched)
+					node->flags |= MAILBOX_MATCHED;
+				node->flags |= always_flags;
+			}
+			/* We don't want to show the parent mailboxes unless
+			   something else matches them, but if they are matched
+			   we want to show them having child subscriptions */
+			add_matched = FALSE;
+		} else {
+			if ((match & IMAP_MATCH_PARENT) == 0)
+				break;
+			/* We've a (possibly) non-subscribed parent mailbox
+			   which has a subscribed child mailbox. Make sure we
+			   return the parent mailbox. */
+		}
+
+		if (!match_parents)
+			break;
+
+		/* see if parent matches */
+		p = strrchr(name, ns->sep);
+		if (p == NULL)
+			break;
+
+		name = t_strdup_until(name, p);
+		create_flags &= ~MAILBOX_NOCHILDREN;
+		always_flags = MAILBOX_CHILDREN | MAILBOX_CHILD_SUBSCRIBED;
+	}
+	t_pop();
+}
+
 bool mailbox_list_name_is_too_large(const char *name, char sep)
 {
 	unsigned int levels = 1, level_len = 0;
--- a/src/lib-storage/mailbox-list.h	Sun Oct 28 01:52:00 2007 +0300
+++ b/src/lib-storage/mailbox-list.h	Sun Oct 28 01:53:32 2007 +0300
@@ -45,6 +45,9 @@
 enum mailbox_list_iter_flags {
 	/* Ignore index file and ACLs (used by ACL plugin internally) */
 	MAILBOX_LIST_ITER_RAW_LIST		= 0x000001,
+	/* Use virtual mailbox names (virtual separators and namespace
+	   prefixes) for patterns and for returned mailbox names. */
+	MAILBOX_LIST_ITER_VIRTUAL_NAMES		= 0x000002,
 
 	/* List only subscribed mailboxes */
 	MAILBOX_LIST_ITER_SELECT_SUBSCRIBED	= 0x000010,
--- a/src/plugins/acl/acl-mailbox-list.c	Sun Oct 28 01:52:00 2007 +0300
+++ b/src/plugins/acl/acl-mailbox-list.c	Sun Oct 28 01:53:32 2007 +0300
@@ -2,6 +2,7 @@
 
 #include "lib.h"
 #include "array.h"
+#include "str.h"
 #include "imap-match.h"
 #include "mailbox-tree.h"
 #include "mail-namespace.h"
@@ -73,12 +74,11 @@
 	const struct acl_mask *acl_mask;
 	struct acl_mailbox_list_context *nonowner_list_ctx;
 	struct imap_match_glob *glob;
-	enum imap_match_result match;
-	struct mailbox_node *node;
+	struct mail_namespace *ns = ctx->ctx.list->ns;
 	const char *name;
+	string_t *vname;
 	char sep;
 	int try, ret;
-	bool created;
 
 	if ((ctx->ctx.flags & MAILBOX_LIST_ITER_RAW_LIST) != 0)
 		return FALSE;
@@ -89,7 +89,13 @@
 
 	/* default is to not list mailboxes. we can optimize this. */
 	t_push();
-	sep = mailbox_list_get_hierarchy_sep(ctx->ctx.list);
+	if ((ctx->ctx.flags & MAILBOX_LIST_ITER_VIRTUAL_NAMES) != 0) {
+		sep = ns->sep;
+		vname = t_str_new(256);
+	} else {
+		sep = ns->real_sep;
+		vname = NULL;
+	}
 	glob = imap_match_init_multiple(pool_datastack_create(), patterns,
 					TRUE, sep);
 
@@ -100,23 +106,12 @@
 
 		while ((ret = acl_backend_nonowner_lookups_iter_next(
 					nonowner_list_ctx, &name)) > 0) {
-			match = imap_match(glob, name);
-			if (match == IMAP_MATCH_YES) {
-				node = mailbox_tree_get(ctx->tree, name,
-							&created);
-				if (created)
-					node->flags |= MAILBOX_NOCHILDREN;
-				node->flags |= MAILBOX_FLAG_MATCHED;
-				node->flags &= ~MAILBOX_NONEXISTENT;
-			} else if ((match & IMAP_MATCH_PARENT) != 0) {
-				node = mailbox_tree_get(ctx->tree, name,
-							&created);
-				if (created)
-					node->flags |= MAILBOX_NONEXISTENT;
-				node->flags |= MAILBOX_FLAG_MATCHED |
-					MAILBOX_CHILDREN;
-				node->flags &= ~MAILBOX_NOCHILDREN;
+			if (vname != NULL) {
+				name = mail_namespace_get_vname(ns, vname,
+								name);
 			}
+			mailbox_list_iter_update(&ctx->ctx, ctx->tree,
+						 glob, FALSE, TRUE, name);
 		}
 		if (ret == 0)
 			break;
@@ -159,15 +154,12 @@
 	struct acl_mailbox_list_iterate_context *ctx =
 		(struct acl_mailbox_list_iterate_context *)_ctx;
 	struct acl_mailbox_list *alist = ACL_LIST_CONTEXT(_ctx->list);
+	struct mail_namespace *ns = _ctx->list->ns;
 	const struct mailbox_info *info;
 	struct mailbox_node *node;
-	const char *ns_prefix, *acl_name;
-	unsigned int ns_prefix_len;
+	const char *acl_name;
 	int ret;
 
-	ns_prefix = _ctx->list->ns->prefix;
-	ns_prefix_len = strlen(ns_prefix);
-
 	for (;;) {
 		if (ctx->tree_iter != NULL) {
 			node = mailbox_tree_iterate_next(ctx->tree_iter,
@@ -188,15 +180,20 @@
 			return info;
 		}
 
-		/* Mailbox names contain namespace prefix, except when listing
-		   INBOX. */
+		t_push();
 		acl_name = info->name;
-		if (strncmp(acl_name, ns_prefix, ns_prefix_len) == 0)
-			acl_name += ns_prefix_len;
+		if ((ctx->ctx.flags & MAILBOX_LIST_ITER_VIRTUAL_NAMES) != 0) {
+			/* Mailbox names contain namespace prefix,
+			   except when listing INBOX. */
+			if (strncmp(acl_name, ns->prefix, ns->prefix_len) == 0)
+				acl_name += ns->prefix_len;
+			acl_name = mail_namespace_fix_sep(ns, acl_name);
+		}
 
 		ret = acl_mailbox_list_have_right(alist, acl_name,
 						  ACL_STORAGE_RIGHT_LOOKUP,
 						  NULL);
+		t_pop();
 		if (ret > 0)
 			return info;
 		if (ret < 0) {