]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
doveadm: Add "mail dict" commands
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Thu, 10 Aug 2023 10:53:30 +0000 (13:53 +0300)
committerAki Tuomi <aki.tuomi@open-xchange.com>
Wed, 12 Feb 2025 10:34:10 +0000 (12:34 +0200)
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.

src/doveadm/Makefile.am
src/doveadm/doveadm-dict.c
src/doveadm/doveadm-mail-dict.c [new file with mode: 0644]
src/doveadm/doveadm-mail.c
src/doveadm/doveadm-mail.h

index 0f364ace7bf7ce2227f73efcb5e4b57b8d63b8a7..21fc450630d520695363395a58c842e549610651 100644 (file)
@@ -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 \
index a45d9ed2dc544490a278c950c729aafec9e72a4c..472b801247d7795bae18daedb7157ae3cdd549c8 100644 (file)
@@ -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 (file)
index 0000000..d743d89
--- /dev/null
@@ -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 = "<config-filter-name> <key>",
+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 <timestamp-nsecs>] [-e <expire-secs>] <config-filter-name> <key> <value>",
+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 <timestamp-nsecs>] <config-filter-name> <key>",
+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 <timestamp-nsecs>] <config-filter-name> <key> <diff>",
+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] <config-filter-name> <prefix>",
+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
+};
index 81a7afa62a0b4421c95661b5272874cdf774b4a8..79a945f4eb46ee32da387e7757599910f48a7c61 100644 (file)
@@ -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)
index 85e0e87c20d803fb258533291e48ea7b319de49c..9fda79e652380b6548fd80d24be39cf604d187ce 100644 (file)
@@ -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) \