dovecot-2.0: lib-storage: mailbox_list_iter_init_namespaces() ha...

dovecot at dovecot.org dovecot at dovecot.org
Wed Apr 28 22:09:22 EEST 2010


details:   http://hg.dovecot.org/dovecot-2.0/rev/af59d2d02f33
changeset: 11200:af59d2d02f33
user:      Timo Sirainen <tss at iki.fi>
date:      Wed Apr 28 22:05:13 2010 +0300
description:
lib-storage: mailbox_list_iter_init_namespaces() has more filtering capabilities now.
 - namespace types

 - MAILBOX_LIST_ITER_STAR_WITHIN_NS flag so that "*" doesn't escape beyond
the namespace it started in.

diffstat:

 src/dsync/dsync-worker-local.c       |    6 +-
 src/lib-storage/mail-namespace.h     |    6 +-
 src/lib-storage/mailbox-list.c       |  172 ++++++++++++++++++++++++++++++++--
 src/lib-storage/mailbox-list.h       |   19 ++-
 src/plugins/virtual/virtual-config.c |    8 +-
 5 files changed, 189 insertions(+), 22 deletions(-)

diffs (truncated from 346 to 300 lines):

diff -r 71e40ea473cf -r af59d2d02f33 src/dsync/dsync-worker-local.c
--- a/src/dsync/dsync-worker-local.c	Wed Apr 28 22:02:59 2010 +0300
+++ b/src/dsync/dsync-worker-local.c	Wed Apr 28 22:05:13 2010 +0300
@@ -395,7 +395,8 @@
 	iter->ret_pool = pool_alloconly_create("local mailbox iter", 1024);
 	iter->list_iter =
 		mailbox_list_iter_init_namespaces(worker->user->namespaces,
-						  patterns, list_flags);
+						  patterns, NAMESPACE_PRIVATE,
+						  list_flags);
 	(void)dsync_worker_get_mailbox_log(worker);
 	return &iter->iter;
 }
@@ -580,7 +581,8 @@
 	iter->iter.worker = _worker;
 	iter->list_iter =
 		mailbox_list_iter_init_namespaces(worker->user->namespaces,
-						  patterns, list_flags);
+						  patterns, NAMESPACE_PRIVATE,
+						  list_flags);
 	(void)dsync_worker_get_mailbox_log(worker);
 	return &iter->iter;
 }
diff -r 71e40ea473cf -r af59d2d02f33 src/lib-storage/mail-namespace.h
--- a/src/lib-storage/mail-namespace.h	Wed Apr 28 22:02:59 2010 +0300
+++ b/src/lib-storage/mail-namespace.h	Wed Apr 28 22:05:13 2010 +0300
@@ -6,9 +6,9 @@
 struct mail_storage_callbacks;
 
 enum namespace_type {
-	NAMESPACE_PRIVATE,
-	NAMESPACE_SHARED,
-	NAMESPACE_PUBLIC
+	NAMESPACE_PRIVATE	= 0x01,
+	NAMESPACE_SHARED	= 0x02,
+	NAMESPACE_PUBLIC	= 0x04
 };
 
 enum namespace_flags {
diff -r 71e40ea473cf -r af59d2d02f33 src/lib-storage/mailbox-list.c
--- a/src/lib-storage/mailbox-list.c	Wed Apr 28 22:02:59 2010 +0300
+++ b/src/lib-storage/mailbox-list.c	Wed Apr 28 22:05:13 2010 +0300
@@ -38,7 +38,8 @@
 	struct mailbox_list_iterate_context *backend_ctx;
 	struct mail_namespace *namespaces;
 	pool_t pool;
-	const char **patterns;
+	const char **patterns, **patterns_ns_match;
+	enum namespace_type type_mask;
 };
 
 struct mailbox_list_module_register mailbox_list_module_register = { 0 };
@@ -592,12 +593,124 @@
 	return list->v.iter_init(list, patterns, flags);
 }
 
+static bool
+ns_match_simple(struct ns_list_iterate_context *ctx, struct mail_namespace *ns)
+{
+	if ((ctx->type_mask & ns->type) == 0)
+		return FALSE;
+
+	if ((ctx->ctx.flags & MAILBOX_LIST_ITER_SKIP_ALIASES) != 0) {
+		if (ns->alias_for != NULL)
+			return FALSE;
+	}
+	return TRUE;
+}
+
+static bool
+ns_match_next(struct ns_list_iterate_context *ctx, struct mail_namespace *ns,
+	      const char *pattern)
+{
+	struct imap_match_glob *glob;
+	enum imap_match_result result;
+	const char *prefix_without_sep;
+	unsigned int len;
+
+	len = ns->prefix_len;
+	if (len > 0 && ns->prefix[len-1] == ns->sep)
+		len--;
+
+	if ((ns->flags & (NAMESPACE_FLAG_LIST_PREFIX |
+			  NAMESPACE_FLAG_LIST_CHILDREN)) == 0) {
+		/* non-listable namespace matches only with exact prefix */
+		if (strncmp(ns->prefix, pattern, ns->prefix_len) != 0)
+			return FALSE;
+	}
+
+	prefix_without_sep = t_strndup(ns->prefix, len);
+	if (*prefix_without_sep == '\0')
+		result = IMAP_MATCH_CHILDREN;
+	else {
+		glob = imap_match_init(pool_datastack_create(), pattern,
+				       TRUE, ns->sep);
+		result = imap_match(glob, prefix_without_sep);
+	}
+
+	if ((ctx->ctx.flags & MAILBOX_LIST_ITER_STAR_WITHIN_NS) == 0) {
+		switch (result) {
+		case IMAP_MATCH_YES:
+		case IMAP_MATCH_CHILDREN:
+			return TRUE;
+		case IMAP_MATCH_NO:
+		case IMAP_MATCH_PARENT:
+			break;
+		}
+		return FALSE;
+	}
+
+	switch (result) {
+	case IMAP_MATCH_YES:
+		/* allow matching prefix only when it's done without
+		   wildcards */
+		if (strcmp(prefix_without_sep, pattern) == 0)
+			return TRUE;
+		break;
+	case IMAP_MATCH_CHILDREN: {
+		/* allow this only if there isn't another namespace
+		   with longer prefix that matches this pattern
+		   (namespaces are sorted by prefix length) */
+		struct mail_namespace *tmp;
+
+		T_BEGIN {
+			for (tmp = ns->next; tmp != NULL; tmp = tmp->next) {
+				if (ns_match_simple(ctx, tmp) &&
+				    ns_match_next(ctx, tmp, pattern))
+					break;
+			}
+		} T_END;
+		if (tmp == NULL)
+			return TRUE;
+		break;
+	}
+	case IMAP_MATCH_NO:
+	case IMAP_MATCH_PARENT:
+		break;
+	}
+	return FALSE;
+}
+
+static bool
+ns_match(struct ns_list_iterate_context *ctx, struct mail_namespace *ns)
+{
+	unsigned int i;
+
+	if (!ns_match_simple(ctx, ns))
+		return FALSE;
+
+	if ((ctx->ctx.flags & MAILBOX_LIST_ITER_VIRTUAL_NAMES) != 0) {
+		/* filter out namespaces whose prefix doesn't match.
+		   this same code handles both with and without
+		   STAR_WITHIN_NS, so the "without" case is slower than
+		   necessary, but this shouldn't matter much */
+		T_BEGIN {
+			for (i = 0; ctx->patterns_ns_match[i] != NULL; i++) {
+				if (ns_match_next(ctx, ns,
+						  ctx->patterns_ns_match[i]))
+					break;
+			}
+		} T_END;
+
+		if (ctx->patterns_ns_match[i] == NULL)
+			return FALSE;
+	}
+	return ns;
+}
+
 static struct mail_namespace *
 ns_next(struct ns_list_iterate_context *ctx, struct mail_namespace *ns)
 {
-	if ((ctx->ctx.flags & MAILBOX_LIST_ITER_SKIP_ALIASES) != 0) {
-		while (ns != NULL && ns->alias_for != NULL)
-			ns = ns->next;
+	for (; ns != NULL; ns = ns->next) {
+		if (ns_match(ctx, ns))
+			break;
 	}
 	return ns;
 }
@@ -609,7 +722,8 @@
 		(struct ns_list_iterate_context *)_ctx;
 	const struct mailbox_info *info;
 
-	info = mailbox_list_iter_next(ctx->backend_ctx);
+	info = ctx->backend_ctx == NULL ? NULL :
+		mailbox_list_iter_next(ctx->backend_ctx);
 	if (info == NULL && ctx->namespaces != NULL) {
 		/* go to the next namespace */
 		if (mailbox_list_iter_deinit(&ctx->backend_ctx) < 0)
@@ -632,16 +746,39 @@
 		(struct ns_list_iterate_context *)_ctx;
 	int ret;
 
-	if (mailbox_list_iter_deinit(&ctx->backend_ctx) < 0)
-		_ctx->failed = TRUE;
+	if (ctx->backend_ctx != NULL) {
+		if (mailbox_list_iter_deinit(&ctx->backend_ctx) < 0)
+			_ctx->failed = TRUE;
+	}
 	ret = _ctx->failed ? -1 : 0;
 	pool_unref(&ctx->pool);
 	return ret;
 }
 
+static const char **
+dup_patterns_without_stars(pool_t pool, const char *const *patterns,
+			   unsigned int count)
+{
+	const char **dup;
+	unsigned int i;
+
+	dup = p_new(pool, const char *, count + 1);
+	for (i = 0; i < count; i++) {
+		char *p = p_strdup(pool, patterns[i]);
+		dup[i] = p;
+
+		for (; *p != '\0'; p++) {
+			if (*p == '*')
+				*p = '%';
+		}
+	}
+	return dup;
+}
+
 struct mailbox_list_iterate_context *
 mailbox_list_iter_init_namespaces(struct mail_namespace *namespaces,
 				  const char *const *patterns,
+				  enum namespace_type type_mask,
 				  enum mailbox_list_iter_flags flags)
 {
 	struct ns_list_iterate_context *ctx;
@@ -650,9 +787,13 @@
 
 	i_assert(namespaces != NULL);
 
+	i_assert((flags & MAILBOX_LIST_ITER_STAR_WITHIN_NS) == 0 ||
+		 (flags & MAILBOX_LIST_ITER_VIRTUAL_NAMES) != 0);
+
 	pool = pool_alloconly_create("mailbox list namespaces", 1024);
 	ctx = p_new(pool, struct ns_list_iterate_context, 1);
 	ctx->pool = pool;
+	ctx->type_mask = type_mask;
 	ctx->ctx.flags = flags;
 	ctx->ctx.list = p_new(pool, struct mailbox_list, 1);
 	ctx->ctx.list->v.iter_next = mailbox_list_ns_iter_next;
@@ -663,11 +804,22 @@
 	for (i = 0; i < count; i++)
 		ctx->patterns[i] = p_strdup(pool, patterns[i]);
 
+	if ((flags & MAILBOX_LIST_ITER_STAR_WITHIN_NS) != 0) {
+		/* create copies of patterns with '*' wildcard changed to '%' */
+		ctx->patterns_ns_match =
+			dup_patterns_without_stars(pool, ctx->patterns, count);
+	} else {
+		ctx->patterns_ns_match = ctx->patterns;
+	}
+
 	namespaces = ns_next(ctx, namespaces);
 	ctx->ctx.list->ns = namespaces;
-	ctx->backend_ctx = mailbox_list_iter_init_multiple(namespaces->list,
-							   patterns, flags);
-	ctx->namespaces = ns_next(ctx, namespaces->next);
+	if (namespaces != NULL) {
+		ctx->backend_ctx =
+			mailbox_list_iter_init_multiple(namespaces->list,
+							patterns, flags);
+		ctx->namespaces = ns_next(ctx, namespaces->next);
+	}
 	return &ctx->ctx;
 }
 
diff -r 71e40ea473cf -r af59d2d02f33 src/lib-storage/mailbox-list.h
--- a/src/lib-storage/mailbox-list.h	Wed Apr 28 22:02:59 2010 +0300
+++ b/src/lib-storage/mailbox-list.h	Wed Apr 28 22:05:13 2010 +0300
@@ -10,6 +10,7 @@
 #  define MAILBOX_LIST_NAME_MAX_LENGTH 4096
 #endif
 
+enum namespace_type;
 struct mail_namespace;
 struct mail_storage;
 struct mailbox_list;
@@ -63,17 +64,24 @@
 	/* Use virtual mailbox names (virtual separators and namespace
 	   prefixes) for patterns and for returned mailbox names. */
 	MAILBOX_LIST_ITER_VIRTUAL_NAMES		= 0x000002,
+	/* Don't list INBOX unless it actually exists */
+	MAILBOX_LIST_ITER_NO_AUTO_INBOX		= 0x000004,
+
 	/* For mailbox_list_iter_init_namespaces(): Skip namespaces that
 	   have alias_for set. */
-	MAILBOX_LIST_ITER_SKIP_ALIASES		= 0x000004,
-	/* Don't list INBOX unless it actually exists */
-	MAILBOX_LIST_ITER_NO_AUTO_INBOX		= 0x000008,
+	MAILBOX_LIST_ITER_SKIP_ALIASES		= 0x000008,
+	/* For mailbox_list_iter_init_namespaces(): '*' in a pattern doesn't
+	   match beyond namespace boundary (e.g. "foo*" or "*o" doesn't match
+	   "foo." namespace's mailboxes, but "*.*" does). also '%' can't match
+	   namespace prefixes, if there exists a parent namespace whose children


More information about the dovecot-cvs mailing list