dovecot-2.2: imap: Allow wildcards in GETMETADATA mailbox-name.

dovecot at dovecot.org dovecot at dovecot.org
Thu Dec 19 23:08:10 EET 2013


details:   http://hg.dovecot.org/dovecot-2.2/rev/0c3071ebe44b
changeset: 17077:0c3071ebe44b
user:      Timo Sirainen <tss at iki.fi>
date:      Thu Dec 19 23:08:03 2013 +0200
description:
imap: Allow wildcards in GETMETADATA mailbox-name.
RFC 5464 doesn't specify this, but its earlier draft did, and Kolab uses it.

diffstat:

 src/imap/cmd-getmetadata.c |  122 ++++++++++++++++++++++++++++++++------------
 1 files changed, 89 insertions(+), 33 deletions(-)

diffs (172 lines):

diff -r f64810b00b7f -r 0c3071ebe44b src/imap/cmd-getmetadata.c
--- a/src/imap/cmd-getmetadata.c	Thu Dec 19 23:07:15 2013 +0200
+++ b/src/imap/cmd-getmetadata.c	Thu Dec 19 23:08:03 2013 +0200
@@ -4,6 +4,7 @@
 #include "str.h"
 #include "istream.h"
 #include "ostream.h"
+#include "mailbox-list-iter.h"
 #include "imap-quote.h"
 #include "imap-metadata.h"
 
@@ -12,6 +13,7 @@
 
 	struct mailbox *box;
 	struct mailbox_transaction_context *trans;
+	struct mailbox_list_iterate_context *list_iter;
 
 	ARRAY_TYPE(const_string) entries;
 	uint32_t maxsize;
@@ -30,6 +32,8 @@
 	bool failed;
 };
 
+static bool cmd_getmetadata_iter_next(struct imap_getmetadata_context *ctx);
+
 static bool
 cmd_getmetadata_parse_options(struct imap_getmetadata_context *ctx,
 			      const struct imap_arg *options)
@@ -267,14 +271,37 @@
 	}
 }
 
+static void cmd_getmetadata_mailbox_deinit(struct imap_getmetadata_context *ctx)
+{
+	if (ctx->iter != NULL)
+		(void)mailbox_attribute_iter_deinit(&ctx->iter);
+	if (ctx->box != NULL) {
+		(void)mailbox_transaction_commit(&ctx->trans);
+		mailbox_free(&ctx->box);
+	}
+	ctx->first_entry_sent = FALSE;
+	ctx->entry_idx = 0;
+}
+
 static void cmd_getmetadata_deinit(struct imap_getmetadata_context *ctx)
 {
-	ctx->cmd->client->output_cmd_lock = NULL;
+	struct client_command_context *cmd = ctx->cmd;
 
-	if (ctx->iter != NULL)
-		(void)mailbox_attribute_iter_deinit(&ctx->iter);
-	(void)mailbox_transaction_commit(&ctx->trans);
-	mailbox_free(&ctx->box);
+	cmd_getmetadata_mailbox_deinit(ctx);
+	cmd->client->output_cmd_lock = NULL;
+
+	if (ctx->list_iter != NULL &&
+	    mailbox_list_iter_deinit(&ctx->list_iter) < 0)
+		client_send_list_error(cmd, cmd->client->user->namespaces->list);
+	else if (ctx->failed) {
+		client_send_tagline(cmd, "NO Getmetadata failed to send some entries");
+	} else if (ctx->largest_seen_size != 0) {
+		client_send_tagline(cmd, t_strdup_printf(
+			"OK [METADATA LONGENTRIES %"PRIuUOFF_T"] "
+			"Getmetadata completed.", ctx->largest_seen_size));
+	} else {
+		client_send_tagline(cmd, "OK Getmetadata completed.");
+	}
 }
 
 static bool cmd_getmetadata_continue(struct client_command_context *cmd)
@@ -308,14 +335,47 @@
 	if (ctx->first_entry_sent)
 		o_stream_nsend_str(cmd->client->output, ")\r\n");
 
-	if (ctx->failed) {
-		client_send_tagline(cmd, "NO Getmetadata failed to send some entries");
-	} else if (ctx->largest_seen_size != 0) {
-		client_send_tagline(cmd, t_strdup_printf(
-			"OK [METADATA LONGENTRIES %"PRIuUOFF_T"] "
-			"Getmetadata completed.", ctx->largest_seen_size));
-	} else {
-		client_send_tagline(cmd, "OK Getmetadata completed.");
+	cmd_getmetadata_mailbox_deinit(ctx);
+	if (ctx->list_iter != NULL)
+		return cmd_getmetadata_iter_next(ctx);
+	cmd_getmetadata_deinit(ctx);
+	return TRUE;
+}
+
+static bool
+cmd_getmetadata_mailbox(struct imap_getmetadata_context *ctx,
+			struct mail_namespace *ns, const char *mailbox)
+{
+	struct client_command_context *cmd = ctx->cmd;
+
+	ctx->box = mailbox_alloc(ns->list, mailbox, MAILBOX_FLAG_READONLY);
+	if (mailbox_open(ctx->box) < 0) {
+		client_send_box_error(cmd, ctx->box);
+		mailbox_free(&ctx->box);
+		return TRUE;
+	}
+	ctx->trans = mailbox_transaction_begin(ctx->box, 0);
+
+	if (ctx->depth > 0)
+		ctx->iter_entry_prefix = str_new(cmd->pool, 128);
+
+	if (!cmd_getmetadata_continue(cmd)) {
+		cmd->state = CLIENT_COMMAND_STATE_WAIT_OUTPUT;
+		cmd->func = cmd_getmetadata_continue;
+		return FALSE;
+	}
+	return TRUE;
+}
+
+static bool cmd_getmetadata_iter_next(struct imap_getmetadata_context *ctx)
+{
+	const struct mailbox_info *info;
+
+	while ((info = mailbox_list_iter_next(ctx->list_iter)) != NULL) {
+		if ((info->flags & (MAILBOX_NOSELECT | MAILBOX_NONEXISTENT)) != 0)
+			continue;
+		/* we'll get back here recursively */
+		return cmd_getmetadata_mailbox(ctx, info->ns, info->vname);
 	}
 	cmd_getmetadata_deinit(ctx);
 	return TRUE;
@@ -365,28 +425,24 @@
 		/* server attribute */
 		ctx->key_prefix = MAILBOX_ATTRIBUTE_PREFIX_DOVECOT_PVT_SERVER;
 		ns = mail_namespace_find_inbox(cmd->client->user->namespaces);
-		mailbox = "INBOX";
-	} else {
+		return cmd_getmetadata_mailbox(ctx, ns, "INBOX");
+	} else if (strchr(mailbox, '*') == NULL &&
+		   strchr(mailbox, '%') == NULL) {
 		ns = client_find_namespace(cmd, &mailbox);
 		if (ns == NULL)
 			return TRUE;
+		return cmd_getmetadata_mailbox(ctx, ns, mailbox);
+	} else {
+		/* wildcards in mailbox name. this isn't supported by RFC 5464,
+		   but it was in the earlier drafts and is already used by
+		   some software (Kolab). */
+		const char *patterns[2];
+		patterns[0] = mailbox; patterns[1] = NULL;
+
+		ctx->list_iter =
+			mailbox_list_iter_init_namespaces(
+				cmd->client->user->namespaces,
+				patterns, MAIL_NAMESPACE_TYPE_MASK_ALL, 0);
+		return cmd_getmetadata_iter_next(ctx);
 	}
-
-	ctx->box = mailbox_alloc(ns->list, mailbox, MAILBOX_FLAG_READONLY);
-	if (mailbox_open(ctx->box) < 0) {
-		client_send_box_error(cmd, ctx->box);
-		mailbox_free(&ctx->box);
-		return TRUE;
-	}
-	ctx->trans = mailbox_transaction_begin(ctx->box, 0);
-
-	if (ctx->depth > 0)
-		ctx->iter_entry_prefix = str_new(cmd->pool, 128);
-
-	if (!cmd_getmetadata_continue(cmd)) {
-		cmd->state = CLIENT_COMMAND_STATE_WAIT_OUTPUT;
-		cmd->func = cmd_getmetadata_continue;
-		return FALSE;
-	}
-	return TRUE;
 }


More information about the dovecot-cvs mailing list