cmd-setmetadata.c revision fe779565bda49a0ed0476724819c6e3c1340c94b
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2013-2015 Dovecot authors, see the included COPYING file */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "imap-common.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "ioloop.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "istream.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "istream-seekable.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "ostream.h"
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen#include "str.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "imap-metadata.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#define METADATA_MAX_INMEM_SIZE (1024*128)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstruct imap_setmetadata_context {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct client_command_context *cmd;
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen struct imap_parser *parser;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct mailbox *box;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct imap_metadata_transaction *trans;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen char *entry_name;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen uoff_t entry_value_len;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct istream *input;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen bool failed;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen bool cmd_error_sent;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen bool storage_failure;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen};
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic void cmd_setmetadata_deinit(struct imap_setmetadata_context *ctx)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen o_stream_set_flush_callback(ctx->cmd->client->output,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen client_output, ctx->cmd->client);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->cmd->client->input_lock = NULL;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen imap_parser_unref(&ctx->parser);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (ctx->trans != NULL)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen imap_metadata_transaction_rollback(&ctx->trans);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (ctx->box != NULL && ctx->box != ctx->cmd->client->mailbox)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mailbox_free(&ctx->box);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_free(ctx->entry_name);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic int
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainencmd_setmetadata_parse_entryvalue(struct imap_setmetadata_context *ctx,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen const char **entry_r,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen const struct imap_arg **value_r)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen const struct imap_arg *args;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen const char *name, *error;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen int ret;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen bool fatal;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* parse the entry name */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ret = imap_parser_read_args(ctx->parser, 1,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen IMAP_PARSE_FLAG_INSIDE_LIST, &args);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (ret >= 0) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (ret == 0) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* ')' found */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen *entry_r = NULL;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return 1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (!imap_arg_get_astring(args, &name)) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen client_send_command_error(ctx->cmd,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen "Entry name isn't astring");
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return -1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ret = imap_parser_read_args(ctx->parser, 2,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen IMAP_PARSE_FLAG_INSIDE_LIST |
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen IMAP_PARSE_FLAG_LITERAL_SIZE |
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen IMAP_PARSE_FLAG_LITERAL8, &args);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (ret < 0) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (ret == -2)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return 0;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen error = imap_parser_get_error(ctx->parser, &fatal);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (fatal) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen client_disconnect_with_error(ctx->cmd->client, error);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return -1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen client_send_command_error(ctx->cmd, error);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return -1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_assert(!IMAP_ARG_IS_EOL(&args[1]));
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (args[1].type == IMAP_ARG_LIST) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen client_send_command_error(ctx->cmd, "Entry value can't be a list");
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return -1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (!ctx->cmd_error_sent &&
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen !imap_metadata_verify_entry_name(name, &error)) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen client_send_command_error(ctx->cmd, error);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->cmd_error_sent = TRUE;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (ctx->cmd_error_sent) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->cmd->param_error = FALSE;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->cmd->state = CLIENT_COMMAND_STATE_WAIT_INPUT;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->failed = TRUE;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (args[1].type == IMAP_ARG_LITERAL_SIZE) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* client won't see "+ OK", so we can abort
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen immediately */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->cmd->client->input_skip_line = FALSE;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return -1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* entry names are case-insensitive. handle this by using only
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen lowercase names. */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen *entry_r = t_str_lcase(name);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen *value_r = &args[1];
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return 1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic int
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainencmd_setmetadata_entry_read_stream(struct imap_setmetadata_context *ctx)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen const unsigned char *data;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen size_t size;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct mail_attribute_value value;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen int ret;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen while ((ret = i_stream_read_data(ctx->input, &data, &size, 0)) > 0)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_stream_skip(ctx->input, size);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (ctx->input->v_offset == ctx->entry_value_len) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* finished reading the value */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_stream_seek(ctx->input, 0);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (ctx->failed) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_stream_unref(&ctx->input);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return 1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen memset(&value, 0, sizeof(value));
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen value.value_stream = ctx->input;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (imap_metadata_set(ctx->trans, ctx->entry_name, &value) < 0) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* delay reporting the failure so we'll finish
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen reading the command input */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->storage_failure = TRUE;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ctx->failed = TRUE;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_stream_unref(&ctx->input);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return 1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (ctx->input->eof) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* client disconnected */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return -1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return 0;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic int
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainencmd_setmetadata_entry(struct imap_setmetadata_context *ctx,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen const char *entry_name,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen const struct imap_arg *entry_value)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct istream *inputs[2];
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct mail_attribute_value value;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen string_t *path;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen int ret;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen switch (entry_value->type) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen case IMAP_ARG_NIL:
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen case IMAP_ARG_ATOM:
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen case IMAP_ARG_STRING:
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* we have the value already */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (ctx->failed)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return 1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen memset(&value, 0, sizeof(value));
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen value.value = imap_arg_as_nstring(entry_value);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ret = imap_metadata_set(ctx->trans, entry_name, &value);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (ret < 0) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* delay reporting the failure so we'll finish
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen reading the command input */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->storage_failure = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->failed = TRUE;
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return 1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case IMAP_ARG_LITERAL_SIZE:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen o_stream_nsend(ctx->cmd->client->output, "+ OK\r\n", 6);
4dc8837ab37c1a606add1067e21ed868754db4e3Timo Sirainen o_stream_nflush(ctx->cmd->client->output);
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen o_stream_uncork(ctx->cmd->client->output);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen o_stream_cork(ctx->cmd->client->output);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* fall through */
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen case IMAP_ARG_LITERAL_SIZE_NONSYNC:
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen i_free(ctx->entry_name);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->entry_name = i_strdup(entry_name);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->entry_value_len = imap_arg_as_literal_size(entry_value);
e06c0b65c16ccce69bbee009ead14d7d3d17a256Timo Sirainen
2abfef71398a61e5ed97c23a1ceb71461933ccb8Timo Sirainen inputs[0] = i_stream_create_limit(ctx->cmd->client->input,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->entry_value_len);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen inputs[1] = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen path = t_str_new(128);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen mail_user_set_get_temp_prefix(path, ctx->cmd->client->user->set);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->input = i_stream_create_seekable_path(inputs,
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen METADATA_MAX_INMEM_SIZE, str_c(path));
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen i_stream_set_name(ctx->input, i_stream_get_name(inputs[0]));
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen i_stream_unref(&inputs[0]);
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen return cmd_setmetadata_entry_read_stream(ctx);
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen case IMAP_ARG_LITERAL:
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen case IMAP_ARG_LIST:
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen case IMAP_ARG_EOL:
b66a7b7ab0db2c9ad425912d3f21a36fcf76d876Timo Sirainen break;
cbf7138b49d32fce0645dc6523fbb42cc07cb2faTimo Sirainen }
cbf7138b49d32fce0645dc6523fbb42cc07cb2faTimo Sirainen i_unreached();
b9b48aaaebf6f72dfab567cda073cde8a7b26598Timo Sirainen}
b9b48aaaebf6f72dfab567cda073cde8a7b26598Timo Sirainen
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainenstatic bool cmd_setmetadata_continue(struct client_command_context *cmd)
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct imap_setmetadata_context *ctx = cmd->context;
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen const char *entry, *error_string;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen enum mail_error error;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const struct imap_arg *value;
e30b748edcef3cf3352478bf21fa8f785bdc773aTimo Sirainen int ret;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen if (cmd->cancel) {
d4dcb9c30dba354cff7af6d303ecef7698194c55Timo Sirainen cmd_setmetadata_deinit(ctx);
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen return TRUE;
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen }
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen
1582b4d531679849bba299c17b6ec9402b7df67dTimo Sirainen if (ctx->input != NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((ret = cmd_setmetadata_entry_read_stream(ctx)) == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return FALSE;
9c7e765845357342923e16351181091028e5930fTimo Sirainen if (ret < 0) {
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen cmd_setmetadata_deinit(ctx);
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen return TRUE;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen }
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen }
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen while ((ret = cmd_setmetadata_parse_entryvalue(ctx, &entry, &value)) > 0 &&
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen entry != NULL) {
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen ret = ctx->failed ? 1 :
6bf1543bb7af03324c04e8f9ac8e430f395989aeTimo Sirainen cmd_setmetadata_entry(ctx, entry, value);
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen imap_parser_reset(ctx->parser);
b00787191c3c31bebb939c3d00f1fcdb67356c69Timo Sirainen if (ret <= 0)
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen break;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen }
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen if (ret == 0)
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen return 0;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen if (ret < 0 || ctx->cmd_error_sent) {
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen /* already sent the error to client */ ;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen } else if (ctx->storage_failure) {
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen if (ctx->box == NULL)
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen client_disconnect_if_inconsistent(cmd->client);
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen error_string = imap_metadata_transaction_get_last_error
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen (ctx->trans, &error);
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen client_send_tagline(cmd,
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen imap_get_error_string(cmd, error_string, error));
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen } else if (imap_metadata_transaction_commit(&ctx->trans,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen &error, &error_string) < 0) {
e30b748edcef3cf3352478bf21fa8f785bdc773aTimo Sirainen if (ctx->box == NULL)
e30b748edcef3cf3352478bf21fa8f785bdc773aTimo Sirainen client_disconnect_if_inconsistent(cmd->client);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_send_tagline(cmd,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen imap_get_error_string(cmd, error_string, error));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_send_tagline(cmd, "OK Setmetadata completed.");
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen }
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen cmd_setmetadata_deinit(ctx);
b5e6f6f27c1461f0f9f202615eeb738a645188c3Timo Sirainen return TRUE;
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen}
44dc970b18c4e2d06f34cb908924152156e4a45bTimo Sirainen
e30b748edcef3cf3352478bf21fa8f785bdc773aTimo Sirainenstatic bool
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainencmd_setmetadata_start(struct imap_setmetadata_context *ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct client_command_context *cmd = ctx->cmd;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct client *client = cmd->client;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* we support large literals, so read the values from client
e05181d973025627ba08b631c12c07c3bbc99528Timo Sirainen asynchronously the same way as APPEND does. */
0b3662995e9fa0d0d857ec5350ce2b1ee6d3b94fTimo Sirainen client->input_lock = cmd;
0b3662995e9fa0d0d857ec5350ce2b1ee6d3b94fTimo Sirainen ctx->parser = imap_parser_create(client->input, client->output,
0b3662995e9fa0d0d857ec5350ce2b1ee6d3b94fTimo Sirainen client->set->imap_max_line_length);
0b3662995e9fa0d0d857ec5350ce2b1ee6d3b94fTimo Sirainen o_stream_unset_flush_callback(client->output);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen cmd->func = cmd_setmetadata_continue;
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen cmd->context = ctx;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen return cmd_setmetadata_continue(cmd);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainenstatic bool
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainencmd_setmetadata_server(struct imap_setmetadata_context *ctx)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen ctx->trans = imap_metadata_transaction_begin_server(ctx->cmd->client->user);
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen return cmd_setmetadata_start(ctx);
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen}
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainenstatic bool
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainencmd_setmetadata_mailbox(struct imap_setmetadata_context *ctx,
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen const char *mailbox)
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen{
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen struct client_command_context *cmd = ctx->cmd;
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen struct client *client = cmd->client;
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen struct mail_namespace *ns;
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen ns = client_find_namespace(cmd, &mailbox);
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen if (ns == NULL)
cbf7138b49d32fce0645dc6523fbb42cc07cb2faTimo Sirainen return TRUE;
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen if (client->mailbox != NULL && !client->mailbox_examined &&
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen mailbox_equals(client->mailbox, ns, mailbox))
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen ctx->box = client->mailbox;
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen else {
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen ctx->box = mailbox_alloc(ns->list, mailbox, 0);
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen if (mailbox_open(ctx->box) < 0) {
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen client_send_box_error(cmd, ctx->box);
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen mailbox_free(&ctx->box);
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen return TRUE;
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen }
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen }
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen ctx->trans = imap_metadata_transaction_begin(ctx->box);
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen return cmd_setmetadata_start(ctx);
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen}
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainenbool cmd_setmetadata(struct client_command_context *cmd)
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen{
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen struct imap_setmetadata_context *ctx;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen const struct imap_arg *args;
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen const char *mailbox;
992a9e2d6c6ee45d87089ac54267e0198a7802c3Timo Sirainen int ret;
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen ret = imap_parser_read_args(cmd->parser, 2,
4b43f50117630aa12b3cfd0cbd05ae22ba27fec1Timo Sirainen IMAP_PARSE_FLAG_STOP_AT_LIST, &args);
538303a216166f3526c0ae9658c9978275cfa100Timo Sirainen if (ret == -1) {
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen client_send_command_error(cmd, NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return TRUE;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen }
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen if (ret == -2)
a87e5f15283e057c7dc26dd9db7b616268c95ca7Timo Sirainen return FALSE;
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen if (!imap_arg_get_astring(&args[0], &mailbox) ||
c93cd163f9c1d4b0ca29f49cbfdbf474caeef5bfTimo Sirainen args[1].type != IMAP_ARG_LIST) {
6925fd9cd70c30884406d50f1d85efb6561e776cTimo Sirainen client_send_command_error(cmd, "Invalid arguments.");
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen return TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!cmd->client->imap_metadata_enabled) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen client_send_command_error(cmd, "METADATA disabled.");
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen return TRUE;
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen }
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen ctx = p_new(cmd->pool, struct imap_setmetadata_context, 1);
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen ctx->cmd = cmd;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen ctx->cmd->context = ctx;
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen if (mailbox[0] == '\0') {
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen /* server attribute */
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen return cmd_setmetadata_server(ctx);
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen }
9ef0f38972e7f42ff8d1795f47f6a3e6d621be9cTimo Sirainen
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen return cmd_setmetadata_mailbox(ctx, mailbox);
32ee977e189266744ef69ac4e832fd3111d6f949Timo Sirainen}
8e5fedd9ada47735be8ac0f8af2a66e8528bd776Timo Sirainen