dovecot: Added support for multiple mailbox list patterns.

dovecot at dovecot.org dovecot at dovecot.org
Sun Jul 15 05:33:47 EEST 2007


details:   http://hg.dovecot.org/dovecot/rev/cc1f4688a988
changeset: 6007:cc1f4688a988
user:      Timo Sirainen <tss at iki.fi>
date:      Sun Jul 15 05:33:43 2007 +0300
description:
Added support for multiple mailbox list patterns.

diffstat:

12 files changed, 506 insertions(+), 313 deletions(-)
src/imap/cmd-list.c                              |  314 ++++++++++++--------
src/lib-imap/imap-match.c                        |  331 ++++++++++++++--------
src/lib-imap/imap-match.h                        |   16 -
src/lib-storage/list/index-mailbox-list.c        |   17 -
src/lib-storage/list/mailbox-list-fs-iter.c      |   53 ++-
src/lib-storage/list/mailbox-list-fs.h           |    2 
src/lib-storage/list/mailbox-list-maildir-iter.c |   29 -
src/lib-storage/list/mailbox-list-maildir.h      |    2 
src/lib-storage/mailbox-list-private.h           |    3 
src/lib-storage/mailbox-list.c                   |   19 +
src/lib-storage/mailbox-list.h                   |    8 
src/plugins/acl/acl-mailbox-list.c               |   25 -

diffs (truncated from 1302 to 300 lines):

diff -r 9da1ec15340d -r cc1f4688a988 src/imap/cmd-list.c
--- a/src/imap/cmd-list.c	Sun Jul 15 02:45:25 2007 +0300
+++ b/src/imap/cmd-list.c	Sun Jul 15 05:33:43 2007 +0300
@@ -12,7 +12,7 @@ struct cmd_list_context {
 struct cmd_list_context {
 	struct client_command_context *cmd;
 	const char *ref;
-	const char *pattern;
+	const char *const *patterns;
 	enum mailbox_list_flags list_flags;
 
 	struct mail_namespace *ns;
@@ -403,17 +403,12 @@ skip_namespace_prefix(const char **prefi
 }
 
 static bool
-skip_namespace_prefix_refpattern(struct cmd_list_context *ctx,
-				 const char **cur_ns_prefix_p,
-				 const char **cur_ref_p,
-				 const char **cur_pattern_p)
+skip_namespace_prefix_ref(struct cmd_list_context *ctx,
+			  const char **cur_ns_prefix_p,
+			  const char **cur_ref_p)
 {
 	const char *cur_ns_prefix = *cur_ns_prefix_p;
 	const char *cur_ref = *cur_ref_p;
-	const char *cur_pattern = *cur_pattern_p;
-
-	if (*ctx->ns->prefix == '\0')
-		return TRUE;
 
 	if (*cur_ref != '\0') {
 		/* reference argument given. skip namespace prefix using it.
@@ -434,33 +429,46 @@ skip_namespace_prefix_refpattern(struct 
 		}
 	}
 
-	if (*cur_ns_prefix != '\0') {
-		/* skip namespace prefix using pattern */
-		const char *old_ns_prefix = cur_ns_prefix;
-		const char *old_pattern = cur_pattern;
-
-		i_assert(*cur_ref == '\0');
-
-		skip_namespace_prefix(&cur_ns_prefix, &cur_pattern,
-				      cur_ref == ctx->ref, ctx->ns->sep);
-
-		if (*cur_pattern == '\0' && *cur_ns_prefix == '\0') {
-			/* trying to list the namespace prefix itself. */
-			cur_ns_prefix = old_ns_prefix;
-			cur_pattern = old_pattern;
-		}
-	}
-
 	*cur_ns_prefix_p = cur_ns_prefix;
 	*cur_ref_p = cur_ref;
+	return TRUE;
+}
+
+static void
+skip_namespace_prefix_pattern(struct cmd_list_context *ctx,
+			      const char **cur_ns_prefix_p,
+			      const char *cur_ref, const char **cur_pattern_p)
+{
+	const char *cur_ns_prefix = *cur_ns_prefix_p;
+	const char *cur_pattern = *cur_pattern_p;
+	const char *old_ns_prefix = cur_ns_prefix;
+	const char *old_pattern = cur_pattern;
+
+	if (*cur_ns_prefix == '\0')
+		return;
+
+	/* skip namespace prefix using pattern */
+	i_assert(*cur_ref == '\0');
+
+	skip_namespace_prefix(&cur_ns_prefix, &cur_pattern,
+			      cur_ref == ctx->ref, ctx->ns->sep);
+
+	if (*cur_pattern == '\0' && *cur_ns_prefix == '\0') {
+		/* trying to list the namespace prefix itself. */
+		cur_ns_prefix = old_ns_prefix;
+		cur_pattern = old_pattern;
+	}
+
+	*cur_ns_prefix_p = cur_ns_prefix;
 	*cur_pattern_p = cur_pattern;
-	return TRUE;
 }
 
 static enum imap_match_result
 list_use_inboxcase(struct cmd_list_context *ctx)
 {
 	struct imap_match_glob *inbox_glob;
+	const char *const *pat;
+	enum imap_match_result match, ret;
 
 	if (*ctx->ns->prefix != '\0' &&
 	    (ctx->ns->flags & NAMESPACE_FLAG_INBOX) == 0)
@@ -468,10 +476,22 @@ list_use_inboxcase(struct cmd_list_conte
 
 	/* if the original reference and pattern combined produces something
 	   that matches INBOX, the INBOX casing is on. */
-	inbox_glob = imap_match_init(ctx->cmd->pool,
-				     t_strconcat(ctx->ref, ctx->pattern, NULL),
-				     TRUE, ctx->ns->sep);
-	return imap_match(inbox_glob, "INBOX");
+	ret = IMAP_MATCH_NO;
+	for (pat = ctx->patterns; *pat != NULL; pat++) {
+		t_push();
+		inbox_glob =
+			imap_match_init(pool_datastack_create(),
+					t_strconcat(ctx->ref, *pat, NULL),
+					TRUE, ctx->ns->sep);
+		match = imap_match(inbox_glob, "INBOX");
+		t_pop();
+
+		if (match == IMAP_MATCH_YES)
+			return IMAP_MATCH_YES;
+		if ((match & IMAP_MATCH_PARENT) != 0)
+			ret = IMAP_MATCH_PARENT;
+	}
+	return ret;
 }
 
 static void
@@ -509,19 +529,95 @@ skip_pattern_wildcard_prefix(const char 
 	*cur_pattern_p = cur_pattern;
 }
 
+static bool
+list_namespace_init_pattern(struct cmd_list_context *ctx, bool inboxcase,
+			    const char *cur_ref, const char *cur_ns_prefix,
+			    const char **cur_pattern_p, bool *want_glob_r)
+{
+	struct mail_namespace *ns = ctx->ns;
+	struct imap_match_glob *pat_glob;
+	const char *cur_pattern = *cur_pattern_p;
+	enum imap_match_result match;
+	size_t len;
+
+	skip_namespace_prefix_pattern(ctx, &cur_ns_prefix,
+				      cur_ref, &cur_pattern);
+	if (*cur_ns_prefix == '\0') {
+		*want_glob_r = FALSE;
+		*cur_pattern_p = cur_pattern;
+		return TRUE;
+	}
+
+	/* namespace prefix still wasn't completely skipped over.
+	   for example cur_ns_prefix=INBOX/, pattern=%/% or pattern=IN%.
+	   Check that pattern matches namespace prefix. */
+	i_assert(*cur_ref == '\0');
+
+	/* drop the trailing separator in namespace prefix.
+	   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 &&
+	    strcmp(cur_pattern, cur_ns_prefix) != 0) {
+		ctx->cur_ns_skip_trailing_sep = TRUE;
+		cur_ns_prefix = t_strndup(cur_ns_prefix, len-1);
+	}
+
+	/* hidden and non-listable namespaces are invisible to wildcards */
+	if ((ns->flags & NAMESPACE_FLAG_LIST) == 0 &&
+	    list_pattern_has_wildcards(cur_pattern))
+		return FALSE;
+
+	/* check if this namespace prefix matches the current pattern */
+	pat_glob = imap_match_init(pool_datastack_create(), *cur_pattern_p,
+				   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;
+	}
+
+	/* We have now verified that the pattern matches the namespace prefix,
+	   so we'll just have to skip over as many hierarchies from pattern as
+	   there exists in namespace prefix. */
+	skip_pattern_wildcard_prefix(cur_ns_prefix, ns->sep, &cur_pattern);
+
+	if (*cur_pattern == '\0' && ctx->cur_ns_match_inbox) {
+		/* ns_prefix="INBOX/" and we wanted to list "%".
+		   This is an optimization to avoid doing an empty
+		   listing followed by another INBOX listing later. */
+		cur_pattern = "INBOX";
+		*want_glob_r = FALSE;
+	} else if (*cur_pattern != '*' || strcmp(*cur_pattern_p, "*") == 0) {
+		/* a) we don't have '*' in pattern
+		   b) we want to display everything
+
+		   we don't need to do separate filtering ourself */
+		*want_glob_r = FALSE;
+	} else {
+		*want_glob_r = TRUE;
+	}
+
+	*cur_pattern_p = cur_pattern;
+	return TRUE;
+}
+
 static void list_namespace_init(struct cmd_list_context *ctx)
 {
 	struct mail_namespace *ns = ctx->ns;
-	const char *cur_ns_prefix, *cur_ref, *cur_pattern;
-	enum imap_match_result match;
+	const char *cur_ns_prefix, *cur_ref, *const *pat, *pattern;
 	enum imap_match_result inbox_match;
-	size_t len;
+	ARRAY_DEFINE(used_patterns, const char *);
+	bool inboxcase, want_glob = FALSE, want_any_glob = FALSE;
 
 	cur_ns_prefix = ns->prefix;
 	cur_ref = ctx->ref;
-	cur_pattern = ctx->pattern;
-
-	if ((ctx->ns->flags & NAMESPACE_FLAG_HIDDEN) != 0 &&
+
+	if ((ns->flags & NAMESPACE_FLAG_HIDDEN) != 0 &&
 	    (ctx->list_flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) != 0) {
 		/* ignore hidden namespaces */
 		return;
@@ -532,85 +628,42 @@ static void list_namespace_init(struct c
 	if ((ns->flags & NAMESPACE_FLAG_INBOX) != 0)
 		ctx->seen_inbox_namespace = TRUE;
 
-	if (!skip_namespace_prefix_refpattern(ctx, &cur_ns_prefix,
-					      &cur_ref, &cur_pattern))
-		return;
+	if (*cur_ns_prefix != '\0') {
+		/* namespace has a prefix. see if we can skip over it. */
+		if (!skip_namespace_prefix_ref(ctx, &cur_ns_prefix, &cur_ref))
+			return;
+	}
 
 	inbox_match = list_use_inboxcase(ctx);
 	ctx->cur_ns_match_inbox = inbox_match == IMAP_MATCH_YES;
-
-	ctx->glob = imap_match_init(ctx->cmd->pool, ctx->pattern,
-				    (inbox_match == IMAP_MATCH_YES ||
-				     inbox_match == IMAP_MATCH_PARENT) &&
-				    cur_pattern == ctx->pattern, ns->sep);
-
-	if (*cur_ns_prefix != '\0') {
-		/* namespace prefix still wasn't completely skipped over.
-		   for example cur_ns_prefix=INBOX/, pattern=%/% or pattern=IN%.
-		   Check that pattern matches namespace prefix. */
-		i_assert(*cur_ref == '\0');
-
-		/* drop the trailing separator in namespace prefix.
-		   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 &&
-		    strcmp(cur_pattern, cur_ns_prefix) != 0) {
-			ctx->cur_ns_skip_trailing_sep = TRUE;
-			cur_ns_prefix = t_strndup(cur_ns_prefix, len-1);
-		}
-
-		/* hidden and non-listable namespaces should still be seen
-		   without wildcards. */
-		match = ((ns->flags & NAMESPACE_FLAG_LIST) == 0 &&
-			 list_pattern_has_wildcards(cur_pattern)) ?
-			IMAP_MATCH_NO : imap_match(ctx->glob, cur_ns_prefix);
-		if (match != IMAP_MATCH_YES && match != IMAP_MATCH_CHILDREN)
-			return;
-
-		if (match == IMAP_MATCH_YES &&
-		    (ns->flags & NAMESPACE_FLAG_LIST) != 0 &&
-		    (ctx->list_flags &
-		     MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) == 0)
-			ctx->cur_ns_send_prefix = TRUE;
-	}
-
-
-	if (*cur_ns_prefix != '\0') {
-		/* We didn't skip over the whole namespace prefix. For example
-		   cur_ns_prefix=INBOX/ and pattern=%/% or IN*.
-
-		   We have already verified that the pattern matches the
-		   namespace prefix, so we'll just have to skip over as many
-		   hierarchies from pattern as there exists in namespace
-		   prefix. */
-		i_assert(*cur_ref == '\0');
-		skip_pattern_wildcard_prefix(cur_ns_prefix, ns->sep,
-					     &cur_pattern);
-
-		if (*cur_pattern == '\0' && ctx->cur_ns_match_inbox) {
-			/* ns_prefix="INBOX/" and we wanted to list "%".
-			   This is an optimization to avoid doing an empty
-			   listing followed by another INBOX listing later. */
-			cur_pattern = "INBOX";
-		}
-	}
-


More information about the dovecot-cvs mailing list