dovecot-2.2: Moved most of the IMAP LIST code to lib-storage.

dovecot at dovecot.org dovecot at dovecot.org
Thu Aug 30 21:12:40 EEST 2012


details:   http://hg.dovecot.org/dovecot-2.2/rev/5ffcde8baa8a
changeset: 14986:5ffcde8baa8a
user:      Timo Sirainen <tss at iki.fi>
date:      Thu Aug 30 21:12:23 2012 +0300
description:
Moved most of the IMAP LIST code to lib-storage.
Also removed MAILBOX_LIST_ITER_SHOW_EXISTING_PARENT flag, since there wasn't
any clearly good way to handle it. Some clients got confused when they saw
that foo/ mailbox was returned with \Noselect flag. Either they thought that
the mailbox was named foo/ or that foo was \Noselect. Pretty much the only
sane way to handle this would be to not make return \Noselect and to treat
foo and foo/ as equivalent in all commands, but that might cause trouble
with ACLs and similar checks..

diffstat:

 src/imap/cmd-list.c                         |  658 ++-------------------------
 src/lib-storage/list/mailbox-list-fs-iter.c |   17 +-
 src/lib-storage/mailbox-list-iter.c         |  411 +++++++++++++---
 src/lib-storage/mailbox-list.h              |    4 -
 4 files changed, 379 insertions(+), 711 deletions(-)

diffs (truncated from 1351 to 300 lines):

diff -r e4c09527aa9e -r 5ffcde8baa8a src/imap/cmd-list.c
--- a/src/imap/cmd-list.c	Thu Aug 30 18:44:43 2012 +0300
+++ b/src/imap/cmd-list.c	Thu Aug 30 21:12:23 2012 +0300
@@ -14,24 +14,15 @@
 
 struct cmd_list_context {
 	struct client_command_context *cmd;
-	const char *ref;
-	const char *const *patterns;
+	struct mail_user *user;
+
 	enum mailbox_list_iter_flags list_flags;
 	struct imap_status_items status_items;
-	enum mailbox_info_flags inbox_flags;
 
-	struct mail_namespace *ns;
 	struct mailbox_list_iterate_context *list_iter;
 
-	ARRAY(struct mail_namespace *) ns_prefixes_listed;
-
 	unsigned int lsub:1;
 	unsigned int lsub_no_unsubscribed:1;
-	unsigned int inbox_found:1;
-	unsigned int seen_inbox_namespace:1;
-	unsigned int cur_ns_match_inbox:1;
-	unsigned int cur_ns_send_prefix:1;
-	unsigned int cur_ns_skip_trailing_sep:1;
 	unsigned int used_listext:1;
 	unsigned int used_status:1;
 };
@@ -164,90 +155,6 @@
 	return TRUE;
 }
 
-static enum mailbox_info_flags
-list_get_inbox_flags(struct cmd_list_context *ctx)
-{
-	struct mail_namespace *ns;
-	struct mailbox_list_iterate_context *list_iter;
-	const struct mailbox_info *info;
-	enum mailbox_info_flags flags = MAILBOX_UNMARKED;
-
-	if (ctx->seen_inbox_namespace &&
-	    (ctx->ns->flags & NAMESPACE_FLAG_INBOX_USER) == 0) {
-		/* INBOX doesn't exist. use the default INBOX flags */
-		return flags;
-	}
-
-	/* find the INBOX flags */
-	ns = mail_namespace_find_inbox(ctx->cmd->client->user->namespaces);
-	list_iter = mailbox_list_iter_init(ns->list, "INBOX", 0);
-	info = mailbox_list_iter_next(list_iter);
-	if (info != NULL) {
-		i_assert(strcasecmp(info->vname, "INBOX") == 0);
-		flags = info->flags;
-	}
-	(void)mailbox_list_iter_deinit(&list_iter);
-	return flags;
-}
-
-static bool list_namespace_has_children(struct cmd_list_context *ctx)
-{
-	enum mailbox_list_iter_flags list_flags =
-		MAILBOX_LIST_ITER_RETURN_NO_FLAGS;
-	struct mailbox_list_iterate_context *list_iter;
-	const struct mailbox_info *info;
-	bool ret = FALSE;
-
-	if ((ctx->list_flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) != 0)
-		list_flags |= MAILBOX_LIST_ITER_SELECT_SUBSCRIBED;
-
-	list_iter = mailbox_list_iter_init(ctx->ns->list,
-		t_strconcat(ctx->ns->prefix, "%", NULL), list_flags);
-	info = mailbox_list_iter_next(list_iter);
-	if (info != NULL)
-		ret = TRUE;
-	if (mailbox_list_iter_deinit(&list_iter) < 0) {
-		/* safer to answer TRUE in error conditions */
-		ret = TRUE;
-	}
-	return ret;
-}
-
-static const char *ns_get_listed_prefix(struct cmd_list_context *ctx)
-{
-	struct imap_match_glob *glob;
-	enum imap_match_result match;
-	const char *ns_prefix, *p;
-	bool inboxcase;
-	unsigned int skip_len;
-
-	skip_len = strlen(ctx->ref);
-	if (strncmp(ctx->ns->prefix, ctx->ref, skip_len) != 0)
-		skip_len = 0;
-
-	inboxcase = strncasecmp(ctx->ns->prefix, "INBOX", 5) == 0 &&
-		ctx->ns->prefix[5] == mail_namespace_get_sep(ctx->ns);
-	glob = imap_match_init_multiple(pool_datastack_create(),
-					ctx->patterns, inboxcase,
-					mail_namespace_get_sep(ctx->ns));
-	ns_prefix = ctx->ns->prefix + skip_len;
-	match = imap_match(glob, ns_prefix);
-	if (match == IMAP_MATCH_YES) {
-		return !ctx->cur_ns_skip_trailing_sep ? ctx->ns->prefix :
-			t_strndup(ctx->ns->prefix, strlen(ctx->ns->prefix)-1);
-	}
-
-	while ((match & IMAP_MATCH_PARENT) != 0) {
-		p = strrchr(ns_prefix, mail_namespace_get_sep(ctx->ns));
-		i_assert(p != NULL);
-		ns_prefix = t_strdup_until(ns_prefix, p);
-		match = imap_match(glob, ns_prefix);
-	}
-	i_assert(match == IMAP_MATCH_YES);
-	return t_strconcat(t_strndup(ctx->ns->prefix, skip_len),
-			   ns_prefix, NULL);
-}
-
 static void list_reply_append_ns_sep_param(string_t *str, char sep)
 {
 	str_append_c(str, '"');
@@ -259,101 +166,6 @@
 }
 
 static void
-list_namespace_send_prefix(struct cmd_list_context *ctx, bool have_children)
-{
-	struct mail_namespace *const *listed;
-	const struct mailbox_settings *mailbox_set;
-	struct mailbox *box;
-	enum mailbox_existence existence;
-	unsigned int len;
-	enum mailbox_info_flags flags;
-	const char *name;
-	string_t *str;
-	bool same_ns, ends_with_sep;
-	char ns_sep = mail_namespace_get_sep(ctx->ns);
-
-	ctx->cur_ns_send_prefix = FALSE;
-
-	/* see if we already listed this as a valid mailbox in another
-	   namespace */
-	array_foreach(&ctx->ns_prefixes_listed, listed) {
-		if (*listed == ctx->ns)
-			return;
-	}
-
-	name = ns_get_listed_prefix(ctx);
-	len = strlen(ctx->ns->prefix);
-	ends_with_sep = ctx->ns->prefix[len-1] == ns_sep;
-
-	/* we may be listing namespace's parent. in such case we always want to
-	   set the name as nonexistent. */
-	same_ns = strcmp(name, ctx->ns->prefix) == 0 ||
-		(strncmp(name, ctx->ns->prefix, len - 1) == 0 && ends_with_sep);
-	if (len == 6 && strncasecmp(ctx->ns->prefix, "INBOX", len-1) == 0 &&
-	    ends_with_sep) {
-		/* INBOX namespace needs to be handled specially. */
-		if (ctx->inbox_found) {
-			/* we're just now going to send it */
-			return;
-		}
-
-		ctx->inbox_found = TRUE;
-		flags = list_get_inbox_flags(ctx);
-	} else if (!same_ns) {
-		/* parent */
-		flags = MAILBOX_NONEXISTENT;
-	} else {
-		/* see if namespace prefix is selectable */
-		box = mailbox_alloc(ctx->ns->list, name, 0);
-		if (mailbox_exists(box, TRUE, &existence) == 0 &&
-		    existence == MAILBOX_EXISTENCE_SELECT)
-			flags = MAILBOX_SELECT;
-		else
-			flags = MAILBOX_NONEXISTENT;
-		mailbox_free(&box);
-	}
-
-	if ((flags & MAILBOX_CHILDREN) == 0) {
-		if (have_children || list_namespace_has_children(ctx)) {
-			flags |= MAILBOX_CHILDREN;
-			flags &= ~MAILBOX_NOCHILDREN;
-		} else {
-			flags |= MAILBOX_NOCHILDREN;
-		}
-	}
-
-	if ((ctx->ns->flags & NAMESPACE_FLAG_LIST_CHILDREN) != 0 ||
-	    (ctx->list_flags & MAILBOX_LIST_ITER_SELECT_SUBSCRIBED) != 0) {
-		if (have_children) {
-			/* children are going to be listed. */
-			return;
-		}
-		if ((flags & MAILBOX_CHILDREN) == 0) {
-			/* namespace has no children. don't show it. */
-			return;
-		}
-		/* namespace has children but they don't match the list
-		   pattern. the prefix itself matches though, so show it. */
-	}
-
-	str = t_str_new(128);
-	str_printfa(str, "* %s (", ctx->lsub ? "LSUB" : "LIST");
-	if (ctx->lsub)
-		flags |= MAILBOX_NONEXISTENT;
-	mailbox_set = (ctx->list_flags & MAILBOX_LIST_ITER_RETURN_SPECIALUSE) == 0 ? NULL :
-		mailbox_settings_find(ctx->cmd->client->user, name);
-	mailbox_flags2str(ctx, str, mailbox_set == NULL ? NULL :
-			  mailbox_set->special_use, flags);
-	str_append(str, ") ");
-	list_reply_append_ns_sep_param(str, ns_sep);
-	str_append_c(str, ' ');
-	imap_quote_append_string(str, name, FALSE);
-	mailbox_childinfo2str(ctx, str, flags);
-
-	client_send_line(ctx->cmd->client, str_c(str));
-}
-
-static void
 list_send_status(struct cmd_list_context *ctx, const char *name,
 		 const char *mutf7_name, enum mailbox_info_flags flags)
 {
@@ -372,7 +184,7 @@
 
 	/* if we're listing subscriptions and there are subscriptions=no
 	   namespaces, ctx->ns may not point to correct one */
-	ns = mail_namespace_find(ctx->ns->user->namespaces, name);
+	ns = mail_namespace_find(ctx->user->namespaces, name);
 	if (imap_status_get(ctx->cmd, ns, name,
 			    &ctx->status_items, &result) < 0) {
 		client_send_line(ctx->cmd->client,
@@ -384,71 +196,26 @@
 			 &ctx->status_items, &result);
 }
 
-static bool list_has_empty_prefix_ns(struct mail_user *user)
+static bool cmd_list_continue(struct client_command_context *cmd)
 {
-	struct mail_namespace *ns;
-
-	ns = mail_namespace_find_prefix(user->namespaces, "");
-	return ns != NULL && (ns->flags & (NAMESPACE_FLAG_LIST_PREFIX |
-					   NAMESPACE_FLAG_LIST_CHILDREN)) != 0;
-}
-
-static int
-list_namespace_mailboxes(struct cmd_list_context *ctx)
-{
+        struct cmd_list_context *ctx = cmd->context;
 	const struct mailbox_info *info;
-	struct mail_namespace *ns;
 	enum mailbox_info_flags flags;
 	string_t *str, *mutf7_name;
 	const char *name;
 	int ret = 0;
 
+	if (cmd->cancel) {
+		if (ctx->list_iter != NULL)
+			(void)mailbox_list_iter_deinit(&ctx->list_iter);
+		return TRUE;
+	}
 	str = t_str_new(256);
 	mutf7_name = t_str_new(128);
 	while ((info = mailbox_list_iter_next(ctx->list_iter)) != NULL) {
 		name = info->vname;
 		flags = info->flags;
 
-		if (strcasecmp(name, "INBOX") == 0) {
-			if (ctx->inbox_found) {
-				/* we already listed this at the beginning
-				   of handling INBOX/ namespace */
-				continue;
-			}
-			if ((ctx->ns->flags & NAMESPACE_FLAG_INBOX_USER) == 0) {
-				/* INBOX is in non-empty prefix namespace,
-				   and we're now listing prefixless namespace
-				   that contains INBOX. There's no way we can
-				   show this mailbox. */
-				ctx->inbox_flags = flags &
-					(MAILBOX_CHILDREN|MAILBOX_NOCHILDREN);
-				continue;
-			}
-
-			if (*info->ns->prefix != '\0' &&
-			    list_has_empty_prefix_ns(info->ns->user)) {
-				/* INBOX is in its own namespace, while a
-				   namespace with prefix="" has its children. */
-				flags &= ~(MAILBOX_CHILDREN|MAILBOX_NOCHILDREN|
-					   MAILBOX_NOINFERIORS);
-				flags |= ctx->inbox_flags;
-			}
-			ctx->inbox_found = TRUE;
-		}
-		if (ctx->cur_ns_send_prefix)
-			list_namespace_send_prefix(ctx, TRUE);
-
-		/* if there's a list=yes namespace with this name, list it as
-		   having children */
-		ns = mail_namespace_find_prefix_nosep(ctx->ns, name);


More information about the dovecot-cvs mailing list