dovecot: Fixes for listing namespaces with prefixes and real != ...

dovecot at dovecot.org dovecot at dovecot.org
Sat Oct 20 22:58:58 EEST 2007


details:   http://hg.dovecot.org/dovecot/rev/c901bdf0db75
changeset: 6573:c901bdf0db75
user:      Timo Sirainen <tss at iki.fi>
date:      Sat Oct 20 22:58:54 2007 +0300
description:
Fixes for listing namespaces with prefixes and real != virtual separator.

diffstat:

3 files changed, 101 insertions(+), 63 deletions(-)
src/imap/cmd-list.c                              |   35 ++++++---
src/lib-storage/list/mailbox-list-fs-iter.c      |   49 +++++++------
src/lib-storage/list/mailbox-list-maildir-iter.c |   80 +++++++++++++---------

diffs (truncated from 368 to 300 lines):

diff -r 79836b3474f4 -r c901bdf0db75 src/imap/cmd-list.c
--- a/src/imap/cmd-list.c	Sat Oct 20 22:23:14 2007 +0300
+++ b/src/imap/cmd-list.c	Sat Oct 20 22:58:54 2007 +0300
@@ -516,6 +516,7 @@ list_namespace_match_pattern(struct cmd_
 	struct mail_namespace *ns = ctx->ns;
 	struct imap_match_glob *pat_glob;
 	enum imap_match_result match;
+	const char *p;
 	size_t len;
 
 	skip_namespace_prefix_pattern(ctx, &cur_ns_prefix,
@@ -547,15 +548,22 @@ list_namespace_match_pattern(struct cmd_
 	pat_glob = imap_match_init(pool_datastack_create(), orig_cur_pattern,
 				   inboxcase, ns->sep);
 	match = imap_match(pat_glob, cur_ns_prefix);
-	if ((match & (IMAP_MATCH_YES | IMAP_MATCH_CHILDREN)) == 0)
-		return FALSE;
-
-	if (match == IMAP_MATCH_YES && (ns->flags & NAMESPACE_FLAG_LIST) != 0 &&
-	    (ctx->list_flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) == 0) {
-		/* the namespace prefix itself matches too. send it. */
-		ctx->cur_ns_send_prefix = TRUE;
-	}
-	return TRUE;
+	if (match == IMAP_MATCH_YES) {
+		if ((ns->flags & NAMESPACE_FLAG_LIST) != 0 &&
+		    (ctx->list_flags &
+		     MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) == 0) {
+			/* the namespace prefix itself matches too. send it. */
+			ctx->cur_ns_send_prefix = TRUE;
+		}
+		/* if the pattern contains '*' characters, we'll need to
+		   check our children too */
+		for (p = orig_cur_pattern; *p != '\0'; p++) {
+			if (*p == '*')
+				return TRUE;
+		}
+	}
+
+	return (match & IMAP_MATCH_CHILDREN) != 0;
 }
 
 static void list_namespace_init(struct cmd_list_context *ctx)
@@ -598,13 +606,18 @@ static void list_namespace_init(struct c
 		if (list_namespace_match_pattern(ctx, inboxcase, cur_ref,
 						 cur_ns_prefix, pattern)) {
 			pattern = mailbox_list_join_refpattern(ns->list,
-				ctx->ref, mail_namespace_fix_sep(ns, pattern));
+							ctx->ref, pattern);
 			array_append(&used_patterns, &pattern, 1);
 		}
 	}
 
-	if (array_count(&used_patterns) == 0)
+	if (array_count(&used_patterns) == 0) {
+		/* it's possible that the namespace prefix matched,
+		   even though its children didn't */
+		if (ctx->cur_ns_send_prefix)
+			list_namespace_send_prefix(ctx, TRUE);
 		return;
+	}
 	(void)array_append_space(&used_patterns); /* NULL-terminate */
 	pat = array_idx(&used_patterns, 0);
 
diff -r 79836b3474f4 -r c901bdf0db75 src/lib-storage/list/mailbox-list-fs-iter.c
--- a/src/lib-storage/list/mailbox-list-fs-iter.c	Sat Oct 20 22:23:14 2007 +0300
+++ b/src/lib-storage/list/mailbox-list-fs-iter.c	Sat Oct 20 22:58:54 2007 +0300
@@ -49,19 +49,20 @@ static const struct mailbox_info *
 static const struct mailbox_info *
 fs_list_next(struct fs_list_iterate_context *ctx);
 
-static int pattern_get_path_pos(const char *pattern, const char *path,
-				unsigned int *pos_r)
+static int
+pattern_get_path_pos(struct mail_namespace *ns, const char *pattern,
+		     const char *path, unsigned int *pos_r)
 {
 	unsigned int i, j;
 
-	if (strncasecmp(path, "INBOX/", 6) == 0) {
+	if (strncasecmp(path, "INBOX", 5) == 0 && path[5] == ns->sep) {
 		/* make sure INBOX prefix is matched case-insensitively */
 		char *tmp = t_strdup_noconst(pattern);
 
-		if (strncmp(path, "INBOX/", 6) != 0)
-			path = t_strconcat("INBOX/", path + 6, NULL);
-
-		for (i = 0; tmp[i] != '/' && tmp[i] != '\0'; i++)
+		if (strncmp(path, "INBOX", 5) != 0)
+			path = t_strdup_printf("INBOX%c%s", ns->sep, path + 6);
+
+		for (i = 0; tmp[i] != ns->sep && tmp[i] != '\0'; i++)
 			tmp[i] = i_toupper(tmp[i]);
 		pattern = tmp;
 	}
@@ -72,13 +73,13 @@ static int pattern_get_path_pos(const ch
 
 		if (pattern[j] == '%') {
 			/* skip until we're at the next hierarchy separator */
-			if (path[i] == '/') {
+			if (path[i] == ns->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] == '/') {
+					if (pattern[j] == ns->sep) {
 						j++;
 						break;
 					}
@@ -96,17 +97,19 @@ static int pattern_get_path_pos(const ch
 	return 1;
 }
 
-static bool pattern_has_wildcard_at(const char *pattern, const char *path)
+static bool
+pattern_has_wildcard_at(struct mail_namespace *ns, const char *pattern,
+			const char *path)
 {
 	unsigned int pos;
 	int ret;
 
-	if ((ret = pattern_get_path_pos(pattern, path, &pos)) < 0)
+	if ((ret = pattern_get_path_pos(ns, pattern, path, &pos)) < 0)
 		return TRUE;
 	if (ret == 0)
 		return FALSE;
 
-	for (; pattern[pos] != '\0' && pattern[pos] != '/'; pos++) {
+	for (; pattern[pos] != '\0' && pattern[pos] != ns->sep; pos++) {
 		if (pattern[pos] == '%' || pattern[pos] == '*')
 			return TRUE;
 	}
@@ -125,7 +128,8 @@ static int list_opendir(struct fs_list_i
 	t_push();
 	patterns = array_idx(&ctx->valid_patterns, 0);
 	for (i = 0; patterns[i] != NULL; i++) {
-		if (pattern_has_wildcard_at(patterns[i], list_path))
+		if (pattern_has_wildcard_at(ctx->ctx.list->ns,
+					    patterns[i], list_path))
 			break;
 	}
 	t_pop();
@@ -190,13 +194,14 @@ fs_list_iter_init(struct mailbox_list *_
 		return &ctx->ctx;
 	}
 	patterns = (const void *)array_idx(&ctx->valid_patterns, 0);
-	ctx->glob = imap_match_init_multiple(default_pool, patterns, TRUE, '/');
+	ctx->glob = imap_match_init_multiple(default_pool, patterns, TRUE,
+					     _list->ns->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('/');
+		ctx->subs_tree = mailbox_tree_init(_list->ns->sep);
 		if (mailbox_list_subscriptions_fill(&ctx->ctx,
 						    ctx->subs_tree,
 						    ctx->glob, FALSE) < 0) {
@@ -334,6 +339,7 @@ static int
 static int
 list_file(struct fs_list_iterate_context *ctx, const struct dirent *d)
 {
+	struct mail_namespace *ns = ctx->ctx.list->ns;
 	const char *fname = d->d_name;
 	struct list_dir_context *dir;
 	const char *list_path, *real_path, *vpath, *inbox_path;
@@ -366,7 +372,7 @@ list_file(struct fs_list_iterate_context
 
 	/* make sure we give only one correct INBOX */
 	real_path = t_strconcat(ctx->dir->real_path, "/", fname, NULL);
-	if ((ctx->ctx.list->ns->flags & NAMESPACE_FLAG_INBOX) != 0 &&
+	if ((ns->flags & NAMESPACE_FLAG_INBOX) != 0 &&
 	    strcasecmp(list_path, "INBOX") == 0) {
 		if (ctx->inbox_listed) {
 			/* already listed the INBOX */
@@ -405,7 +411,7 @@ list_file(struct fs_list_iterate_context
 
 	if ((ctx->info.flags & MAILBOX_NOINFERIORS) == 0) {
 		/* subdirectory. scan inside it. */
-		vpath = t_strconcat(list_path, "/", NULL);
+		vpath = t_strdup_printf("%s%c", list_path, ns->sep);
 		match2 = imap_match(ctx->glob, vpath);
 
 		if (match == IMAP_MATCH_YES)
@@ -421,7 +427,8 @@ list_file(struct fs_list_iterate_context
 			dir = i_new(struct list_dir_context, 1);
 			dir->dirp = dirp;
 			dir->real_path = i_strdup(real_path);
-			dir->virtual_path = i_strconcat(list_path, "/", NULL);
+			dir->virtual_path =
+				i_strdup_printf("%s%c", list_path, ns->sep);
 
 			dir->prev = ctx->dir;
 			ctx->dir = dir;
@@ -473,6 +480,7 @@ static struct dirent *fs_list_dir_next(s
 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;
@@ -493,13 +501,14 @@ static struct dirent *fs_list_dir_next(s
 		patterns += dir->pattern_pos;
 		dir->pattern_pos++;
 
-		ret = pattern_get_path_pos(*patterns, dir->virtual_path, &pos);
+		ret = pattern_get_path_pos(ns, *patterns, dir->virtual_path,
+					   &pos);
 		if (ret == 0)
 			continue;
 		i_assert(ret > 0);
 
 		/* get the filename from the pattern */
-		p = strchr(*patterns + pos, '/');
+		p = strchr(*patterns + pos, ns->sep);
 		fname = p == NULL ? *patterns + pos :
 			t_strdup_until(*patterns + pos, p);
 
diff -r 79836b3474f4 -r c901bdf0db75 src/lib-storage/list/mailbox-list-maildir-iter.c
--- a/src/lib-storage/list/mailbox-list-maildir-iter.c	Sat Oct 20 22:23:14 2007 +0300
+++ b/src/lib-storage/list/mailbox-list-maildir-iter.c	Sat Oct 20 22:58:54 2007 +0300
@@ -45,31 +45,39 @@ static void maildir_fill_parents(struct 
 	const char *p;
 	char hierarchy_sep;
 	bool created;
-
-	hierarchy_sep = ctx->ctx.list->hierarchy_sep;
+	const char *ns_prefix = ctx->ctx.list->ns->prefix;
+	unsigned int ns_prefix_len = strlen(ns_prefix);
+
+	hierarchy_sep = ctx->ctx.list->ns->sep;
 
 	t_push();
 	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) {
-			created = FALSE;
-			node = update_only ?
-				mailbox_tree_lookup(ctx->tree_ctx, mailbox_c) :
-				mailbox_tree_get(ctx->tree_ctx,
-						 mailbox_c, &created);
-			if (node != NULL) {
-				if (created) {
-					/* we haven't yet seen this mailbox,
-					   but we might see it later */
-					node->flags = MAILBOX_NONEXISTENT;
-				}
-				if (!update_only)
-					node->flags |= MAILBOX_MATCHED;
-				node->flags |= MAILBOX_CHILDREN | flags;
-				node->flags &= ~MAILBOX_NOCHILDREN;
-				node_fix_parents(node);
+		if (imap_match(glob, mailbox_c) != IMAP_MATCH_YES)
+			continue;
+
+		if (*ns_prefix != '\0' &&
+		    strncmp(mailbox_c, ns_prefix, ns_prefix_len - 1) == 0) {
+			/* 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);
+		if (node != NULL) {
+			if (created) {
+				/* we haven't yet seen this mailbox,
+				   but we might see it later */
+				node->flags = MAILBOX_NONEXISTENT;
 			}
+			if (!update_only)
+				node->flags |= MAILBOX_MATCHED;
+			node->flags |= MAILBOX_CHILDREN | flags;
+			node->flags &= ~MAILBOX_NOCHILDREN;
+			node_fix_parents(node);
 		}
 	}
 	t_pop();
@@ -79,15 +87,18 @@ maildir_fill_readdir(struct maildir_list
 maildir_fill_readdir(struct maildir_list_iterate_context *ctx,
 		     struct imap_match_glob *glob, bool update_only)
 {
+	struct mail_namespace *ns = ctx->ctx.list->ns;
 	DIR *dirp;
 	struct dirent *d;
-	const char *mailbox_name, *mailbox_c;
+	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;
 	char prefix_char;


More information about the dovecot-cvs mailing list