]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
imap: Allow wildcards in GETMETADATA mailbox-name.
authorTimo Sirainen <tss@iki.fi>
Thu, 19 Dec 2013 21:08:03 +0000 (23:08 +0200)
committerTimo Sirainen <tss@iki.fi>
Thu, 19 Dec 2013 21:08:03 +0000 (23:08 +0200)
RFC 5464 doesn't specify this, but its earlier draft did, and Kolab uses it.

src/imap/cmd-getmetadata.c

index 73759e0b47f48039a984abb212acc1ddaf167723..2a73c8aa3146710539002cfa63ed5dcab70e04ae 100644 (file)
@@ -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 imap_getmetadata_context {
 
        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 @@ struct imap_getmetadata_context {
        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 int cmd_getmetadata_send_entry_tree(struct imap_getmetadata_context *ctx,
        }
 }
 
-static void cmd_getmetadata_deinit(struct imap_getmetadata_context *ctx)
+static void cmd_getmetadata_mailbox_deinit(struct imap_getmetadata_context *ctx)
 {
-       ctx->cmd->client->output_cmd_lock = NULL;
-
        if (ctx->iter != NULL)
                (void)mailbox_attribute_iter_deinit(&ctx->iter);
-       (void)mailbox_transaction_commit(&ctx->trans);
-       mailbox_free(&ctx->box);
+       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)
+{
+       struct client_command_context *cmd = ctx->cmd;
+
+       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 @@ static bool cmd_getmetadata_continue(struct client_command_context *cmd)
        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 @@ bool cmd_getmetadata(struct client_command_context *cmd)
                /* 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;
 }