dovecot-2.1: lib-storage: Moved mailbox list iteration functions...

dovecot at dovecot.org dovecot at dovecot.org
Fri Dec 2 14:26:39 EET 2011


details:   http://hg.dovecot.org/dovecot-2.1/rev/37c2348b67f5
changeset: 13791:37c2348b67f5
user:      Timo Sirainen <tss at iki.fi>
date:      Fri Dec 02 14:23:47 2011 +0200
description:
lib-storage: Moved mailbox list iteration functions to a separate file.

diffstat:

 src/lib-storage/Makefile.am         |    1 +
 src/lib-storage/mailbox-list-iter.c |  396 +++++++++++++++++++++++++++++++++++
 src/lib-storage/mailbox-list.c      |  400 +-----------------------------------
 3 files changed, 399 insertions(+), 398 deletions(-)

diffs (truncated from 847 to 300 lines):

diff -r 6591f7783d55 -r 37c2348b67f5 src/lib-storage/Makefile.am
--- a/src/lib-storage/Makefile.am	Fri Dec 02 13:12:16 2011 +0200
+++ b/src/lib-storage/Makefile.am	Fri Dec 02 14:23:47 2011 +0200
@@ -40,6 +40,7 @@
 	mailbox-header.c \
 	mailbox-keywords.c \
 	mailbox-list.c \
+	mailbox-list-iter.c \
 	mailbox-search-result.c \
 	mailbox-tree.c \
 	mailbox-uidvalidity.c
diff -r 6591f7783d55 -r 37c2348b67f5 src/lib-storage/mailbox-list-iter.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-storage/mailbox-list-iter.c	Fri Dec 02 14:23:47 2011 +0200
@@ -0,0 +1,396 @@
+/* Copyright (c) 2006-2011 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "imap-match.h"
+#include "mailbox-tree.h"
+#include "mailbox-list-private.h"
+
+struct ns_list_iterate_context {
+	struct mailbox_list_iterate_context ctx;
+	struct mailbox_list_iterate_context *backend_ctx;
+	struct mail_namespace *namespaces;
+	pool_t pool;
+	const char **patterns, **patterns_ns_match;
+	enum namespace_type type_mask;
+};
+
+struct mailbox_list_iterate_context *
+mailbox_list_iter_init(struct mailbox_list *list, const char *pattern,
+		       enum mailbox_list_iter_flags flags)
+{
+	const char *patterns[2];
+
+	patterns[0] = pattern;
+	patterns[1] = NULL;
+	return mailbox_list_iter_init_multiple(list, patterns, flags);
+}
+
+static int mailbox_list_subscriptions_refresh(struct mailbox_list *list)
+{
+	struct mail_namespace *ns = list->ns;
+
+	if ((ns->flags & NAMESPACE_FLAG_SUBSCRIPTIONS) == 0) {
+		/* no subscriptions in this namespace. find where they are. */
+		ns = mail_namespace_find_subscribable(ns->user->namespaces,
+						      ns->prefix);
+		if (ns == NULL) {
+			/* no subscriptions */
+			return 0;
+		}
+	}
+	return ns->list->v.subscriptions_refresh(ns->list, list);
+}
+
+struct mailbox_list_iterate_context *
+mailbox_list_iter_init_multiple(struct mailbox_list *list,
+				const char *const *patterns,
+				enum mailbox_list_iter_flags flags)
+{
+	struct mailbox_list_iterate_context *ctx;
+	int ret = 0;
+
+	i_assert(*patterns != NULL);
+
+	if ((flags & (MAILBOX_LIST_ITER_SELECT_SUBSCRIBED |
+		      MAILBOX_LIST_ITER_RETURN_SUBSCRIBED)) != 0)
+		ret = mailbox_list_subscriptions_refresh(list);
+
+	ctx = list->v.iter_init(list, patterns, flags);
+	if (ret < 0)
+		ctx->failed = TRUE;
+	return ctx;
+}
+
+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_inbox(struct mail_namespace *ns, const char *pattern)
+{
+	struct imap_match_glob *glob;
+
+	if ((ns->flags & NAMESPACE_FLAG_INBOX_USER) == 0)
+		return FALSE;
+
+	glob = imap_match_init(pool_datastack_create(), pattern,
+			       TRUE, mail_namespace_get_sep(ns));
+	return imap_match(glob, "INBOX") == IMAP_MATCH_YES;
+}
+
+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] == mail_namespace_get_sep(ns))
+		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, mail_namespace_get_sep(ns));
+		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;
+
+	/* 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_inbox(ns, ctx->patterns_ns_match[i]))
+				break;
+			if (ns_match_next(ctx, ns, ctx->patterns_ns_match[i]))
+				break;
+		}
+	} T_END;
+
+	return ctx->patterns_ns_match[i] != NULL;
+}
+
+static struct mail_namespace *
+ns_next(struct ns_list_iterate_context *ctx, struct mail_namespace *ns)
+{
+	for (; ns != NULL; ns = ns->next) {
+		if (ns_match(ctx, ns))
+			break;
+	}
+	return ns;
+}
+
+static const struct mailbox_info *
+mailbox_list_ns_iter_next(struct mailbox_list_iterate_context *_ctx)
+{
+	struct ns_list_iterate_context *ctx =
+		(struct ns_list_iterate_context *)_ctx;
+	const struct mailbox_info *info;
+
+	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)
+			_ctx->failed = TRUE;
+		ctx->ctx.list->ns = ctx->namespaces;
+		ctx->backend_ctx =
+			mailbox_list_iter_init_multiple(ctx->namespaces->list,
+							ctx->patterns,
+							_ctx->flags);
+		ctx->namespaces = ns_next(ctx, ctx->namespaces->next);
+		return mailbox_list_ns_iter_next(_ctx);
+	}
+	return info;
+}
+
+static int
+mailbox_list_ns_iter_deinit(struct mailbox_list_iterate_context *_ctx)
+{
+	struct ns_list_iterate_context *ctx =
+		(struct ns_list_iterate_context *)_ctx;
+	int ret;
+
+	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;
+	unsigned int i, count;
+	pool_t pool;
+
+	i_assert(namespaces != NULL);
+
+	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;
+	ctx->ctx.list->v.iter_deinit = mailbox_list_ns_iter_deinit;
+
+	count = str_array_length(patterns);
+	ctx->patterns = p_new(pool, const char *, count + 1);
+	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 {


More information about the dovecot-cvs mailing list