Mercurial > dovecot > original-hg > dovecot-2.2
changeset 17077:0c3071ebe44b
imap: Allow wildcards in GETMETADATA mailbox-name.
RFC 5464 doesn't specify this, but its earlier draft did, and Kolab uses it.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Thu, 19 Dec 2013 23:08:03 +0200 |
parents | f64810b00b7f |
children | eb830b4196c4 |
files | src/imap/cmd-getmetadata.c |
diffstat | 1 files changed, 88 insertions(+), 32 deletions(-) [+] |
line wrap: on
line diff
--- 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; + + cmd_getmetadata_mailbox_deinit(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->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; - } - - 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); + 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; - 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; + 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); } - return TRUE; }