From: Timo Sirainen Date: Tue, 25 Jan 2022 17:45:32 +0000 (+0100) Subject: doveadm: Add indexer add/remove/list commands X-Git-Tag: 2.4.0~4438 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=98b408516018b6cd97e4e572a7a80287fabbd609;p=thirdparty%2Fdovecot%2Fcore.git doveadm: Add indexer add/remove/list commands --- diff --git a/src/doveadm/Makefile.am b/src/doveadm/Makefile.am index 464835c37e..ff46341966 100644 --- a/src/doveadm/Makefile.am +++ b/src/doveadm/Makefile.am @@ -77,6 +77,7 @@ doveadm_common_cmds = \ doveadm-dict.c \ doveadm-director.c \ doveadm-fs.c \ + doveadm-indexer.c \ doveadm-instance.c \ doveadm-kick.c \ doveadm-log.c \ diff --git a/src/doveadm/doveadm-cmd.c b/src/doveadm/doveadm-cmd.c index 3fd9bc83b9..496827c011 100644 --- a/src/doveadm/doveadm-cmd.c +++ b/src/doveadm/doveadm-cmd.c @@ -31,6 +31,9 @@ static struct doveadm_cmd_ver2 *doveadm_commands_ver2[] = { &doveadm_cmd_proxy_kick_ver2, &doveadm_cmd_who_ver2, &doveadm_cmd_proxy_list_ver2, + &doveadm_cmd_indexer_add, + &doveadm_cmd_indexer_remove, + &doveadm_cmd_indexer_list, }; ARRAY_TYPE(doveadm_cmd_ver2) doveadm_cmds_ver2; diff --git a/src/doveadm/doveadm-cmd.h b/src/doveadm/doveadm-cmd.h index cbb1e50b82..d29ebd9c92 100644 --- a/src/doveadm/doveadm-cmd.h +++ b/src/doveadm/doveadm-cmd.h @@ -159,5 +159,8 @@ extern struct doveadm_cmd_ver2 doveadm_cmd_proxy_list_ver2; extern struct doveadm_cmd_ver2 doveadm_cmd_sis_deduplicate; extern struct doveadm_cmd_ver2 doveadm_cmd_sis_find; extern struct doveadm_cmd_ver2 doveadm_cmd_zlibconnect; +extern struct doveadm_cmd_ver2 doveadm_cmd_indexer_add; +extern struct doveadm_cmd_ver2 doveadm_cmd_indexer_remove; +extern struct doveadm_cmd_ver2 doveadm_cmd_indexer_list; #endif diff --git a/src/doveadm/doveadm-indexer.c b/src/doveadm/doveadm-indexer.c new file mode 100644 index 0000000000..69437cd5a8 --- /dev/null +++ b/src/doveadm/doveadm-indexer.c @@ -0,0 +1,200 @@ +/* Copyright (c) 2022 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "str.h" +#include "strescape.h" +#include "connection.h" +#include "istream.h" +#include "ostream.h" +#include "doveadm.h" +#include "doveadm-print.h" + +#include + +#define INDEXER_SOCKET_NAME "indexer" + +static struct istream *indexer_send_cmd(const char *cmd) +{ + const char *path = t_strconcat(doveadm_settings->base_dir, + "/"INDEXER_SOCKET_NAME, NULL); + const struct connection_settings set = { + .service_name_out = "indexer-client", + .service_name_in = "indexer-server", + .major_version = 1, + .minor_version = 0, + }; + const char *error; + struct istream *input; + struct ostream *output; + if (doveadm_blocking_connect(path, &set, &input, &output, &error) < 0) + i_fatal("%s", error); + o_stream_nsend_str(output, t_strconcat(cmd, "\r\n", NULL)); + if (o_stream_flush(output) < 0) + i_fatal("write(indexer) failed: %s", o_stream_get_error(output)); + o_stream_unref(&output); + return input; +} + +static struct istream * +indexer_send_cmd_with_args(const char *cmd, const char *const *args) +{ + string_t *str = t_str_new(128); + + str_append(str, cmd); + if (args != NULL) { + for (unsigned int i = 0; args[i] != NULL; i++) { + str_append_c(str, '\t'); + str_append_tabescaped(str, args[i]); + } + } + return indexer_send_cmd(str_c(str)); +} + +static void cmd_indexer_add(struct doveadm_cmd_context *cctx) +{ + const char *user, *mailbox, *line; + int64_t max_recent; + bool head; + + if (!doveadm_cmd_param_bool(cctx, "head", &head)) + head = FALSE; + if (!doveadm_cmd_param_int64(cctx, "max-recent", &max_recent)) + max_recent = 0; + if (!doveadm_cmd_param_str(cctx, "user", &user) || + !doveadm_cmd_param_str(cctx, "mailbox", &mailbox)) + help_ver2(&doveadm_cmd_indexer_add); + + const char *cmd = head ? "PREPEND" : "APPEND"; + const char *const args[] = { + "0", user, mailbox, dec2str(max_recent), + NULL + }; + struct istream *input = indexer_send_cmd_with_args(cmd, args); + + alarm(5); + if ((line = i_stream_read_next_line(input)) == NULL) + i_fatal("read(indexer) failed: %s", i_stream_get_error(input)); + if (strcmp(line, "0\tOK") != 0) + i_fatal("indexer: %s returned unexpected reply: %s", cmd, line); + alarm(0); + i_stream_destroy(&input); +} + +static void cmd_indexer_remove(struct doveadm_cmd_context *cctx) +{ + const char *line, *user_mask, *mailbox_mask; + + if (!doveadm_cmd_param_str(cctx, "user-mask", &user_mask)) + help_ver2(&doveadm_cmd_indexer_remove); + if (!doveadm_cmd_param_str(cctx, "mailbox-mask", &mailbox_mask)) + mailbox_mask = NULL; + + const char *const args[] = { "0", user_mask, mailbox_mask, NULL }; + struct istream *input = indexer_send_cmd_with_args("REMOVE", args); + + alarm(5); + if ((line = i_stream_read_next_line(input)) == NULL) + i_fatal("read(indexer) failed: %s", i_stream_get_error(input)); + if (strcmp(line, "0\tOK") != 0) + i_fatal("indexer: REMOVE returned unexpected reply: %s", line); + alarm(0); + i_stream_destroy(&input); +} + +static int cmd_indexer_list_print(const char *const *args) +{ + if (str_array_length(args) < 7) + return -1; + + /* + */ + doveadm_print(args[1]); + doveadm_print(args[2]); + doveadm_print(args[3]); + doveadm_print(args[4]); + switch (args[5][0]) { + case 'i': + doveadm_print("index"); + break; + case 'o': + doveadm_print("optimize"); + break; + default: + doveadm_print(args[5]); + break; + } + if (args[6][0] != 'w') + doveadm_print("queued"); + else if (args[6][1] == 'h') + doveadm_print("working/head-queued"); + else if (args[6][1] == 't') + doveadm_print("working/tail-queued"); + else + doveadm_print("working"); + return 0; +} + +static void cmd_indexer_list(struct doveadm_cmd_context *cctx) +{ + const char *line, *user_mask; + + if (!doveadm_cmd_param_str(cctx, "user-mask", &user_mask)) + user_mask = NULL; + + const char *const args[] = { "0", "all", user_mask, NULL }; + struct istream *input = indexer_send_cmd_with_args("LIST", args); + + doveadm_print_init(DOVEADM_PRINT_TYPE_TABLE); + doveadm_print_header_simple("username"); + doveadm_print_header_simple("mailbox"); + doveadm_print_header_simple("session_id"); + doveadm_print_header_simple("max_recent"); + doveadm_print_header_simple("type"); + doveadm_print_header_simple("status"); + + alarm(30); + while ((line = i_stream_read_next_line(input)) != NULL) { + if (strcmp(line, "0") == 0) + break; + T_BEGIN { + const char *const *args = t_strsplit_tabescaped(line); + if (cmd_indexer_list_print(args) < 0) + i_fatal("Unexpected input: %s", line); + } T_END; + } + if (line == NULL) + i_fatal("read(indexer) failed: %s", i_stream_get_error(input)); + alarm(0); + i_stream_destroy(&input); +} + +struct doveadm_cmd_ver2 doveadm_cmd_indexer_add = { + .cmd = cmd_indexer_add, + .name = "indexer add", + .usage = "[-h] [-n ] ", +DOVEADM_CMD_PARAMS_START +DOVEADM_CMD_PARAM('h', "head", CMD_PARAM_BOOL, 0) +DOVEADM_CMD_PARAM('n', "max-recent", CMD_PARAM_STR, 0) +DOVEADM_CMD_PARAM('\0', "user", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAM('\0', "mailbox", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAMS_END +}; + +struct doveadm_cmd_ver2 doveadm_cmd_indexer_remove = { + .cmd = cmd_indexer_remove, + .name = "indexer remove", + .usage = " []", +DOVEADM_CMD_PARAMS_START +DOVEADM_CMD_PARAM('\0', "user-mask", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAM('\0', "mailbox-mask", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAMS_END +}; + +struct doveadm_cmd_ver2 doveadm_cmd_indexer_list = { + .cmd = cmd_indexer_list, + .name = "indexer list", + .usage = "[]", +DOVEADM_CMD_PARAMS_START +DOVEADM_CMD_PARAM('\0', "user-mask", CMD_PARAM_STR, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAMS_END +};