bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen#include "imap-common.h"
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen#include "str.h"
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen#include "istream.h"
0e0fe9bed9a2be8760acf93abc6e16758195ef38Timo Sirainen#include "istream-sized.h"
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen#include "ostream.h"
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen#include "mailbox-list-iter.h"
5d786275b6a866622860729834096b0a2ad11c97Timo Sirainen#include "imap-utf7.h"
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen#include "imap-quote.h"
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen#include "imap-metadata.h"
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenstruct imap_getmetadata_context {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen struct client_command_context *cmd;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen struct mailbox *box;
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch struct imap_metadata_transaction *trans;
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen struct mailbox_list_iterate_context *list_iter;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen ARRAY_TYPE(const_string) entries;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen uint32_t maxsize;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen uoff_t largest_seen_size;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen unsigned int depth;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen struct istream *cur_stream;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch struct imap_metadata_iter *iter;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen string_t *iter_entry_prefix;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
a1a79357a8d8e18806fd9888559939b7f60c4426Timo Sirainen string_t *delayed_errors;
a1a79357a8d8e18806fd9888559939b7f60c4426Timo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen unsigned int entry_idx;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen bool first_entry_sent;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen bool failed;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen};
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Boschstatic bool
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Boschcmd_getmetadata_mailbox_iter_next(struct imap_getmetadata_context *ctx);
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenstatic bool
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainencmd_getmetadata_parse_options(struct imap_getmetadata_context *ctx,
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen const struct imap_arg *options)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen{
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen const char *value;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen while (!IMAP_ARG_IS_EOL(options)) {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (imap_arg_atom_equals(options, "MAXSIZE")) {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen options++;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (!imap_arg_get_atom(options, &value) ||
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen str_to_uint32(value, &ctx->maxsize) < 0) {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen client_send_command_error(ctx->cmd,
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen "Invalid value for MAXSIZE option");
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return FALSE;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen } else if (imap_arg_atom_equals(options, "DEPTH")) {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen options++;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (!imap_arg_get_atom(options, &value)) {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen client_send_command_error(ctx->cmd,
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen "Invalid value for DEPTH option");
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return FALSE;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (strcmp(value, "0") == 0)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen ctx->depth = 0;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen else if (strcmp(value, "1") == 0)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen ctx->depth = 1;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen else if (strcmp(value, "infinity") == 0)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen ctx->depth = UINT_MAX;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen else {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen client_send_command_error(ctx->cmd,
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen "Invalid value for DEPTH option");
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return FALSE;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen } else {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen client_send_command_error(ctx->cmd, "Unknown option");
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return FALSE;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen options++;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return TRUE;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen}
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenstatic bool
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenimap_metadata_parse_entry_names(struct imap_getmetadata_context *ctx,
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen const struct imap_arg *entries)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen{
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch const char *value, *error;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen p_array_init(&ctx->entries, ctx->cmd->pool, 4);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen for (; !IMAP_ARG_IS_EOL(entries); entries++) {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (!imap_arg_get_astring(entries, &value)) {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen client_send_command_error(ctx->cmd, "Entry isn't astring");
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return FALSE;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch if (!imap_metadata_verify_entry_name(value, &error)) {
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch client_send_command_error(ctx->cmd, error);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return FALSE;
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch }
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen /* names are case-insensitive so we'll always lowercase them */
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen value = p_strdup(ctx->cmd->pool, t_str_lcase(value));
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen array_append(&ctx->entries, &value, 1);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return TRUE;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen}
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainenstatic string_t *
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainenmetadata_add_entry(struct imap_getmetadata_context *ctx, const char *entry)
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainen{
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainen string_t *str;
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainen
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainen str = t_str_new(64);
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainen if (!ctx->first_entry_sent) {
5d786275b6a866622860729834096b0a2ad11c97Timo Sirainen string_t *mailbox_mutf7 = t_str_new(64);
5d786275b6a866622860729834096b0a2ad11c97Timo Sirainen
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainen ctx->first_entry_sent = TRUE;
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainen str_append(str, "* METADATA ");
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch if (ctx->box == NULL) {
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch /* server metadata reply */
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch str_append(str, "\"\"");
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch } else {
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch if (imap_utf8_to_utf7(mailbox_get_vname(ctx->box), mailbox_mutf7) < 0)
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch i_unreached();
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch imap_append_astring(str, str_c(mailbox_mutf7));
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch }
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainen str_append(str, " (");
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainen
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainen /* nothing can be sent until untagged METADATA is finished */
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainen ctx->cmd->client->output_cmd_lock = ctx->cmd;
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainen } else {
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainen str_append_c(str, ' ');
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainen }
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainen imap_append_astring(str, entry);
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainen return str;
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainen}
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainen
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainenstatic void
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainencmd_getmetadata_send_nil_reply(struct imap_getmetadata_context *ctx,
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainen const char *entry)
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainen{
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainen string_t *str;
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainen
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainen /* client requested a specific entry that didn't exist.
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainen we must return it as NIL. */
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainen str = metadata_add_entry(ctx, entry);
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainen str_append(str, " NIL");
6d0e6c57cf45ad517748cfbb5f3aa3b53e42e3d0Martti Rannanjärvi o_stream_nsend(ctx->cmd->client->output, str_data(str), str_len(str));
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainen}
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenstatic void cmd_getmetadata_send_entry(struct imap_getmetadata_context *ctx,
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainen const char *entry, bool require_reply)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen{
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch struct client *client = ctx->cmd->client;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen struct mail_attribute_value value;
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch const char *error_string;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen enum mail_error error;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen uoff_t value_len;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen string_t *str;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch if (imap_metadata_get_stream(ctx->trans, entry, &value) < 0) {
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch error_string = imap_metadata_transaction_get_last_error(
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch ctx->trans, &error);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (error != MAIL_ERROR_NOTFOUND && error != MAIL_ERROR_PERM) {
a1a79357a8d8e18806fd9888559939b7f60c4426Timo Sirainen str_printfa(ctx->delayed_errors, "* NO %s\r\n",
a1a79357a8d8e18806fd9888559939b7f60c4426Timo Sirainen error_string);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen ctx->failed = TRUE;
a1a79357a8d8e18806fd9888559939b7f60c4426Timo Sirainen return;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (value.value != NULL)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen value_len = strlen(value.value);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen else if (value.value_stream != NULL) {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (i_stream_get_size(value.value_stream, TRUE, &value_len) < 0) {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen i_error("GETMETADATA %s: i_stream_get_size(%s) failed: %s", entry,
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen i_stream_get_name(value.value_stream),
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen i_stream_get_error(value.value_stream));
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen i_stream_unref(&value.value_stream);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen ctx->failed = TRUE;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen } else {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen /* skip nonexistent entries */
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainen if (require_reply)
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainen cmd_getmetadata_send_nil_reply(ctx, entry);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (value_len > ctx->maxsize) {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen /* value length is larger than specified MAXSIZE,
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen skip this entry */
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (ctx->largest_seen_size < value_len)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen ctx->largest_seen_size = value_len;
204ee6ed414f5e4eeb6f6c10763b55daf56f11acJosef 'Jeff' Sipek i_stream_unref(&value.value_stream);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainen str = metadata_add_entry(ctx, entry);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (value.value != NULL) {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen str_printfa(str, " {%"PRIuUOFF_T"}\r\n%s", value_len, value.value);
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch o_stream_nsend(client->output, str_data(str), str_len(str));
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen } else {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen str_printfa(str, " ~{%"PRIuUOFF_T"}\r\n", value_len);
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch o_stream_nsend(client->output, str_data(str), str_len(str));
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
0e0fe9bed9a2be8760acf93abc6e16758195ef38Timo Sirainen ctx->cur_stream = i_stream_create_sized(value.value_stream, value_len);
0e0fe9bed9a2be8760acf93abc6e16758195ef38Timo Sirainen i_stream_unref(&value.value_stream);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen}
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenstatic bool
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainencmd_getmetadata_stream_continue(struct imap_getmetadata_context *ctx)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen{
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen enum ostream_send_istream_result res;
0e0fe9bed9a2be8760acf93abc6e16758195ef38Timo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen o_stream_set_max_buffer_size(ctx->cmd->client->output, 0);
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen res = o_stream_send_istream(ctx->cmd->client->output, ctx->cur_stream);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen o_stream_set_max_buffer_size(ctx->cmd->client->output, (size_t)-1);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen switch (res) {
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen case OSTREAM_SEND_ISTREAM_RESULT_FINISHED:
0e0fe9bed9a2be8760acf93abc6e16758195ef38Timo Sirainen return TRUE;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen case OSTREAM_SEND_ISTREAM_RESULT_WAIT_INPUT:
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen i_unreached();
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen case OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT:
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen return FALSE;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen case OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT:
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen i_error("read(%s) failed: %s",
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen i_stream_get_name(ctx->cur_stream),
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen i_stream_get_error(ctx->cur_stream));
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen client_disconnect(ctx->cmd->client,
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen "Internal GETMETADATA failure");
ed7b5bc903a450a10f0c66820d3b579854ba0923Phil Carmody return TRUE;
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen case OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT:
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen /* client disconnected */
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen return TRUE;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
378e6cb162b355d6f103526505bc00b9a78962e7Timo Sirainen i_unreached();
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen}
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Boschstatic int
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Boschcmd_getmetadata_send_entry_tree(struct imap_getmetadata_context *ctx,
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen const char *entry)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen{
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch struct client *client = ctx->cmd->client;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch if (o_stream_get_buffer_used_size(client->output) >=
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen CLIENT_OUTPUT_OPTIMAL_SIZE) {
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch if (o_stream_flush(client->output) <= 0) {
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch o_stream_set_flush_pending(client->output, TRUE);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return 0;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (ctx->iter != NULL) {
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch const char *subentry;
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen /* DEPTH iteration */
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen do {
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch subentry = imap_metadata_iter_next(ctx->iter);
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch if (subentry == NULL) {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen /* iteration finished, get to the next entry */
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch if (imap_metadata_iter_deinit(&ctx->iter) < 0) {
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch enum mail_error error;
a1a79357a8d8e18806fd9888559939b7f60c4426Timo Sirainen
a1a79357a8d8e18806fd9888559939b7f60c4426Timo Sirainen str_printfa(ctx->delayed_errors, "* NO %s\r\n",
a1a79357a8d8e18806fd9888559939b7f60c4426Timo Sirainen imap_metadata_transaction_get_last_error(ctx->trans, &error));
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen ctx->failed = TRUE;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return -1;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch } while (ctx->depth == 1 && strchr(subentry, '/') != NULL);
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch entry = t_strconcat(str_c(ctx->iter_entry_prefix), subentry, NULL);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
a5c1051a846db2aa91473ecced02d8d91f249357Timo Sirainen cmd_getmetadata_send_entry(ctx, entry, ctx->iter == NULL);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (ctx->cur_stream != NULL) {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (!cmd_getmetadata_stream_continue(ctx))
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return 0;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen i_stream_unref(&ctx->cur_stream);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (ctx->iter != NULL) {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen /* already iterating the entry */
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return 1;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen } else if (ctx->depth == 0) {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen /* no iteration for the entry */
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return -1;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen } else {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen /* we just sent the entry root. iterate its children. */
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen str_truncate(ctx->iter_entry_prefix, 0);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen str_append(ctx->iter_entry_prefix, entry);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen str_append_c(ctx->iter_entry_prefix, '/');
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch ctx->iter = imap_metadata_iter_init(ctx->trans, entry);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return 1;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen}
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Boschstatic void cmd_getmetadata_iter_deinit(struct imap_getmetadata_context *ctx)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen{
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (ctx->iter != NULL)
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch (void)imap_metadata_iter_deinit(&ctx->iter);
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch if (ctx->trans != NULL)
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch (void)imap_metadata_transaction_commit(&ctx->trans, NULL, NULL);
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch if (ctx->box != NULL)
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen mailbox_free(&ctx->box);
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen ctx->first_entry_sent = FALSE;
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen ctx->entry_idx = 0;
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen}
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainenstatic void cmd_getmetadata_deinit(struct imap_getmetadata_context *ctx)
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen{
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen struct client_command_context *cmd = ctx->cmd;
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch cmd_getmetadata_iter_deinit(ctx);
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen cmd->client->output_cmd_lock = NULL;
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen if (ctx->list_iter != NULL &&
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen mailbox_list_iter_deinit(&ctx->list_iter) < 0)
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen client_send_list_error(cmd, cmd->client->user->namespaces->list);
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen else if (ctx->failed) {
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen client_send_tagline(cmd, "NO Getmetadata failed to send some entries");
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen } else if (ctx->largest_seen_size != 0) {
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen client_send_tagline(cmd, t_strdup_printf(
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen "OK [METADATA LONGENTRIES %"PRIuUOFF_T"] "
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen "Getmetadata completed.", ctx->largest_seen_size));
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen } else {
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen client_send_tagline(cmd, "OK Getmetadata completed.");
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen }
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen}
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenstatic bool cmd_getmetadata_continue(struct client_command_context *cmd)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen{
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen struct imap_getmetadata_context *ctx = cmd->context;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen const char *const *entries;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen unsigned int count;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen int ret;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (cmd->cancel) {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen cmd_getmetadata_deinit(ctx);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return TRUE;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (ctx->cur_stream != NULL) {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (!cmd_getmetadata_stream_continue(ctx))
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return FALSE;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen i_stream_unref(&ctx->cur_stream);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen entries = array_get(&ctx->entries, &count);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen for (; ctx->entry_idx < count; ctx->entry_idx++) {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen do {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen T_BEGIN {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen ret = cmd_getmetadata_send_entry_tree(ctx, entries[ctx->entry_idx]);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen } T_END;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (ret == 0)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return FALSE;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen } while (ret > 0);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (ctx->first_entry_sent)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen o_stream_nsend_str(cmd->client->output, ")\r\n");
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
a1a79357a8d8e18806fd9888559939b7f60c4426Timo Sirainen if (str_len(ctx->delayed_errors) > 0) {
a1a79357a8d8e18806fd9888559939b7f60c4426Timo Sirainen o_stream_nsend(cmd->client->output,
a1a79357a8d8e18806fd9888559939b7f60c4426Timo Sirainen str_data(ctx->delayed_errors),
a1a79357a8d8e18806fd9888559939b7f60c4426Timo Sirainen str_len(ctx->delayed_errors));
a1a79357a8d8e18806fd9888559939b7f60c4426Timo Sirainen str_truncate(ctx->delayed_errors, 0);
a1a79357a8d8e18806fd9888559939b7f60c4426Timo Sirainen }
a1a79357a8d8e18806fd9888559939b7f60c4426Timo Sirainen
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch cmd_getmetadata_iter_deinit(ctx);
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen if (ctx->list_iter != NULL)
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch return cmd_getmetadata_mailbox_iter_next(ctx);
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen cmd_getmetadata_deinit(ctx);
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen return TRUE;
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen}
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Boschstatic bool
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Boschcmd_getmetadata_start(struct imap_getmetadata_context *ctx)
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen{
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen struct client_command_context *cmd = ctx->cmd;
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen if (ctx->depth > 0)
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen ctx->iter_entry_prefix = str_new(cmd->pool, 128);
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen if (!cmd_getmetadata_continue(cmd)) {
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen cmd->state = CLIENT_COMMAND_STATE_WAIT_OUTPUT;
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen cmd->func = cmd_getmetadata_continue;
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch return FALSE;
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen }
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch return TRUE;
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch}
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Boschstatic bool
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Boschcmd_getmetadata_server(struct imap_getmetadata_context *ctx)
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch{
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch ctx->trans = imap_metadata_transaction_begin_server(ctx->cmd->client->user);
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch return cmd_getmetadata_start(ctx);
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch}
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Boschstatic int
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Boschcmd_getmetadata_try_mailbox(struct imap_getmetadata_context *ctx,
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch struct mail_namespace *ns, const char *mailbox)
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch{
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch ctx->box = mailbox_alloc(ns->list, mailbox, MAILBOX_FLAG_READONLY);
61cf001f1944d92eb25f113ba4c08985d6e30d53Timo Sirainen mailbox_set_reason(ctx->box, "GETMETADATA");
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch if (mailbox_open(ctx->box) < 0)
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch return -1;
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch ctx->trans = imap_metadata_transaction_begin(ctx->box);
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch return cmd_getmetadata_start(ctx) ? 1 : 0;
730f8250fe4f840e2f708b9648e90e0069772088Timo Sirainen}
730f8250fe4f840e2f708b9648e90e0069772088Timo Sirainen
730f8250fe4f840e2f708b9648e90e0069772088Timo Sirainenstatic bool
730f8250fe4f840e2f708b9648e90e0069772088Timo Sirainencmd_getmetadata_mailbox(struct imap_getmetadata_context *ctx,
730f8250fe4f840e2f708b9648e90e0069772088Timo Sirainen struct mail_namespace *ns, const char *mailbox)
730f8250fe4f840e2f708b9648e90e0069772088Timo Sirainen{
730f8250fe4f840e2f708b9648e90e0069772088Timo Sirainen int ret;
730f8250fe4f840e2f708b9648e90e0069772088Timo Sirainen
730f8250fe4f840e2f708b9648e90e0069772088Timo Sirainen ret = cmd_getmetadata_try_mailbox(ctx, ns, mailbox);
730f8250fe4f840e2f708b9648e90e0069772088Timo Sirainen if (ret < 0) {
730f8250fe4f840e2f708b9648e90e0069772088Timo Sirainen client_send_box_error(ctx->cmd, ctx->box);
730f8250fe4f840e2f708b9648e90e0069772088Timo Sirainen mailbox_free(&ctx->box);
730f8250fe4f840e2f708b9648e90e0069772088Timo Sirainen }
730f8250fe4f840e2f708b9648e90e0069772088Timo Sirainen return ret != 0;
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen}
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Boschstatic bool
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Boschcmd_getmetadata_mailbox_iter_next(struct imap_getmetadata_context *ctx)
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen{
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen const struct mailbox_info *info;
730f8250fe4f840e2f708b9648e90e0069772088Timo Sirainen int ret;
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen while ((info = mailbox_list_iter_next(ctx->list_iter)) != NULL) {
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen if ((info->flags & (MAILBOX_NOSELECT | MAILBOX_NONEXISTENT)) != 0)
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen continue;
730f8250fe4f840e2f708b9648e90e0069772088Timo Sirainen ret = cmd_getmetadata_try_mailbox(ctx, info->ns, info->vname);
730f8250fe4f840e2f708b9648e90e0069772088Timo Sirainen if (ret > 0) {
730f8250fe4f840e2f708b9648e90e0069772088Timo Sirainen /* we'll already recursively went through
730f8250fe4f840e2f708b9648e90e0069772088Timo Sirainen all the mailboxes (FIXME: ugly and potentially
730f8250fe4f840e2f708b9648e90e0069772088Timo Sirainen stack consuming) */
730f8250fe4f840e2f708b9648e90e0069772088Timo Sirainen return TRUE;
730f8250fe4f840e2f708b9648e90e0069772088Timo Sirainen } else if (ret == 0) {
730f8250fe4f840e2f708b9648e90e0069772088Timo Sirainen /* need to send more data later */
730f8250fe4f840e2f708b9648e90e0069772088Timo Sirainen return FALSE;
730f8250fe4f840e2f708b9648e90e0069772088Timo Sirainen }
730f8250fe4f840e2f708b9648e90e0069772088Timo Sirainen T_BEGIN {
730f8250fe4f840e2f708b9648e90e0069772088Timo Sirainen client_send_line(ctx->cmd->client, t_strdup_printf(
730f8250fe4f840e2f708b9648e90e0069772088Timo Sirainen "* NO Failed to open mailbox %s: %s",
730f8250fe4f840e2f708b9648e90e0069772088Timo Sirainen info->vname, mailbox_get_last_error(ctx->box, NULL)));
730f8250fe4f840e2f708b9648e90e0069772088Timo Sirainen } T_END;
730f8250fe4f840e2f708b9648e90e0069772088Timo Sirainen mailbox_free(&ctx->box);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen cmd_getmetadata_deinit(ctx);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return TRUE;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen}
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainenbool cmd_getmetadata(struct client_command_context *cmd)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen{
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen struct imap_getmetadata_context *ctx;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen struct mail_namespace *ns;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen const struct imap_arg *args, *options, *entries;
954bbe7f868d4cde546b73306a7e9c1918f2256eTimo Sirainen const char *mailbox, *entry_name;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (!client_read_args(cmd, 0, 0, &args))
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return FALSE;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (!cmd->client->imap_metadata_enabled) {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen client_send_command_error(cmd, "METADATA disabled.");
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return TRUE;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen ctx = p_new(cmd->pool, struct imap_getmetadata_context, 1);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen ctx->cmd = cmd;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen ctx->maxsize = (uint32_t)-1;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen ctx->cmd->context = ctx;
a1a79357a8d8e18806fd9888559939b7f60c4426Timo Sirainen ctx->delayed_errors = str_new(cmd->pool, 128);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (imap_arg_get_list(&args[0], &options)) {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (!cmd_getmetadata_parse_options(ctx, options))
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return TRUE;
77b4e728245a1905b1cce68fce9e9b7adf7efc2cTimo Sirainen args++;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
77b4e728245a1905b1cce68fce9e9b7adf7efc2cTimo Sirainen if (!imap_arg_get_astring(&args[0], &mailbox)) {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen client_send_command_error(cmd, "Invalid arguments.");
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return TRUE;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
77b4e728245a1905b1cce68fce9e9b7adf7efc2cTimo Sirainen if (!imap_arg_get_list(&args[1], &entries)) {
77b4e728245a1905b1cce68fce9e9b7adf7efc2cTimo Sirainen if (!imap_arg_get_astring(&args[1], &entry_name) ||
77b4e728245a1905b1cce68fce9e9b7adf7efc2cTimo Sirainen !IMAP_ARG_IS_EOL(&args[2])) {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen client_send_command_error(cmd, "Invalid arguments.");
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return TRUE;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
77b4e728245a1905b1cce68fce9e9b7adf7efc2cTimo Sirainen entries = args+1;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (!imap_metadata_parse_entry_names(ctx, entries))
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return TRUE;
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (mailbox[0] == '\0') {
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen /* server attribute */
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch return cmd_getmetadata_server(ctx);
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen } else if (strchr(mailbox, '*') == NULL &&
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen strchr(mailbox, '%') == NULL) {
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch /* mailbox attribute */
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen ns = client_find_namespace(cmd, &mailbox);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen if (ns == NULL)
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen return TRUE;
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen return cmd_getmetadata_mailbox(ctx, ns, mailbox);
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen } else {
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen /* wildcards in mailbox name. this isn't supported by RFC 5464,
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen but it was in the earlier drafts and is already used by
08b0192ede9e06c6e56363e96c1eee9c913c1a29Timo Sirainen some software (Horde). */
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen const char *patterns[2];
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen patterns[0] = mailbox; patterns[1] = NULL;
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen ctx->list_iter =
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen mailbox_list_iter_init_namespaces(
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen cmd->client->user->namespaces,
b6709d9c413338d32187fb0cf5ba32abaf16c20eTimo Sirainen patterns, MAIL_NAMESPACE_TYPE_MASK_ALL, 0);
8ccdf195768afdfbc32088d7be77dfca7dddd829Stephan Bosch return cmd_getmetadata_mailbox_iter_next(ctx);
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen }
02c75e04c6ff80726bb59e3ea34a7995ad1f6f7cTimo Sirainen}