From: Timo Sirainen Date: Thu, 10 Aug 2023 10:53:30 +0000 (+0300) Subject: doveadm: Add "mail dict" commands X-Git-Tag: 2.4.1~1376 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=82bf713b5be87ad2bc63a965f59365d07510dedb;p=thirdparty%2Fdovecot%2Fcore.git doveadm: Add "mail dict" commands These are similar to "doveadm dict" commands, but they're run in the mail user context. This way all user-specific settings are applied and process uid/gid is also set properly. --- diff --git a/src/doveadm/Makefile.am b/src/doveadm/Makefile.am index 0f364ace7b..21fc450630 100644 --- a/src/doveadm/Makefile.am +++ b/src/doveadm/Makefile.am @@ -90,6 +90,7 @@ doveadm_common_mail_cmds = \ doveadm-mail.c \ doveadm-mail-altmove.c \ doveadm-mail-deduplicate.c \ + doveadm-mail-dict.c \ doveadm-mail-expunge.c \ doveadm-mail-fetch.c \ doveadm-mail-flags.c \ diff --git a/src/doveadm/doveadm-dict.c b/src/doveadm/doveadm-dict.c index a45d9ed2dc..472b801247 100644 --- a/src/doveadm/doveadm-dict.c +++ b/src/doveadm/doveadm-dict.c @@ -19,7 +19,10 @@ cmd_dict_init(struct doveadm_cmd_context *cctx, const char *filter_name, *error, *key, *username = ""; i_zero(dopset_r); - (void)doveadm_cmd_param_str(cctx, "user", &username); + if (cctx->cmd->mail_cmd != NULL) + username = cctx->username; /* doveadm mail dict command */ + else + (void)doveadm_cmd_param_str(cctx, "user", &username); dopset_r->username = username; if (!doveadm_cmd_param_str(cctx, "filter-name", &filter_name)) { @@ -142,6 +145,10 @@ void doveadm_dict_get(struct doveadm_cmd_context *cctx, const char *key) } else { unsigned int i, values_count = str_array_length(ctx.values); + /* We don't know beforehand how many values there are, + so allow adding headers at this stage, even though + it's not correct. */ + doveadm_print_header_disallow(FALSE); for (i = 1; i < values_count; i++) doveadm_print_header("value", "", DOVEADM_PRINT_HEADER_FLAG_HIDE_TITLE); for (i = 0; i < values_count; i++) @@ -291,6 +298,10 @@ void doveadm_dict_iter(struct doveadm_cmd_context *cctx, while (dict_iterate_values(iter, &key, &values)) { unsigned int values_count = str_array_length(values); if (!header_printed) { + /* We don't know beforehand how many values there are, + so allow adding headers at this stage, even though + it's not correct. */ + doveadm_print_header_disallow(FALSE); for (unsigned int i = 1; i < values_count; i++) doveadm_print_header_simple("value"); header_printed = TRUE; diff --git a/src/doveadm/doveadm-mail-dict.c b/src/doveadm/doveadm-mail-dict.c new file mode 100644 index 0000000000..d743d890ef --- /dev/null +++ b/src/doveadm/doveadm-mail-dict.c @@ -0,0 +1,244 @@ +/* Copyright (c) 2023 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "dict.h" +#include "doveadm-mail.h" +#include "doveadm-dict.h" +#include "doveadm-print.h" + +struct mail_dict_cmd_context { + struct doveadm_mail_cmd_context ctx; + const char *key, *value, *prefix; + int64_t inc_diff; + enum dict_iterate_flags iter_flags; +}; + +static void cmd_mail_dict_get_init(struct doveadm_mail_cmd_context *_cctx) +{ + struct mail_dict_cmd_context *cctx = + container_of(_cctx, struct mail_dict_cmd_context, ctx); + + if (!doveadm_cmd_param_str(_cctx->cctx, "key", &cctx->key)) { + doveadm_mail_help_name("mail dict get"); + return; + } + doveadm_print_header("value", "", DOVEADM_PRINT_HEADER_FLAG_HIDE_TITLE); +} + +static int cmd_mail_dict_get_run(struct doveadm_mail_cmd_context *_cctx, + struct mail_user *user ATTR_UNUSED) +{ + struct mail_dict_cmd_context *cctx = + container_of(_cctx, struct mail_dict_cmd_context, ctx); + + doveadm_dict_get(_cctx->cctx, cctx->key); + return 0; +} + +static struct doveadm_mail_cmd_context *cmd_mail_dict_get_alloc(void) +{ + struct mail_dict_cmd_context *ctx = + doveadm_mail_cmd_alloc(struct mail_dict_cmd_context); + ctx->ctx.service_flags |= MAIL_STORAGE_SERVICE_FLAG_MINIMAL_USER_INIT; + ctx->ctx.v.init = cmd_mail_dict_get_init; + ctx->ctx.v.run = cmd_mail_dict_get_run; + doveadm_print_init(DOVEADM_PRINT_TYPE_TABLE); + return &ctx->ctx; +} + +static void cmd_mail_dict_set_init(struct doveadm_mail_cmd_context *_cctx) +{ + struct mail_dict_cmd_context *cctx = + container_of(_cctx, struct mail_dict_cmd_context, ctx); + + if (!doveadm_cmd_param_str(_cctx->cctx, "key", &cctx->key) || + !doveadm_cmd_param_str(_cctx->cctx, "value", &cctx->value)) + doveadm_mail_help_name("mail dict set"); +} + +static int cmd_mail_dict_set_run(struct doveadm_mail_cmd_context *_cctx, + struct mail_user *user ATTR_UNUSED) +{ + struct mail_dict_cmd_context *cctx = + container_of(_cctx, struct mail_dict_cmd_context, ctx); + + doveadm_dict_set(_cctx->cctx, cctx->key, cctx->value); + return 0; +} + +static struct doveadm_mail_cmd_context *cmd_mail_dict_set_alloc(void) +{ + struct mail_dict_cmd_context *ctx = + doveadm_mail_cmd_alloc(struct mail_dict_cmd_context); + ctx->ctx.service_flags |= MAIL_STORAGE_SERVICE_FLAG_MINIMAL_USER_INIT; + ctx->ctx.v.init = cmd_mail_dict_set_init; + ctx->ctx.v.run = cmd_mail_dict_set_run; + return &ctx->ctx; +} + +static void cmd_mail_dict_unset_init(struct doveadm_mail_cmd_context *_cctx) +{ + struct mail_dict_cmd_context *cctx = + container_of(_cctx, struct mail_dict_cmd_context, ctx); + + if (!doveadm_cmd_param_str(_cctx->cctx, "key", &cctx->key)) + doveadm_mail_help_name("mail dict unset"); +} + +static int cmd_mail_dict_unset_run(struct doveadm_mail_cmd_context *_cctx, + struct mail_user *user ATTR_UNUSED) +{ + struct mail_dict_cmd_context *cctx = + container_of(_cctx, struct mail_dict_cmd_context, ctx); + + doveadm_dict_unset(_cctx->cctx, cctx->key); + return 0; +} + +static struct doveadm_mail_cmd_context *cmd_mail_dict_unset_alloc(void) +{ + struct mail_dict_cmd_context *ctx = + doveadm_mail_cmd_alloc(struct mail_dict_cmd_context); + ctx->ctx.service_flags |= MAIL_STORAGE_SERVICE_FLAG_MINIMAL_USER_INIT; + ctx->ctx.v.init = cmd_mail_dict_unset_init; + ctx->ctx.v.run = cmd_mail_dict_unset_run; + return &ctx->ctx; +} + +static void cmd_mail_dict_inc_init(struct doveadm_mail_cmd_context *_cctx) +{ + struct mail_dict_cmd_context *cctx = + container_of(_cctx, struct mail_dict_cmd_context, ctx); + + if (!doveadm_cmd_param_str(_cctx->cctx, "key", &cctx->key) || + !doveadm_cmd_param_int64(_cctx->cctx, "difference", &cctx->inc_diff)) { + doveadm_mail_help_name("mail dict inc"); + return; + } +} + +static int cmd_mail_dict_inc_run(struct doveadm_mail_cmd_context *_cctx, + struct mail_user *user ATTR_UNUSED) +{ + struct mail_dict_cmd_context *cctx = + container_of(_cctx, struct mail_dict_cmd_context, ctx); + + doveadm_dict_inc(_cctx->cctx, cctx->key, cctx->inc_diff); + return 0; +} + +static struct doveadm_mail_cmd_context *cmd_mail_dict_inc_alloc(void) +{ + struct mail_dict_cmd_context *ctx = + doveadm_mail_cmd_alloc(struct mail_dict_cmd_context); + ctx->ctx.service_flags |= MAIL_STORAGE_SERVICE_FLAG_MINIMAL_USER_INIT; + ctx->ctx.v.init = cmd_mail_dict_inc_init; + ctx->ctx.v.run = cmd_mail_dict_inc_run; + return &ctx->ctx; +} + +static void cmd_mail_dict_iter_init(struct doveadm_mail_cmd_context *_cctx) +{ + struct mail_dict_cmd_context *cctx = + container_of(_cctx, struct mail_dict_cmd_context, ctx); + + if (!doveadm_cmd_param_str(_cctx->cctx, "prefix", &cctx->prefix)) { + doveadm_mail_help_name("mail dict iter"); + return; + } + if (doveadm_cmd_param_flag(_cctx->cctx, "exact")) + cctx->iter_flags |= DICT_ITERATE_FLAG_EXACT_KEY; + if (doveadm_cmd_param_flag(_cctx->cctx, "recurse")) + cctx->iter_flags |= DICT_ITERATE_FLAG_RECURSE; + if (doveadm_cmd_param_flag(_cctx->cctx, "no-value")) + cctx->iter_flags |= DICT_ITERATE_FLAG_NO_VALUE; + + doveadm_print_header_simple("key"); + if ((cctx->iter_flags & DICT_ITERATE_FLAG_NO_VALUE) == 0) + doveadm_print_header_simple("value"); +} + +static int cmd_mail_dict_iter_run(struct doveadm_mail_cmd_context *_cctx, + struct mail_user *user ATTR_UNUSED) +{ + struct mail_dict_cmd_context *cctx = + container_of(_cctx, struct mail_dict_cmd_context, ctx); + + doveadm_dict_iter(_cctx->cctx, cctx->iter_flags, cctx->prefix); + return 0; +} + +static struct doveadm_mail_cmd_context *cmd_mail_dict_iter_alloc(void) +{ + struct mail_dict_cmd_context *ctx = + doveadm_mail_cmd_alloc(struct mail_dict_cmd_context); + ctx->ctx.service_flags |= MAIL_STORAGE_SERVICE_FLAG_MINIMAL_USER_INIT; + ctx->ctx.v.init = cmd_mail_dict_iter_init; + ctx->ctx.v.run = cmd_mail_dict_iter_run; + doveadm_print_init(DOVEADM_PRINT_TYPE_TAB); + return &ctx->ctx; +} + +struct doveadm_cmd_ver2 doveadm_cmd_mail_dict_get = { + .name = "mail dict get", + .mail_cmd = cmd_mail_dict_get_alloc, + .usage = " ", +DOVEADM_CMD_PARAMS_START +DOVEADM_CMD_MAIL_COMMON +DOVEADM_CMD_PARAM('\0', "filter-name", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAM('\0', "key", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAMS_END +}; + +struct doveadm_cmd_ver2 doveadm_cmd_mail_dict_set = { + .name = "mail dict set", + .mail_cmd = cmd_mail_dict_set_alloc, + .usage = "[-t ] [-e ] ", +DOVEADM_CMD_PARAMS_START +DOVEADM_CMD_MAIL_COMMON +DOVEADM_CMD_PARAM('t', "timestamp", CMD_PARAM_INT64, CMD_PARAM_FLAG_UNSIGNED) +DOVEADM_CMD_PARAM('e', "expire-secs", CMD_PARAM_INT64, CMD_PARAM_FLAG_UNSIGNED) +DOVEADM_CMD_PARAM('\0', "filter-name", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAM('\0', "key", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAM('\0', "value", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAMS_END +}; + +struct doveadm_cmd_ver2 doveadm_cmd_mail_dict_unset = { + .name = "mail dict unset", + .mail_cmd = cmd_mail_dict_unset_alloc, + .usage = "[-t ] ", +DOVEADM_CMD_PARAMS_START +DOVEADM_CMD_MAIL_COMMON +DOVEADM_CMD_PARAM('t', "timestamp", CMD_PARAM_INT64, CMD_PARAM_FLAG_UNSIGNED) +DOVEADM_CMD_PARAM('\0', "filter-name", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAM('\0', "key", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAMS_END +}; + +struct doveadm_cmd_ver2 doveadm_cmd_mail_dict_inc = { + .name = "mail dict inc", + .mail_cmd = cmd_mail_dict_inc_alloc, + .usage = "[-t ] ", +DOVEADM_CMD_PARAMS_START +DOVEADM_CMD_MAIL_COMMON +DOVEADM_CMD_PARAM('t', "timestamp", CMD_PARAM_INT64, CMD_PARAM_FLAG_UNSIGNED) +DOVEADM_CMD_PARAM('\0', "filter-name", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAM('\0', "key", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAM('\0', "difference", CMD_PARAM_INT64, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAMS_END +}; + +struct doveadm_cmd_ver2 doveadm_cmd_mail_dict_iter = { + .name = "mail dict iter", + .mail_cmd = cmd_mail_dict_iter_alloc, + .usage = "[-1RV] ", +DOVEADM_CMD_PARAMS_START +DOVEADM_CMD_MAIL_COMMON +DOVEADM_CMD_PARAM('1', "exact", CMD_PARAM_BOOL, 0) +DOVEADM_CMD_PARAM('R', "recurse", CMD_PARAM_BOOL, 0) +DOVEADM_CMD_PARAM('V', "no-value", CMD_PARAM_BOOL, 0) +DOVEADM_CMD_PARAM('\0', "filter-name", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAM('\0', "prefix", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAMS_END +}; diff --git a/src/doveadm/doveadm-mail.c b/src/doveadm/doveadm-mail.c index 81a7afa62a..79a945f4eb 100644 --- a/src/doveadm/doveadm-mail.c +++ b/src/doveadm/doveadm-mail.c @@ -826,6 +826,11 @@ static struct doveadm_cmd_ver2 *mail_commands_ver2[] = { &doveadm_cmd_mail_fs_delete, &doveadm_cmd_mail_fs_iter, &doveadm_cmd_mail_fs_iter_dirs, + &doveadm_cmd_mail_dict_get, + &doveadm_cmd_mail_dict_set, + &doveadm_cmd_mail_dict_unset, + &doveadm_cmd_mail_dict_inc, + &doveadm_cmd_mail_dict_iter, }; void doveadm_mail_init(void) diff --git a/src/doveadm/doveadm-mail.h b/src/doveadm/doveadm-mail.h index 85e0e87c20..9fda79e652 100644 --- a/src/doveadm/doveadm-mail.h +++ b/src/doveadm/doveadm-mail.h @@ -218,6 +218,11 @@ extern struct doveadm_cmd_ver2 doveadm_cmd_mail_fs_metadata; extern struct doveadm_cmd_ver2 doveadm_cmd_mail_fs_delete; extern struct doveadm_cmd_ver2 doveadm_cmd_mail_fs_iter; extern struct doveadm_cmd_ver2 doveadm_cmd_mail_fs_iter_dirs; +extern struct doveadm_cmd_ver2 doveadm_cmd_mail_dict_get; +extern struct doveadm_cmd_ver2 doveadm_cmd_mail_dict_set; +extern struct doveadm_cmd_ver2 doveadm_cmd_mail_dict_unset; +extern struct doveadm_cmd_ver2 doveadm_cmd_mail_dict_inc; +extern struct doveadm_cmd_ver2 doveadm_cmd_mail_dict_iter; #define DOVEADM_CMD_MAIL_COMMON \ DOVEADM_CMD_PARAM('A', "all-users", CMD_PARAM_BOOL, 0) \