Mercurial > dovecot > core-2.2
diff src/imap/cmd-setmetadata.c @ 18094:a350812e07bf
lib-imap-storage: Created new METADATA API.
author | Stephan Bosch <stephan@rename-it.nl> |
---|---|
date | Sat, 15 Nov 2014 02:27:27 +0200 |
parents | add8c00fb3cc |
children | 3009a1a6f6d5 |
line wrap: on
line diff
--- a/src/imap/cmd-setmetadata.c Sat Nov 15 02:22:56 2014 +0200 +++ b/src/imap/cmd-setmetadata.c Sat Nov 15 02:27:27 2014 +0200 @@ -14,10 +14,8 @@ struct client_command_context *cmd; struct imap_parser *parser; - const char *key_prefix; - struct mailbox *box; - struct mailbox_transaction_context *trans; + struct imap_metadata_transaction *trans; char *entry_name; uoff_t entry_value_len; @@ -32,8 +30,8 @@ ctx->cmd->client->input_lock = NULL; imap_parser_unref(&ctx->parser); if (ctx->trans != NULL) - mailbox_transaction_rollback(&ctx->trans); - if (ctx->box != ctx->cmd->client->mailbox) + imap_metadata_transaction_rollback(&ctx->trans); + if (ctx->box != NULL && ctx->box != ctx->cmd->client->mailbox) mailbox_free(&ctx->box); i_free(ctx->entry_name); } @@ -84,12 +82,15 @@ client_send_command_error(ctx->cmd, "Entry value can't be a list"); return -1; } - if (ctx->cmd_error_sent || - !imap_metadata_verify_entry_name(ctx->cmd, name)) { + if (!ctx->cmd_error_sent && + !imap_metadata_verify_entry_name(name, &error)) { + client_send_command_error(ctx->cmd, error); + ctx->cmd_error_sent = TRUE; + } + if (ctx->cmd_error_sent) { ctx->cmd->param_error = FALSE; ctx->cmd->state = CLIENT_COMMAND_STATE_WAIT_INPUT; - ctx->cmd_error_sent = TRUE; ctx->failed = TRUE; if (args[1].type == IMAP_ARG_LITERAL_SIZE) { /* client won't see "+ OK", so we can abort @@ -111,8 +112,6 @@ { const unsigned char *data; size_t size; - enum mail_attribute_type type; - const char *key; struct mail_attribute_value value; int ret; @@ -127,11 +126,9 @@ return 1; } - imap_metadata_entry2key(ctx->entry_name, ctx->key_prefix, - &type, &key); memset(&value, 0, sizeof(value)); value.value_stream = ctx->input; - if (mailbox_attribute_set(ctx->trans, type, key, &value) < 0) { + if (imap_metadata_set(ctx->trans, ctx->entry_name, &value) < 0) { /* delay reporting the failure so we'll finish reading the command input */ ctx->storage_failure = TRUE; @@ -153,8 +150,6 @@ const struct imap_arg *entry_value) { struct istream *inputs[2]; - enum mail_attribute_type type; - const char *key; struct mail_attribute_value value; string_t *path; int ret; @@ -164,15 +159,11 @@ case IMAP_ARG_ATOM: case IMAP_ARG_STRING: /* we have the value already */ - imap_metadata_entry2key(entry_name, ctx->key_prefix, - &type, &key); if (ctx->failed) return 1; memset(&value, 0, sizeof(value)); value.value = imap_arg_as_nstring(entry_value); - ret = value.value == NULL ? - mailbox_attribute_unset(ctx->trans, type, key) : - mailbox_attribute_set(ctx->trans, type, key, &value); + ret = imap_metadata_set(ctx->trans, entry_name, &value); if (ret < 0) { /* delay reporting the failure so we'll finish reading the command input */ @@ -213,7 +204,8 @@ static bool cmd_setmetadata_continue(struct client_command_context *cmd) { struct imap_setmetadata_context *ctx = cmd->context; - const char *entry; + const char *entry, *error_string; + enum mail_error error; const struct imap_arg *value; int ret; @@ -242,24 +234,85 @@ if (ret == 0) return 0; - if (ret < 0 || ctx->cmd_error_sent) + if (ret < 0 || ctx->cmd_error_sent) { /* already sent the error to client */ ; - else if (ctx->storage_failure) - client_send_box_error(cmd, ctx->box); - else if (mailbox_transaction_commit(&ctx->trans) < 0) - client_send_box_error(cmd, ctx->box); - else + } else if (ctx->storage_failure) { + if (ctx->box == NULL) + client_disconnect_if_inconsistent(cmd->client); + error_string = imap_metadata_transaction_get_last_error + (ctx->trans, &error); + client_send_tagline(cmd, + imap_get_error_string(cmd, error_string, error)); + } else if (imap_metadata_transaction_commit(&ctx->trans, + &error, &error_string) < 0) { + if (ctx->box == NULL) + client_disconnect_if_inconsistent(cmd->client); + client_send_tagline(cmd, + imap_get_error_string(cmd, error_string, error)); + } else { client_send_tagline(cmd, "OK Setmetadata completed."); + } cmd_setmetadata_deinit(ctx); return TRUE; } +static bool +cmd_setmetadata_start(struct imap_setmetadata_context *ctx) +{ + struct client_command_context *cmd = ctx->cmd; + struct client *client = cmd->client; + + /* we support large literals, so read the values from client + asynchronously the same way as APPEND does. */ + client->input_lock = cmd; + ctx->parser = imap_parser_create(client->input, client->output, + client->set->imap_max_line_length); + o_stream_unset_flush_callback(client->output); + + cmd->func = cmd_setmetadata_continue; + cmd->context = ctx; + return cmd_setmetadata_continue(cmd); +} + +static bool +cmd_setmetadata_server(struct imap_setmetadata_context *ctx) +{ + ctx->trans = imap_metadata_transaction_begin_server(ctx->cmd->client->user); + return cmd_setmetadata_start(ctx); +} + +static bool +cmd_setmetadata_mailbox(struct imap_setmetadata_context *ctx, + const char *mailbox) +{ + struct client_command_context *cmd = ctx->cmd; + struct client *client = cmd->client; + struct mail_namespace *ns; + + ns = client_find_namespace(cmd, &mailbox); + if (ns == NULL) + return TRUE; + + if (client->mailbox != NULL && !client->mailbox_examined && + mailbox_equals(client->mailbox, ns, mailbox)) + ctx->box = client->mailbox; + else { + ctx->box = mailbox_alloc(ns->list, mailbox, 0); + if (mailbox_open(ctx->box) < 0) { + client_send_box_error(cmd, ctx->box); + mailbox_free(&ctx->box); + return TRUE; + } + } + ctx->trans = imap_metadata_transaction_begin(ctx->box); + return cmd_setmetadata_start(ctx); +} + bool cmd_setmetadata(struct client_command_context *cmd) { struct imap_setmetadata_context *ctx; const struct imap_arg *args; const char *mailbox; - struct mail_namespace *ns; int ret; ret = imap_parser_read_args(cmd->parser, 2, @@ -287,35 +340,8 @@ if (mailbox[0] == '\0') { /* server attribute */ - ctx->key_prefix = MAILBOX_ATTRIBUTE_PREFIX_DOVECOT_PVT_SERVER; - ns = mail_namespace_find_inbox(cmd->client->user->namespaces); - mailbox = "INBOX"; - } else { - ns = client_find_namespace(cmd, &mailbox); - if (ns == NULL) - return TRUE; + return cmd_setmetadata_server(ctx); } - if (cmd->client->mailbox != NULL && !cmd->client->mailbox_examined && - mailbox_equals(cmd->client->mailbox, ns, mailbox)) - ctx->box = cmd->client->mailbox; - else { - ctx->box = mailbox_alloc(ns->list, mailbox, 0); - 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); - /* we support large literals, so read the values from client - asynchronously the same way as APPEND does. */ - cmd->client->input_lock = cmd; - ctx->parser = imap_parser_create(cmd->client->input, cmd->client->output, - cmd->client->set->imap_max_line_length); - o_stream_unset_flush_callback(cmd->client->output); - - cmd->func = cmd_setmetadata_continue; - cmd->context = ctx; - return cmd_setmetadata_continue(cmd); + return cmd_setmetadata_mailbox(ctx, mailbox); }