From: Timo Sirainen Date: Thu, 23 Oct 2014 03:38:20 +0000 (+0300) Subject: doveadm: Added metadata set/unset/get/list commands. X-Git-Tag: 2.2.15~25 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=2c57ebc900742bd1119ef011b77b4910c4660cfa;p=thirdparty%2Fdovecot%2Fcore.git doveadm: Added metadata set/unset/get/list commands. --- diff --git a/src/doveadm/Makefile.am b/src/doveadm/Makefile.am index a7767989af..a4b9df8fef 100644 --- a/src/doveadm/Makefile.am +++ b/src/doveadm/Makefile.am @@ -71,6 +71,7 @@ common = \ doveadm-mail-index.c \ doveadm-mail-iter.c \ doveadm-mail-mailbox.c \ + doveadm-mail-mailbox-metadata.c \ doveadm-mail-mailbox-status.c \ doveadm-mail-copymove.c \ doveadm-mailbox-list-iter.c \ diff --git a/src/doveadm/doveadm-mail-mailbox-metadata.c b/src/doveadm/doveadm-mail-mailbox-metadata.c new file mode 100644 index 0000000000..351e80a4fd --- /dev/null +++ b/src/doveadm/doveadm-mail-mailbox-metadata.c @@ -0,0 +1,289 @@ +/* Copyright (c) 2014 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "str.h" +#include "mail-namespace.h" +#include "mail-storage.h" +#include "doveadm-print.h" +#include "doveadm-mail.h" +#include "doveadm-mailbox-list-iter.h" + +struct metadata_cmd_context { + struct doveadm_mail_cmd_context ctx; + const char *mailbox; + enum mail_attribute_type key_type; + const char *key; + struct mail_attribute_value value; +}; + +static int +cmd_mailbox_metadata_set_run(struct doveadm_mail_cmd_context *_ctx, + struct mail_user *user) +{ + struct metadata_cmd_context *ctx = (struct metadata_cmd_context *)_ctx; + struct mail_namespace *ns; + struct mailbox *box; + struct mailbox_transaction_context *trans; + int ret; + + ns = mail_namespace_find(user->namespaces, ctx->mailbox); + box = mailbox_alloc(ns->list, ctx->mailbox, 0); + + if (mailbox_open(box) < 0) { + i_error("Failed to open mailbox: %s", + mailbox_get_last_error(box, NULL)); + mailbox_free(&box); + return -1; + } + trans = mailbox_transaction_begin(box, 0); + + ret = ctx->value.value == NULL ? + mailbox_attribute_unset(trans, ctx->key_type, ctx->key) : + mailbox_attribute_set(trans, ctx->key_type, ctx->key, &ctx->value); + if (ret < 0) { + i_error("Failed to set attribute: %s", + mailbox_get_last_error(box, NULL)); + mailbox_transaction_rollback(&trans); + } else if (mailbox_transaction_commit(&trans) < 0) { + i_error("Failed to commit transaction: %s", + mailbox_get_last_error(box, NULL)); + ret = -1; + } + + mailbox_free(&box); + return ret; +} + +static void +cmd_mailbox_metadata_parse_key(const char *arg, + enum mail_attribute_type *type_r, + const char **key_r) +{ + if (strncmp(arg, "/private/", 9) == 0) { + *type_r = MAIL_ATTRIBUTE_TYPE_PRIVATE; + *key_r = arg + 9; + } else if (strncmp(arg, "/shared/", 8) == 0) { + *type_r = MAIL_ATTRIBUTE_TYPE_SHARED; + *key_r = arg + 8; + } else if (strcmp(arg, "/private") == 0) { + *type_r = MAIL_ATTRIBUTE_TYPE_PRIVATE; + *key_r = ""; + } else if (strcmp(arg, "/shared") == 0) { + *type_r = MAIL_ATTRIBUTE_TYPE_SHARED; + *key_r = ""; + } else { + i_fatal_status(EX_USAGE, "Invalid metadata key '%s': " + "Must begin with /private or /shared", arg); + } +} + +static void +cmd_mailbox_metadata_set_init(struct doveadm_mail_cmd_context *_ctx, + const char *const args[]) +{ + struct metadata_cmd_context *ctx = (struct metadata_cmd_context *)_ctx; + const char *key; + + if (str_array_length(args) != 3) + doveadm_mail_help_name("mailbox metadata set"); + cmd_mailbox_metadata_parse_key(args[1], &ctx->key_type, &key); + + ctx->mailbox = p_strdup(_ctx->pool, args[0]); + ctx->key = p_strdup(_ctx->pool, key); + ctx->value.value = p_strdup(_ctx->pool, args[2]); +} + +static struct doveadm_mail_cmd_context *cmd_mailbox_metadata_set_alloc(void) +{ + struct metadata_cmd_context *ctx; + + ctx = doveadm_mail_cmd_alloc(struct metadata_cmd_context); + ctx->ctx.v.init = cmd_mailbox_metadata_set_init; + ctx->ctx.v.run = cmd_mailbox_metadata_set_run; + return &ctx->ctx; +} + +static void +cmd_mailbox_metadata_unset_init(struct doveadm_mail_cmd_context *_ctx, + const char *const args[]) +{ + struct metadata_cmd_context *ctx = (struct metadata_cmd_context *)_ctx; + const char *key; + + if (str_array_length(args) != 2) + doveadm_mail_help_name("mailbox metadata unset"); + cmd_mailbox_metadata_parse_key(args[1], &ctx->key_type, &key); + + ctx->mailbox = p_strdup(_ctx->pool, args[0]); + ctx->key = p_strdup(_ctx->pool, key); +} + +static struct doveadm_mail_cmd_context *cmd_mailbox_metadata_unset_alloc(void) +{ + struct metadata_cmd_context *ctx; + + ctx = doveadm_mail_cmd_alloc(struct metadata_cmd_context); + ctx->ctx.v.init = cmd_mailbox_metadata_unset_init; + ctx->ctx.v.run = cmd_mailbox_metadata_set_run; + return &ctx->ctx; +} + +static int +cmd_mailbox_metadata_get_run(struct doveadm_mail_cmd_context *_ctx, + struct mail_user *user) +{ + struct metadata_cmd_context *ctx = (struct metadata_cmd_context *)_ctx; + struct mail_namespace *ns; + struct mailbox *box; + struct mailbox_transaction_context *trans; + struct mail_attribute_value value; + int ret; + + ns = mail_namespace_find(user->namespaces, ctx->mailbox); + box = mailbox_alloc(ns->list, ctx->mailbox, 0); + + if (mailbox_open(box) < 0) { + i_error("Failed to open mailbox: %s", + mailbox_get_last_error(box, NULL)); + mailbox_free(&box); + return -1; + } + trans = mailbox_transaction_begin(box, 0); + + ret = mailbox_attribute_get_stream(trans, ctx->key_type, ctx->key, &value); + if (ret < 0) { + i_error("Failed to get attribute: %s", + mailbox_get_last_error(box, NULL)); + } else if (ret == 0) { + /* not found, print as empty */ + doveadm_print(""); + } else if (value.value_stream != NULL) { + doveadm_print_istream(value.value_stream); + } else { + doveadm_print(value.value); + } + + (void)mailbox_transaction_commit(&trans); + mailbox_free(&box); + return ret; +} + +static void +cmd_mailbox_metadata_get_init(struct doveadm_mail_cmd_context *_ctx, + const char *const args[]) +{ + struct metadata_cmd_context *ctx = (struct metadata_cmd_context *)_ctx; + const char *key; + + if (str_array_length(args) != 2) + doveadm_mail_help_name("mailbox metadata get"); + cmd_mailbox_metadata_parse_key(args[1], &ctx->key_type, &key); + + ctx->mailbox = p_strdup(_ctx->pool, args[0]); + ctx->key = p_strdup(_ctx->pool, key); + doveadm_print_header("value", "value", + DOVEADM_PRINT_HEADER_FLAG_HIDE_TITLE); +} + +static struct doveadm_mail_cmd_context *cmd_mailbox_metadata_get_alloc(void) +{ + struct metadata_cmd_context *ctx; + + ctx = doveadm_mail_cmd_alloc(struct metadata_cmd_context); + ctx->ctx.v.init = cmd_mailbox_metadata_get_init; + ctx->ctx.v.run = cmd_mailbox_metadata_get_run; + doveadm_print_init(DOVEADM_PRINT_TYPE_FLOW); + return &ctx->ctx; +} + +static int +cmd_mailbox_metadata_list_run_iter(struct metadata_cmd_context *ctx, + struct mailbox *box, + enum mail_attribute_type type) +{ + struct mailbox_attribute_iter *iter; + const char *key; + + iter = mailbox_attribute_iter_init(box, type, ctx->key); + while ((key = mailbox_attribute_iter_next(iter)) != NULL) + doveadm_print(key); + return mailbox_attribute_iter_deinit(&iter); +} + +static int +cmd_mailbox_metadata_list_run(struct doveadm_mail_cmd_context *_ctx, + struct mail_user *user) +{ + struct metadata_cmd_context *ctx = (struct metadata_cmd_context *)_ctx; + struct mail_namespace *ns; + struct mailbox *box; + int ret = 0; + + ns = mail_namespace_find(user->namespaces, ctx->mailbox); + box = mailbox_alloc(ns->list, ctx->mailbox, 0); + + if (mailbox_open(box) < 0) { + i_error("Failed to open mailbox: %s", + mailbox_get_last_error(box, NULL)); + mailbox_free(&box); + return -1; + } + + if (ctx->key == NULL || ctx->key_type == MAIL_ATTRIBUTE_TYPE_PRIVATE) { + if (cmd_mailbox_metadata_list_run_iter(ctx, box, MAIL_ATTRIBUTE_TYPE_PRIVATE) < 0) + ret = -1; + } + if (ctx->key == NULL || ctx->key_type == MAIL_ATTRIBUTE_TYPE_SHARED) { + if (cmd_mailbox_metadata_list_run_iter(ctx, box, MAIL_ATTRIBUTE_TYPE_SHARED) < 0) + ret = -1; + } + mailbox_free(&box); + return ret; +} + +static void +cmd_mailbox_metadata_list_init(struct doveadm_mail_cmd_context *_ctx, + const char *const args[]) +{ + struct metadata_cmd_context *ctx = (struct metadata_cmd_context *)_ctx; + const char *key; + + if (args[0] == NULL) + doveadm_mail_help_name("mailbox metadata list"); + if (args[1] != NULL) + cmd_mailbox_metadata_parse_key(args[1], &ctx->key_type, &key); + ctx->mailbox = p_strdup(_ctx->pool, args[0]); + doveadm_print_header("key", "key", + DOVEADM_PRINT_HEADER_FLAG_HIDE_TITLE); +} + +static struct doveadm_mail_cmd_context *cmd_mailbox_metadata_list_alloc(void) +{ + struct metadata_cmd_context *ctx; + + ctx = doveadm_mail_cmd_alloc(struct metadata_cmd_context); + ctx->ctx.v.init = cmd_mailbox_metadata_list_init; + ctx->ctx.v.run = cmd_mailbox_metadata_list_run; + doveadm_print_init(DOVEADM_PRINT_TYPE_FLOW); + return &ctx->ctx; +} + +struct doveadm_mail_cmd cmd_mailbox_metadata_set = { + cmd_mailbox_metadata_set_alloc, "mailbox metadata set", + " " +}; + +struct doveadm_mail_cmd cmd_mailbox_metadata_unset = { + cmd_mailbox_metadata_unset_alloc, "mailbox metadata unset", + " " +}; + +struct doveadm_mail_cmd cmd_mailbox_metadata_get = { + cmd_mailbox_metadata_get_alloc, "mailbox metadata get", + " " +}; + +struct doveadm_mail_cmd cmd_mailbox_metadata_list = { + cmd_mailbox_metadata_list_alloc, "mailbox metadata list", + " []" +}; diff --git a/src/doveadm/doveadm-mail.c b/src/doveadm/doveadm-mail.c index f233109af3..9a0627e751 100644 --- a/src/doveadm/doveadm-mail.c +++ b/src/doveadm/doveadm-mail.c @@ -714,6 +714,10 @@ static struct doveadm_mail_cmd *mail_commands[] = { &cmd_mailbox_subscribe, &cmd_mailbox_unsubscribe, &cmd_mailbox_status, + &cmd_mailbox_metadata_set, + &cmd_mailbox_metadata_unset, + &cmd_mailbox_metadata_get, + &cmd_mailbox_metadata_list, &cmd_batch, &cmd_dsync_backup, &cmd_dsync_mirror, diff --git a/src/doveadm/doveadm-mail.h b/src/doveadm/doveadm-mail.h index 9c8a512f1d..47e3b58d8c 100644 --- a/src/doveadm/doveadm-mail.h +++ b/src/doveadm/doveadm-mail.h @@ -155,6 +155,10 @@ extern struct doveadm_mail_cmd cmd_mailbox_rename; extern struct doveadm_mail_cmd cmd_mailbox_subscribe; extern struct doveadm_mail_cmd cmd_mailbox_unsubscribe; extern struct doveadm_mail_cmd cmd_mailbox_status; +extern struct doveadm_mail_cmd cmd_mailbox_metadata_set; +extern struct doveadm_mail_cmd cmd_mailbox_metadata_unset; +extern struct doveadm_mail_cmd cmd_mailbox_metadata_get; +extern struct doveadm_mail_cmd cmd_mailbox_metadata_list; extern struct doveadm_mail_cmd cmd_batch; #endif