]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
doveadm: Split doveadm-cmd into doveadm-cmd-parse
authorMarco Bettini <marco.bettini@open-xchange.com>
Fri, 22 Apr 2022 10:09:21 +0000 (10:09 +0000)
committerMarco Bettini <marco.bettini@open-xchange.com>
Wed, 1 Jun 2022 10:02:08 +0000 (10:02 +0000)
src/doveadm/Makefile.am
src/doveadm/doveadm-cmd-parse.c [new file with mode: 0644]
src/doveadm/doveadm-cmd-parse.h [new file with mode: 0644]
src/doveadm/doveadm-cmd.c
src/doveadm/doveadm-cmd.h

index 7ec204c88f779eca68a9bddd08ee5075ee13efa9..9f9e116eaa56eaf42345ad7f92921608e2c599fe 100644 (file)
@@ -131,6 +131,7 @@ common = \
        $(doveadm_common_mail_cmds) \
        $(doveadm_common_dump_cmds) \
        doveadm-cmd.c \
+       doveadm-cmd-parse.c \
        doveadm-print.c \
        doveadm-settings.c \
        doveadm-util.c \
@@ -160,6 +161,7 @@ pkginc_libdir = $(pkgincludedir)
 pkginc_lib_HEADERS = \
        doveadm.h \
        doveadm-cmd.h \
+       doveadm-cmd-parse.h \
        doveadm-dsync.h \
        doveadm-dump.h \
        doveadm-mail.h \
diff --git a/src/doveadm/doveadm-cmd-parse.c b/src/doveadm/doveadm-cmd-parse.c
new file mode 100644 (file)
index 0000000..b43be65
--- /dev/null
@@ -0,0 +1,307 @@
+/* Copyright (c) 2009-2016 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "array.h"
+#include "istream.h"
+#include "str.h"
+#include "net.h"
+#include "doveadm.h"
+#include "doveadm-cmd-parse.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <getopt.h>
+
+ARRAY_DEFINE_TYPE(getopt_option_array, struct option);
+
+static const struct doveadm_cmd_param *
+doveadm_cmd_param_get(const struct doveadm_cmd_context *cctx,
+                     const char *name)
+{
+       i_assert(cctx != NULL);
+       i_assert(cctx->argv != NULL);
+       for(int i = 0; i < cctx->argc; i++) {
+               if (strcmp(cctx->argv[i].name, name) == 0 &&
+                   cctx->argv[i].value_set)
+                       return &cctx->argv[i];
+       }
+       return NULL;
+}
+
+bool doveadm_cmd_param_bool(const struct doveadm_cmd_context *cctx,
+                           const char *name, bool *value_r)
+{
+       const struct doveadm_cmd_param *param;
+       if ((param = doveadm_cmd_param_get(cctx, name)) == NULL)
+               return FALSE;
+
+       if (param->type == CMD_PARAM_BOOL) {
+               *value_r = param->value.v_bool;
+               return TRUE;
+       }
+       return FALSE;
+}
+
+bool doveadm_cmd_param_int64(const struct doveadm_cmd_context *cctx,
+                            const char *name, int64_t *value_r)
+{
+       const struct doveadm_cmd_param *param;
+       if ((param = doveadm_cmd_param_get(cctx, name)) == NULL)
+               return FALSE;
+
+       if (param->type == CMD_PARAM_INT64) {
+               *value_r = param->value.v_int64;
+               return TRUE;
+       }
+       return FALSE;
+}
+
+bool doveadm_cmd_param_str(const struct doveadm_cmd_context *cctx,
+                          const char *name, const char **value_r)
+{
+       const struct doveadm_cmd_param *param;
+       if ((param = doveadm_cmd_param_get(cctx, name)) == NULL)
+               return FALSE;
+
+       if (param->type == CMD_PARAM_STR) {
+               *value_r = param->value.v_string;
+               return TRUE;
+       }
+       return FALSE;
+}
+
+bool doveadm_cmd_param_ip(const struct doveadm_cmd_context *cctx,
+                         const char *name, struct ip_addr *value_r)
+{
+       const struct doveadm_cmd_param *param;
+       if ((param = doveadm_cmd_param_get(cctx, name)) == NULL)
+               return FALSE;
+
+       if (param->type == CMD_PARAM_IP) {
+               memcpy(value_r, &param->value.v_ip, sizeof(struct ip_addr));
+               return TRUE;
+       }
+       return FALSE;
+}
+
+bool doveadm_cmd_param_array(const struct doveadm_cmd_context *cctx,
+                            const char *name, const char *const **value_r)
+{
+       const struct doveadm_cmd_param *param;
+       unsigned int count;
+
+       if ((param = doveadm_cmd_param_get(cctx, name)) == NULL)
+               return FALSE;
+       if (param->type == CMD_PARAM_ARRAY) {
+               *value_r = array_get(&param->value.v_array, &count);
+               /* doveadm_cmd_params_null_terminate_arrays() should have been
+                  called, which guarantees that we're NULL-terminated */
+               i_assert((*value_r)[count] == NULL);
+               return TRUE;
+       }
+       return FALSE;
+}
+
+bool doveadm_cmd_param_istream(const struct doveadm_cmd_context *cctx,
+                              const char *name, struct istream **value_r)
+{
+       const struct doveadm_cmd_param *param;
+       if ((param = doveadm_cmd_param_get(cctx, name)) == NULL)
+               return FALSE;
+
+       if (param->type == CMD_PARAM_ISTREAM) {
+               *value_r = param->value.v_istream;
+               return TRUE;
+       }
+       return FALSE;
+}
+
+void doveadm_cmd_params_clean(ARRAY_TYPE(doveadm_cmd_param_arr_t) *pargv)
+{
+       struct doveadm_cmd_param *param;
+
+       array_foreach_modifiable(pargv, param) {
+               if (param->type == CMD_PARAM_ISTREAM &&
+                   param->value.v_istream != NULL)
+                       i_stream_destroy(&param->value.v_istream);
+       }
+       array_clear(pargv);
+}
+
+void doveadm_cmd_params_null_terminate_arrays(
+       ARRAY_TYPE(doveadm_cmd_param_arr_t) *pargv)
+{
+       struct doveadm_cmd_param *param;
+
+       array_foreach_modifiable(pargv, param) {
+               if (param->type == CMD_PARAM_ARRAY &&
+                   array_is_created(&param->value.v_array)) {
+                       array_append_zero(&param->value.v_array);
+                       array_pop_back(&param->value.v_array);
+               }
+       }
+}
+
+static void
+doveadm_build_options(const struct doveadm_cmd_param par[],
+                     string_t *shortopts,
+                     ARRAY_TYPE(getopt_option_array) *longopts)
+{
+       for (size_t i = 0; par[i].name != NULL; i++) {
+               struct option longopt;
+
+               i_zero(&longopt);
+               longopt.name = par[i].name;
+               if (par[i].short_opt != '\0') {
+                       longopt.val = par[i].short_opt;
+                       str_append_c(shortopts, par[i].short_opt);
+                       if (par[i].type != CMD_PARAM_BOOL)
+                               str_append_c(shortopts, ':');
+               }
+               if (par[i].type != CMD_PARAM_BOOL)
+                       longopt.has_arg = 1;
+               array_push_back(longopts, &longopt);
+       }
+       array_append_zero(longopts);
+}
+
+static void
+doveadm_fill_param(struct doveadm_cmd_param *param,
+                  const char *value, pool_t pool)
+{
+       param->value_set = TRUE;
+       switch (param->type) {
+       case CMD_PARAM_BOOL:
+               param->value.v_bool = TRUE;
+               break;
+       case CMD_PARAM_INT64:
+               if (str_to_int64(value, &param->value.v_int64) != 0)
+                       param->value_set = FALSE;
+               break;
+       case CMD_PARAM_IP:
+               if (net_addr2ip(value, &param->value.v_ip) != 0)
+                       param->value_set = FALSE;
+               break;
+       case CMD_PARAM_STR:
+               param->value.v_string = p_strdup(pool, value);
+               break;
+       case CMD_PARAM_ARRAY:
+               if (!array_is_created(&param->value.v_array))
+                       p_array_init(&param->value.v_array, pool, 8);
+               const char *val = p_strdup(pool, value);
+               array_push_back(&param->value.v_array, &val);
+               break;
+       case CMD_PARAM_ISTREAM: {
+               struct istream *is;
+               if (strcmp(value,"-") == 0)
+                       is = i_stream_create_fd(STDIN_FILENO, IO_BLOCK_SIZE);
+               else
+                       is = i_stream_create_file(value, IO_BLOCK_SIZE);
+               param->value.v_istream = is;
+               break;
+       }
+       }
+}
+
+static int
+doveadm_cmd_process_options(int argc, const char *const argv[],
+                           struct doveadm_cmd_context *cctx, pool_t pool,
+                           ARRAY_TYPE(doveadm_cmd_param_arr_t) *pargv)
+{
+       struct doveadm_cmd_param *param;
+       ARRAY_TYPE(getopt_option_array) opts;
+       string_t *optbuf = str_new(pool, 64);
+
+       p_array_init(&opts, pool, 4);
+
+       // build parameters
+       if ((cctx->cmd->flags & CMD_FLAG_NO_UNORDERED_OPTIONS) != 0)
+               str_append_c(optbuf, '+');
+       doveadm_build_options(cctx->cmd->parameters, optbuf, &opts);
+
+       unsigned int pargc;
+       for (pargc = 0; cctx->cmd->parameters[pargc].name != NULL; pargc++) {
+               param = array_append_space(pargv);
+               memcpy(param, &cctx->cmd->parameters[pargc],
+                      sizeof(struct doveadm_cmd_param));
+               param->value_set = FALSE;
+       }
+       i_assert(pargc == array_count(&opts)-1); /* opts is NULL-terminated */
+
+       if ((cctx->cmd->flags & CMD_FLAG_NO_OPTIONS) != 0) {
+               /* process -parameters as if they were regular parameters */
+               optind = 1;
+               return 0;
+       }
+
+       int c, li;
+       while ((c = getopt_long(argc, (char *const *)argv, str_c(optbuf),
+                               array_front(&opts), &li)) > -1) {
+               switch (c) {
+               case 0:
+                       for (unsigned int i = 0; i < array_count(pargv); i++) {
+                               const struct option *opt = array_idx(&opts, li);
+                               param = array_idx_modifiable(pargv, i);
+                               if (opt->name == param->name)
+                                       doveadm_fill_param(param, optarg, pool);
+                       }
+                       break;
+               case '?':
+               case ':':
+                       doveadm_cmd_params_clean(pargv);
+                       return -1;
+               default:
+                       // hunt the option
+                       for (unsigned int i = 0; i < pargc; i++) {
+                               const struct option *longopt =
+                                       array_idx(&opts, i);
+                               if (longopt->val == c)
+                                       doveadm_fill_param(array_idx_modifiable(pargv, i),
+                                                          optarg, pool);
+                       }
+               }
+       }
+       return 0;
+}
+
+int doveadm_cmdline_run(int argc, const char *const argv[],
+                       struct doveadm_cmd_context *cctx)
+{
+       ARRAY_TYPE(doveadm_cmd_param_arr_t) pargv;
+       unsigned int pargc;
+       pool_t pool = pool_datastack_create();
+
+       p_array_init(&pargv, pool, 20);
+       if (doveadm_cmd_process_options(argc, argv, cctx, pool, &pargv) < 0)
+               return -1;
+
+       /* process positional arguments */
+       for (; optind < argc; optind++) {
+               struct doveadm_cmd_param *ptr;
+               bool found = FALSE;
+               array_foreach_modifiable(&pargv, ptr) {
+                       if ((ptr->flags & CMD_PARAM_FLAG_POSITIONAL) != 0 &&
+                           (ptr->value_set == FALSE ||
+                            ptr->type == CMD_PARAM_ARRAY)) {
+                               doveadm_fill_param(ptr, argv[optind], pool);
+                               found = TRUE;
+                               break;
+                       }
+               }
+               if (!found) {
+                       i_error("Extraneous arguments found: %s",
+                               t_strarray_join(argv + optind, " "));
+                       doveadm_cmd_params_clean(&pargv);
+                       return -1;
+               }
+       }
+
+       doveadm_cmd_params_null_terminate_arrays(&pargv);
+       cctx->argv = array_get_modifiable(&pargv, &pargc);
+       cctx->argc = pargc;
+
+       cctx->cmd->cmd(cctx);
+
+       doveadm_cmd_params_clean(&pargv);
+       return 0;
+}
diff --git a/src/doveadm/doveadm-cmd-parse.h b/src/doveadm/doveadm-cmd-parse.h
new file mode 100644 (file)
index 0000000..db7c4f3
--- /dev/null
@@ -0,0 +1,111 @@
+#ifndef DOVEADM_CMD_PARSE_H
+#define DOVEADM_CMD_PARSE_H
+
+#include "net.h"
+
+#define DOVEADM_CMD_PARAMS_START .parameters = (const struct doveadm_cmd_param[]){
+#define DOVEADM_CMD_PARAM(optP, nameP, typeP, flagP ) { .short_opt = optP, .name = nameP, .type = typeP, .flags = flagP },
+#define DOVEADM_CMD_PARAMS_END { .short_opt = '\0', .name = NULL, .type = CMD_PARAM_BOOL, .flags = CMD_PARAM_FLAG_NONE } }
+
+struct doveadm_cmd_context;
+struct doveadm_mail_cmd_context;
+
+typedef enum {
+       CMD_PARAM_BOOL = 0, /* value in v_bool */
+       CMD_PARAM_INT64,    /* value in v_int64 */
+       CMD_PARAM_IP,       /* value in v_ip (struct ip_addr) */
+       CMD_PARAM_STR,      /* value in v_string (const char*) */
+       CMD_PARAM_ARRAY,    /* value in v_array (const char*[]) */
+       CMD_PARAM_ISTREAM   /* value in v_istream (struct istream*) */
+} doveadm_cmd_param_t;
+
+typedef enum {
+       CMD_PARAM_FLAG_NONE             = 0x0,
+       CMD_PARAM_FLAG_POSITIONAL       = 0x1,
+       CMD_PARAM_FLAG_DO_NOT_EXPOSE    = 0x2,
+} doveadm_cmd_param_flag_t;
+
+typedef enum {
+       CMD_FLAG_NONE                   = 0x0,
+       CMD_FLAG_HIDDEN                 = 0x1,
+       CMD_FLAG_NO_PRINT               = 0x2,
+       /* Don't parse any -options for the command. */
+       CMD_FLAG_NO_OPTIONS             = 0x4,
+       /* Prevent GNU getopt() from finding options after the first
+          non-option is seen (e.g. "-1 arg -2" would parse -1 but not -2
+          as option). */
+       CMD_FLAG_NO_UNORDERED_OPTIONS   = 0x8,
+} doveadm_cmd_flag_t;
+
+struct doveadm_cmd_param {
+       char short_opt;
+       const char *name;
+       doveadm_cmd_param_t type;
+       bool value_set;
+       struct {
+               bool v_bool;
+               int64_t v_int64;
+               const char* v_string;
+               ARRAY_TYPE(const_string) v_array;
+               struct ip_addr v_ip;
+               struct istream* v_istream;
+       } value;
+       doveadm_cmd_param_flag_t flags;
+};
+ARRAY_DEFINE_TYPE(doveadm_cmd_param_arr_t, struct doveadm_cmd_param);
+
+typedef void doveadm_command_ver2_t(struct doveadm_cmd_context *cctx);
+
+struct doveadm_cmd_ver2 {
+       doveadm_command_ver2_t *cmd;
+       struct doveadm_mail_cmd_context *(*mail_cmd)(void);
+       const char *name;
+       const char *usage;
+       doveadm_cmd_flag_t flags;
+       const struct doveadm_cmd_param *parameters;
+};
+
+struct doveadm_cmd_context {
+       const struct doveadm_cmd_ver2 *cmd; /* for help */
+
+       pool_t pool;
+       int argc;
+       const struct doveadm_cmd_param *argv;
+
+       const char *username;
+       struct ip_addr local_ip, remote_ip;
+       in_port_t local_port, remote_port;
+       /* extra fields (e.g. forward_*) sent via doveadm protocol */
+       const char *const *extra_fields;
+
+       enum doveadm_client_type conn_type;
+       struct istream *input;
+       struct ostream *output;
+
+       /* non-NULL if doveadm-server should return referral to another
+          server instead. */
+       const char *referral;
+       bool proxy_redirect_reauth;
+};
+
+/* Returns 0 if success, -1 if parameters were invalid. */
+int doveadm_cmdline_run(int argc, const char *const argv[],
+                       struct doveadm_cmd_context *cctx);
+
+bool doveadm_cmd_param_bool(const struct doveadm_cmd_context *cctx,
+                           const char *name, bool *value_r);
+bool doveadm_cmd_param_int64(const struct doveadm_cmd_context *cctx,
+                            const char *name, int64_t *value_r);
+bool doveadm_cmd_param_str(const struct doveadm_cmd_context *cctx,
+                          const char *name, const char **value_r);
+bool doveadm_cmd_param_ip(const struct doveadm_cmd_context *cctx,
+                         const char *name, struct ip_addr *value_r);
+bool doveadm_cmd_param_array(const struct doveadm_cmd_context *cctx,
+                            const char *name, const char *const **value_r);
+bool doveadm_cmd_param_istream(const struct doveadm_cmd_context *cctx,
+                              const char *name, struct istream **value_r);
+
+void doveadm_cmd_params_clean(ARRAY_TYPE(doveadm_cmd_param_arr_t) *pargv);
+void doveadm_cmd_params_null_terminate_arrays(ARRAY_TYPE(doveadm_cmd_param_arr_t) *pargv);
+
+#endif
index 496827c011e1c724a822a7eb7a90c6c5de196dd8..93f21918dca3bfb75f1d45713520554bf10934d3 100644 (file)
@@ -37,7 +37,6 @@ static struct doveadm_cmd_ver2 *doveadm_commands_ver2[] = {
 };
 
 ARRAY_TYPE(doveadm_cmd_ver2) doveadm_cmds_ver2;
-ARRAY_DEFINE_TYPE(getopt_option_array, struct option);
 
 void doveadm_cmd_register_ver2(struct doveadm_cmd_ver2 *cmd)
 {
@@ -129,195 +128,6 @@ void doveadm_cmds_deinit(void)
        array_free(&doveadm_cmds_ver2);
 }
 
-static const struct doveadm_cmd_param *
-doveadm_cmd_param_get(const struct doveadm_cmd_context *cctx,
-                     const char *name)
-{
-       i_assert(cctx != NULL);
-       i_assert(cctx->argv != NULL);
-       for(int i = 0; i < cctx->argc; i++) {
-               if (strcmp(cctx->argv[i].name, name) == 0 &&
-                   cctx->argv[i].value_set)
-                       return &cctx->argv[i];
-       }
-       return NULL;
-}
-
-bool doveadm_cmd_param_bool(const struct doveadm_cmd_context *cctx,
-                           const char *name, bool *value_r)
-{
-       const struct doveadm_cmd_param *param;
-       if ((param = doveadm_cmd_param_get(cctx, name)) == NULL)
-               return FALSE;
-
-       if (param->type == CMD_PARAM_BOOL) {
-               *value_r = param->value.v_bool;
-               return TRUE;
-       }
-       return FALSE;
-}
-
-bool doveadm_cmd_param_int64(const struct doveadm_cmd_context *cctx,
-                            const char *name, int64_t *value_r)
-{
-       const struct doveadm_cmd_param *param;
-       if ((param = doveadm_cmd_param_get(cctx, name)) == NULL)
-               return FALSE;
-
-       if (param->type == CMD_PARAM_INT64) {
-               *value_r = param->value.v_int64;
-               return TRUE;
-       }
-       return FALSE;
-}
-
-bool doveadm_cmd_param_str(const struct doveadm_cmd_context *cctx,
-                          const char *name, const char **value_r)
-{
-       const struct doveadm_cmd_param *param;
-       if ((param = doveadm_cmd_param_get(cctx, name)) == NULL)
-               return FALSE;
-
-       if (param->type == CMD_PARAM_STR) {
-               *value_r = param->value.v_string;
-               return TRUE;
-       }
-       return FALSE;
-}
-
-bool doveadm_cmd_param_ip(const struct doveadm_cmd_context *cctx,
-                         const char *name, struct ip_addr *value_r)
-{
-       const struct doveadm_cmd_param *param;
-       if ((param = doveadm_cmd_param_get(cctx, name)) == NULL)
-               return FALSE;
-
-       if (param->type == CMD_PARAM_IP) {
-               memcpy(value_r, &param->value.v_ip, sizeof(struct ip_addr));
-               return TRUE;
-       }
-       return FALSE;
-}
-
-bool doveadm_cmd_param_array(const struct doveadm_cmd_context *cctx,
-                            const char *name, const char *const **value_r)
-{
-       const struct doveadm_cmd_param *param;
-       unsigned int count;
-
-       if ((param = doveadm_cmd_param_get(cctx, name)) == NULL)
-               return FALSE;
-       if (param->type == CMD_PARAM_ARRAY) {
-               *value_r = array_get(&param->value.v_array, &count);
-               /* doveadm_cmd_params_null_terminate_arrays() should have been
-                  called, which guarantees that we're NULL-terminated */
-               i_assert((*value_r)[count] == NULL);
-               return TRUE;
-       }
-       return FALSE;
-}
-
-bool doveadm_cmd_param_istream(const struct doveadm_cmd_context *cctx,
-                              const char *name, struct istream **value_r)
-{
-       const struct doveadm_cmd_param *param;
-       if ((param = doveadm_cmd_param_get(cctx, name)) == NULL)
-               return FALSE;
-
-       if (param->type == CMD_PARAM_ISTREAM) {
-               *value_r = param->value.v_istream;
-               return TRUE;
-       }
-       return FALSE;
-}
-
-void doveadm_cmd_params_clean(ARRAY_TYPE(doveadm_cmd_param_arr_t) *pargv)
-{
-       struct doveadm_cmd_param *param;
-
-       array_foreach_modifiable(pargv, param) {
-               if (param->type == CMD_PARAM_ISTREAM &&
-                   param->value.v_istream != NULL)
-                       i_stream_destroy(&param->value.v_istream);
-       }
-       array_clear(pargv);
-}
-
-void doveadm_cmd_params_null_terminate_arrays(
-       ARRAY_TYPE(doveadm_cmd_param_arr_t) *pargv)
-{
-       struct doveadm_cmd_param *param;
-
-       array_foreach_modifiable(pargv, param) {
-               if (param->type == CMD_PARAM_ARRAY &&
-                   array_is_created(&param->value.v_array)) {
-                       array_append_zero(&param->value.v_array);
-                       array_pop_back(&param->value.v_array);
-               }
-       }
-}
-
-static void
-doveadm_build_options(const struct doveadm_cmd_param par[],
-                     string_t *shortopts,
-                     ARRAY_TYPE(getopt_option_array) *longopts)
-{
-       for (size_t i = 0; par[i].name != NULL; i++) {
-               struct option longopt;
-
-               i_zero(&longopt);
-               longopt.name = par[i].name;
-               if (par[i].short_opt != '\0') {
-                       longopt.val = par[i].short_opt;
-                       str_append_c(shortopts, par[i].short_opt);
-                       if (par[i].type != CMD_PARAM_BOOL)
-                               str_append_c(shortopts, ':');
-               }
-               if (par[i].type != CMD_PARAM_BOOL)
-                       longopt.has_arg = 1;
-               array_push_back(longopts, &longopt);
-       }
-       array_append_zero(longopts);
-}
-
-static void
-doveadm_fill_param(struct doveadm_cmd_param *param,
-                  const char *value, pool_t pool)
-{
-       param->value_set = TRUE;
-       switch (param->type) {
-       case CMD_PARAM_BOOL:
-               param->value.v_bool = TRUE;
-               break;
-       case CMD_PARAM_INT64:
-               if (str_to_int64(value, &param->value.v_int64) != 0)
-                       param->value_set = FALSE;
-               break;
-       case CMD_PARAM_IP:
-               if (net_addr2ip(value, &param->value.v_ip) != 0)
-                       param->value_set = FALSE;
-               break;
-       case CMD_PARAM_STR:
-               param->value.v_string = p_strdup(pool, value);
-               break;
-       case CMD_PARAM_ARRAY:
-               if (!array_is_created(&param->value.v_array))
-                       p_array_init(&param->value.v_array, pool, 8);
-               const char *val = p_strdup(pool, value);
-               array_push_back(&param->value.v_array, &val);
-               break;
-       case CMD_PARAM_ISTREAM: {
-               struct istream *is;
-               if (strcmp(value,"-") == 0)
-                       is = i_stream_create_fd(STDIN_FILENO, IO_BLOCK_SIZE);
-               else
-                       is = i_stream_create_file(value, IO_BLOCK_SIZE);
-               param->value.v_istream = is;
-               break;
-       }
-       }
-}
-
 bool doveadm_cmdline_try_run(const char *cmd_name,
                             int argc, const char *const argv[],
                             struct doveadm_cmd_context *cctx)
@@ -333,106 +143,3 @@ bool doveadm_cmdline_try_run(const char *cmd_name,
                doveadm_exit_code = EX_USAGE;
        return TRUE;
 }
-
-static int
-doveadm_cmd_process_options(int argc, const char *const argv[],
-                           struct doveadm_cmd_context *cctx, pool_t pool,
-                           ARRAY_TYPE(doveadm_cmd_param_arr_t) *pargv)
-{
-       struct doveadm_cmd_param *param;
-       ARRAY_TYPE(getopt_option_array) opts;
-       string_t *optbuf = str_new(pool, 64);
-
-       p_array_init(&opts, pool, 4);
-
-       // build parameters
-       if ((cctx->cmd->flags & CMD_FLAG_NO_UNORDERED_OPTIONS) != 0)
-               str_append_c(optbuf, '+');
-       doveadm_build_options(cctx->cmd->parameters, optbuf, &opts);
-
-       unsigned int pargc;
-       for (pargc = 0; cctx->cmd->parameters[pargc].name != NULL; pargc++) {
-               param = array_append_space(pargv);
-               memcpy(param, &cctx->cmd->parameters[pargc],
-                      sizeof(struct doveadm_cmd_param));
-               param->value_set = FALSE;
-       }
-       i_assert(pargc == array_count(&opts)-1); /* opts is NULL-terminated */
-
-       if ((cctx->cmd->flags & CMD_FLAG_NO_OPTIONS) != 0) {
-               /* process -parameters as if they were regular parameters */
-               optind = 1;
-               return 0;
-       }
-
-       int c, li;
-       while ((c = getopt_long(argc, (char *const *)argv, str_c(optbuf),
-                               array_front(&opts), &li)) > -1) {
-               switch (c) {
-               case 0:
-                       for (unsigned int i = 0; i < array_count(pargv); i++) {
-                               const struct option *opt = array_idx(&opts, li);
-                               param = array_idx_modifiable(pargv, i);
-                               if (opt->name == param->name)
-                                       doveadm_fill_param(param, optarg, pool);
-                       }
-                       break;
-               case '?':
-               case ':':
-                       doveadm_cmd_params_clean(pargv);
-                       return -1;
-               default:
-                       // hunt the option
-                       for (unsigned int i = 0; i < pargc; i++) {
-                               const struct option *longopt =
-                                       array_idx(&opts, i);
-                               if (longopt->val == c)
-                                       doveadm_fill_param(array_idx_modifiable(pargv, i),
-                                                          optarg, pool);
-                       }
-               }
-       }
-       return 0;
-}
-
-int doveadm_cmdline_run(int argc, const char *const argv[],
-                       struct doveadm_cmd_context *cctx)
-{
-       ARRAY_TYPE(doveadm_cmd_param_arr_t) pargv;
-       unsigned int pargc;
-       pool_t pool = pool_datastack_create();
-
-       p_array_init(&pargv, pool, 20);
-       if (doveadm_cmd_process_options(argc, argv, cctx, pool, &pargv) < 0)
-               return -1;
-
-       /* process positional arguments */
-       for (; optind < argc; optind++) {
-               struct doveadm_cmd_param *ptr;
-               bool found = FALSE;
-               array_foreach_modifiable(&pargv, ptr) {
-                       if ((ptr->flags & CMD_PARAM_FLAG_POSITIONAL) != 0 &&
-                           (ptr->value_set == FALSE ||
-                            ptr->type == CMD_PARAM_ARRAY)) {
-                               doveadm_fill_param(ptr, argv[optind], pool);
-                               found = TRUE;
-                               break;
-                       }
-               }
-               if (!found) {
-                       i_error("Extraneous arguments found: %s",
-                               t_strarray_join(argv + optind, " "));
-                       doveadm_cmd_params_clean(&pargv);
-                       return -1;
-               }
-       }
-
-       doveadm_cmd_params_null_terminate_arrays(&pargv);
-       cctx->argv = array_get_modifiable(&pargv, &pargc);
-       cctx->argc = pargc;
-
-       cctx->cmd->cmd(cctx);
-
-       doveadm_cmd_params_clean(&pargv);
-       return 0;
-}
index 8bbb55c723e232e9f6209591452974f063906560..1c435ab3ba0a945db92ac13271ffb9a4f3aeb3ee 100644 (file)
@@ -1,96 +1,10 @@
 #ifndef DOVEADM_CMD_H
 #define DOVEADM_CMD_H
 
-#include "net.h"
-
-#define DOVEADM_CMD_PARAMS_START .parameters = (const struct doveadm_cmd_param[]){
-#define DOVEADM_CMD_PARAM(optP, nameP, typeP, flagP ) { .short_opt = optP, .name = nameP, .type = typeP, .flags = flagP },
-#define DOVEADM_CMD_PARAMS_END { .short_opt = '\0', .name = NULL, .type = CMD_PARAM_BOOL, .flags = CMD_PARAM_FLAG_NONE } }
-
-struct doveadm_cmd_ver2;
-struct doveadm_cmd_context;
-struct doveadm_mail_cmd_context;
+#include "doveadm-cmd-parse.h"
 
 typedef void doveadm_command_t(int argc, char *argv[]);
 
-typedef enum {
-       CMD_PARAM_BOOL = 0, /* value will contain 1 (not pointer) */
-       CMD_PARAM_INT64,    /* ditto but contains number (not pointer) */
-       CMD_PARAM_IP,      /* value contains struct ip_addr */
-       CMD_PARAM_STR,     /* value contains const char* */
-       CMD_PARAM_ARRAY,   /* value contains const char*[] */
-       CMD_PARAM_ISTREAM  /* value contains struct istream* */
-} doveadm_cmd_param_t;
-
-typedef enum {
-       CMD_PARAM_FLAG_NONE             = 0x0,
-       CMD_PARAM_FLAG_POSITIONAL       = 0x1,
-       CMD_PARAM_FLAG_DO_NOT_EXPOSE    = 0x2,
-} doveadm_cmd_param_flag_t;
-
-typedef enum {
-       CMD_FLAG_NONE                   = 0x0,
-       CMD_FLAG_HIDDEN                 = 0x1,
-       CMD_FLAG_NO_PRINT               = 0x2,
-       /* Don't parse any -options for the command. */
-       CMD_FLAG_NO_OPTIONS             = 0x4,
-       /* Prevent GNU getopt() from finding options after the first
-          non-option is seen (e.g. "-1 arg -2" would parse -1 but not -2
-          as option). */
-       CMD_FLAG_NO_UNORDERED_OPTIONS   = 0x8,
-} doveadm_cmd_flag_t;
-
-struct doveadm_cmd_param {
-       char short_opt;
-       const char *name;
-       doveadm_cmd_param_t type;
-       bool value_set;
-       struct {
-               bool v_bool;
-               int64_t v_int64;
-               const char* v_string;
-               ARRAY_TYPE(const_string) v_array;
-               struct ip_addr v_ip;
-               struct istream* v_istream;
-       } value;
-       doveadm_cmd_param_flag_t flags;
-};
-ARRAY_DEFINE_TYPE(doveadm_cmd_param_arr_t, struct doveadm_cmd_param);
-
-typedef void doveadm_command_ver2_t(struct doveadm_cmd_context *cctx);
-
-struct doveadm_cmd_ver2 {
-       doveadm_command_ver2_t *cmd;
-       struct doveadm_mail_cmd_context *(*mail_cmd)(void);
-       const char *name;
-       const char *usage;
-       doveadm_cmd_flag_t flags;
-       const struct doveadm_cmd_param *parameters;
-};
-
-struct doveadm_cmd_context {
-       const struct doveadm_cmd_ver2 *cmd; /* for help */
-
-       pool_t pool;
-       int argc;
-       const struct doveadm_cmd_param *argv;
-
-       const char *username;
-       struct ip_addr local_ip, remote_ip;
-       in_port_t local_port, remote_port;
-       /* extra fields (e.g. forward_*) sent via doveadm protocol */
-       const char *const *extra_fields;
-
-       enum doveadm_client_type conn_type;
-       struct istream *input;
-       struct ostream *output;
-
-       /* non-NULL if doveadm-server should return referral to another
-          server instead. */
-       const char *referral;
-       bool proxy_redirect_reauth;
-};
-
 ARRAY_DEFINE_TYPE(doveadm_cmd_ver2, struct doveadm_cmd_ver2);
 extern ARRAY_TYPE(doveadm_cmd_ver2) doveadm_cmds_ver2;
 
@@ -118,25 +32,6 @@ const struct doveadm_cmd_ver2 *doveadm_cmd_find_ver2(const char *cmd_name);
 bool doveadm_cmdline_try_run(const char *cmd_name,
                             int argc, const char *const argv[],
                             struct doveadm_cmd_context *cctx);
-/* Returns 0 if success, -1 if parameters were invalid. */
-int doveadm_cmdline_run(int argc, const char *const argv[],
-                       struct doveadm_cmd_context *cctx);
-
-bool doveadm_cmd_param_bool(const struct doveadm_cmd_context *cctx,
-                           const char *name, bool *value_r);
-bool doveadm_cmd_param_int64(const struct doveadm_cmd_context *cctx,
-                            const char *name, int64_t *value_r);
-bool doveadm_cmd_param_str(const struct doveadm_cmd_context *cctx,
-                          const char *name, const char **value_r);
-bool doveadm_cmd_param_ip(const struct doveadm_cmd_context *cctx,
-                         const char *name, struct ip_addr *value_r);
-bool doveadm_cmd_param_array(const struct doveadm_cmd_context *cctx,
-                            const char *name, const char *const **value_r);
-bool doveadm_cmd_param_istream(const struct doveadm_cmd_context *cctx,
-                              const char *name, struct istream **value_r);
-
-void doveadm_cmd_params_clean(ARRAY_TYPE(doveadm_cmd_param_arr_t) *pargv);
-void doveadm_cmd_params_null_terminate_arrays(ARRAY_TYPE(doveadm_cmd_param_arr_t) *pargv);
 
 extern struct doveadm_cmd_ver2 doveadm_cmd_dump;
 extern struct doveadm_cmd_ver2 doveadm_cmd_service_stop_ver2;