doveadm-mail.c revision 82130fea452f0bed0deb41405ccfedbf674e0e6c
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (c) 2009-2016 Dovecot authors, see the included COPYING file */
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "lib.h"
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen#include "array.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "lib-signals.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "ioloop.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "istream.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "istream-dot.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "istream-seekable.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "str.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "unichar.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "module-dir.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "wildcard-match.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "master-service.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "mail-user.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "mail-namespace.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "mail-storage.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "mail-storage-settings.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "mail-storage-service.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "mail-storage-hooks.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "mail-search-build.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "mail-search-parser.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "mailbox-list-iter.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "client-connection.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "doveadm.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "doveadm-settings.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "doveadm-print.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "doveadm-dsync.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include "doveadm-mail.h"
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#include <stdio.h>
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen#define DOVEADM_MAIL_CMD_INPUT_TIMEOUT_MSECS (5*60*1000)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo SirainenARRAY_TYPE(doveadm_mail_cmd) doveadm_mail_cmds;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenvoid (*hook_doveadm_mail_init)(struct doveadm_mail_cmd_context *ctx);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstruct doveadm_mail_cmd_module_register
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen doveadm_mail_cmd_module_register = { 0 };
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenchar doveadm_mail_cmd_hide = '\0';
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic int killed_signo = 0;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenbool doveadm_is_killed(void)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return killed_signo != 0;
9398c0935613ba038cf2275ff66c43b25092cfd0Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenint doveadm_killed_signo(void)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return killed_signo;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainenvoid doveadm_mail_failed_error(struct doveadm_mail_cmd_context *ctx,
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen enum mail_error error)
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen{
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen int exit_code = 0;
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen switch (error) {
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen case MAIL_ERROR_NONE:
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen i_unreached();
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen case MAIL_ERROR_TEMP:
7569ab8537418b7fc369265f26595b0ef9e4cb35Timo Sirainen exit_code = EX_TEMPFAIL;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen break;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen case MAIL_ERROR_NOTPOSSIBLE:
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen case MAIL_ERROR_EXISTS:
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen case MAIL_ERROR_CONVERSION:
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen case MAIL_ERROR_INVALIDDATA:
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen exit_code = DOVEADM_EX_NOTPOSSIBLE;
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen break;
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen case MAIL_ERROR_PARAMS:
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen exit_code = EX_USAGE;
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen break;
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen case MAIL_ERROR_PERM:
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen exit_code = EX_NOPERM;
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen break;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen case MAIL_ERROR_NOQUOTA:
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen exit_code = EX_CANTCREAT;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen break;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen case MAIL_ERROR_NOTFOUND:
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen exit_code = DOVEADM_EX_NOTFOUND;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen break;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen case MAIL_ERROR_EXPUNGED:
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen case MAIL_ERROR_INUSE:
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen exit_code = EX_TEMPFAIL;
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen break;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen }
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen /* tempfail overrides all other exit codes, otherwise use whatever
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen error happened first */
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen if (ctx->exit_code == 0 || exit_code == EX_TEMPFAIL)
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen ctx->exit_code = exit_code;
fc8d5f0ac909cca77840538e8beef98a8d40c21cTimo Sirainen}
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainenvoid doveadm_mail_failed_storage(struct doveadm_mail_cmd_context *ctx,
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen struct mail_storage *storage)
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen{
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen enum mail_error error;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen mail_storage_get_last_error(storage, &error);
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen doveadm_mail_failed_error(ctx, error);
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen}
fc8d5f0ac909cca77840538e8beef98a8d40c21cTimo Sirainen
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainenvoid doveadm_mail_failed_mailbox(struct doveadm_mail_cmd_context *ctx,
fc8d5f0ac909cca77840538e8beef98a8d40c21cTimo Sirainen struct mailbox *box)
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen{
fc8d5f0ac909cca77840538e8beef98a8d40c21cTimo Sirainen doveadm_mail_failed_storage(ctx, mailbox_get_storage(box));
33dd58ab84a020c4f061d2f6031eb6d4c168df1bTimo Sirainen}
33dd58ab84a020c4f061d2f6031eb6d4c168df1bTimo Sirainen
33dd58ab84a020c4f061d2f6031eb6d4c168df1bTimo Sirainenvoid doveadm_mail_failed_list(struct doveadm_mail_cmd_context *ctx,
33dd58ab84a020c4f061d2f6031eb6d4c168df1bTimo Sirainen struct mailbox_list *list)
33dd58ab84a020c4f061d2f6031eb6d4c168df1bTimo Sirainen{
5d4855d7b4dcffb6975ed8e3c9c376dac74e5c8aTimo Sirainen enum mail_error error;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen mailbox_list_get_last_error(list, &error);
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen doveadm_mail_failed_error(ctx, error);
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen}
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainenstruct doveadm_mail_cmd_context *
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainendoveadm_mail_cmd_alloc_size(size_t size)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen struct doveadm_mail_cmd_context *ctx;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen pool_t pool;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_assert(size >= sizeof(struct doveadm_mail_cmd_context));
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen pool = pool_alloconly_create("doveadm mail cmd", 1024);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ctx = p_malloc(pool, size);
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen ctx->pool = pool;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return ctx;
8eb94c5190ba09bb6f6f068eec7bf96750f08d1dTimo Sirainen}
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
8eb94c5190ba09bb6f6f068eec7bf96750f08d1dTimo Sirainenstatic int
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainencmd_purge_run(struct doveadm_mail_cmd_context *ctx, struct mail_user *user)
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen{
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen struct mail_namespace *ns;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen struct mail_storage *storage;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen int ret = 0;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen for (ns = user->namespaces; ns != NULL; ns = ns->next) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (ns->type != MAIL_NAMESPACE_TYPE_PRIVATE ||
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ns->alias_for != NULL)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen continue;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen storage = mail_namespace_get_default_storage(ns);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (mail_storage_purge(storage) < 0) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_error("Purging namespace '%s' failed: %s", ns->prefix,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen mail_storage_get_last_error(storage, NULL));
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen doveadm_mail_failed_storage(ctx, storage);
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen ret = -1;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen }
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen }
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen return ret;
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen}
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainenstatic struct doveadm_mail_cmd_context *cmd_purge_alloc(void)
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen{
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen struct doveadm_mail_cmd_context *ctx;
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen ctx = doveadm_mail_cmd_alloc(struct doveadm_mail_cmd_context);
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen ctx->v.run = cmd_purge_run;
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen return ctx;
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen}
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainenstatic void doveadm_mail_cmd_input_input(struct doveadm_mail_cmd_context *ctx)
8eb94c5190ba09bb6f6f068eec7bf96750f08d1dTimo Sirainen{
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen while (i_stream_read(ctx->cmd_input) > 0)
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen i_stream_skip(ctx->cmd_input, i_stream_get_data_size(ctx->cmd_input));
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen if (!ctx->cmd_input->eof)
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen return;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen if (ctx->cmd_input->stream_errno != 0) {
adc409a7ac9689d3baf811712ad5a5432cab2d87Timo Sirainen i_error("read(%s) failed: %s",
b321df9603081896b70ec44635af96d674a9839aTimo Sirainen i_stream_get_name(ctx->cmd_input),
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_stream_get_error(ctx->cmd_input));
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
f968e62caa52a8924bd05ebf76ff515b5c18e17bTimo Sirainen io_loop_stop(current_ioloop);
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen}
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic void doveadm_mail_cmd_input_timeout(struct doveadm_mail_cmd_context *ctx)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen struct istream *input;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen input = i_stream_create_error_str(ETIMEDOUT, "Timed out in %u secs",
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen DOVEADM_MAIL_CMD_INPUT_TIMEOUT_MSECS/1000);
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen i_stream_set_name(input, i_stream_get_name(ctx->cmd_input));
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen i_stream_destroy(&ctx->cmd_input);
47bb4a7615c85f212f061499f04f121d6d625387Timo Sirainen ctx->cmd_input = input;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen io_loop_stop(current_ioloop);
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainenstatic void doveadm_mail_cmd_input_read(struct doveadm_mail_cmd_context *ctx)
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen{
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen struct ioloop *ioloop;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen struct io *io;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen struct timeout *to;
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen ioloop = io_loop_create();
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen io = io_add(ctx->cmd_input_fd, IO_READ,
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen doveadm_mail_cmd_input_input, ctx);
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen to = timeout_add(DOVEADM_MAIL_CMD_INPUT_TIMEOUT_MSECS,
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen doveadm_mail_cmd_input_timeout, ctx);
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen /* read the pending input from stream. */
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen io_loop_set_running(ioloop);
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen doveadm_mail_cmd_input_input(ctx);
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen if (io_loop_is_running(ioloop))
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen io_loop_run(ioloop);
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainen io_remove(&io);
4376643cd2c7110e752c09f838f2c4eee6ed8ac6Timo Sirainen timeout_remove(&to);
938835576b218f6bb9498d829cef9514f8609c6fTimo Sirainen io_loop_destroy(&ioloop);
938835576b218f6bb9498d829cef9514f8609c6fTimo Sirainen
938835576b218f6bb9498d829cef9514f8609c6fTimo Sirainen i_assert(ctx->cmd_input->eof);
938835576b218f6bb9498d829cef9514f8609c6fTimo Sirainen i_stream_seek(ctx->cmd_input, 0);
938835576b218f6bb9498d829cef9514f8609c6fTimo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
226259ee6fb9830dafc1a5ba1e95bf5a4345b406Timo Sirainenvoid doveadm_mail_get_input(struct doveadm_mail_cmd_context *ctx)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen struct istream *inputs[2];
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (ctx->cmd_input != NULL)
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen return;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (ctx->conn != NULL)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen inputs[0] = i_stream_create_dot(ctx->conn->input, FALSE);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen else {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen inputs[0] = i_stream_create_fd(STDIN_FILENO, 1024*1024, FALSE);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_stream_set_name(inputs[0], "stdin");
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen inputs[1] = NULL;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ctx->cmd_input_fd = i_stream_get_fd(inputs[0]);
a8e132559a7ebe54c8269d79ce29fa3338c76199Timo Sirainen ctx->cmd_input = i_stream_create_seekable_path(inputs, 1024*256,
e2a700d0628e395d64cbcef4b5b4510816bf51c4Timo Sirainen "/tmp/doveadm.");
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen i_stream_set_name(ctx->cmd_input, i_stream_get_name(inputs[0]));
e2a700d0628e395d64cbcef4b5b4510816bf51c4Timo Sirainen i_stream_unref(&inputs[0]);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen doveadm_mail_cmd_input_read(ctx);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen}
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainenstruct mailbox *
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainendoveadm_mailbox_find(struct mail_user *user, const char *mailbox)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
a8e132559a7ebe54c8269d79ce29fa3338c76199Timo Sirainen struct mail_namespace *ns;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (!uni_utf8_str_is_valid(mailbox)) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_fatal_status(EX_DATAERR,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen "Mailbox name not valid UTF-8: %s", mailbox);
a8e132559a7ebe54c8269d79ce29fa3338c76199Timo Sirainen }
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen ns = mail_namespace_find(user->namespaces, mailbox);
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen return mailbox_alloc(ns->list, mailbox, MAILBOX_FLAG_IGNORE_ACLS);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen}
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainenstruct mail_search_args *
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainendoveadm_mail_build_search_args(const char *const args[])
e2a700d0628e395d64cbcef4b5b4510816bf51c4Timo Sirainen{
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen struct mail_search_parser *parser;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen struct mail_search_args *sargs;
e2a700d0628e395d64cbcef4b5b4510816bf51c4Timo Sirainen const char *error, *charset = "UTF-8";
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen parser = mail_search_parser_init_cmdline(args);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen if (mail_search_build(mail_search_register_get_human(),
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen parser, &charset, &sargs, &error) < 0)
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen i_fatal("%s", error);
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen mail_search_parser_deinit(&parser);
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen return sargs;
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen}
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainenstatic int cmd_force_resync_box(struct doveadm_mail_cmd_context *ctx,
43358fffb1d9f3091fd94895e0ac4643c50e2388Timo Sirainen const struct mailbox_info *info)
430c0b0c370bebeeceba2e206be76bc134742f41Timo Sirainen{
25ee72451d16374ed27fdbf829f4ec756c778352Timo Sirainen struct mailbox *box;
a3dd97fb6d92a89c3de0597fed2d4b044c7aeb84Timo Sirainen int ret = 0;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen box = mailbox_alloc(info->ns->list, info->vname,
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen MAILBOX_FLAG_IGNORE_ACLS);
484e12acec34f16e5a8adc001e23ae48f1dda8c7Timo Sirainen if (mailbox_open(box) < 0) {
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen i_error("Opening mailbox %s failed: %s", info->vname,
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen mailbox_get_last_error(box, NULL));
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen doveadm_mail_failed_mailbox(ctx, box);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen ret = -1;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen } else if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FORCE_RESYNC |
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen MAILBOX_SYNC_FLAG_FIX_INCONSISTENT) < 0) {
484e12acec34f16e5a8adc001e23ae48f1dda8c7Timo Sirainen i_error("Forcing a resync on mailbox %s failed: %s",
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen info->vname, mailbox_get_last_error(box, NULL));
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen doveadm_mail_failed_mailbox(ctx, box);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen ret = -1;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen }
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen mailbox_free(&box);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen return ret;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen}
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainenstatic int cmd_force_resync_run(struct doveadm_mail_cmd_context *ctx,
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen struct mail_user *user)
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen{
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen const enum mailbox_list_iter_flags iter_flags =
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen MAILBOX_LIST_ITER_RETURN_NO_FLAGS |
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen MAILBOX_LIST_ITER_STAR_WITHIN_NS;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen const enum mail_namespace_type ns_mask = MAIL_NAMESPACE_TYPE_MASK_ALL;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen struct mailbox_list_iterate_context *iter;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen const struct mailbox_info *info;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen int ret = 0;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen iter = mailbox_list_iter_init_namespaces(user->namespaces, ctx->args,
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen ns_mask, iter_flags);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen while ((info = mailbox_list_iter_next(iter)) != NULL) {
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen if ((info->flags & (MAILBOX_NOSELECT |
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen MAILBOX_NONEXISTENT)) == 0) T_BEGIN {
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen if (cmd_force_resync_box(ctx, info) < 0)
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen ret = -1;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen } T_END;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen }
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen if (mailbox_list_iter_deinit(&iter) < 0) {
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen i_error("Listing mailboxes failed: %s",
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen mailbox_list_get_last_error(user->namespaces->list, NULL));
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen doveadm_mail_failed_list(ctx, user->namespaces->list);
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen ret = -1;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen }
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen return ret;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen}
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainenstatic void
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainencmd_force_resync_init(struct doveadm_mail_cmd_context *_ctx ATTR_UNUSED,
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen const char *const args[])
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen{
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen if (args[0] == NULL)
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen doveadm_mail_help_name("force-resync");
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen}
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainenstatic struct doveadm_mail_cmd_context *cmd_force_resync_alloc(void)
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen{
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen struct doveadm_mail_cmd_context *ctx;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen ctx = doveadm_mail_cmd_alloc(struct doveadm_mail_cmd_context);
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen ctx->v.init = cmd_force_resync_init;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ctx->v.run = cmd_force_resync_run;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return ctx;
6fabfb7bbfd88d0c1de66981e52850f26067623bTimo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic int
6fabfb7bbfd88d0c1de66981e52850f26067623bTimo Sirainendoveadm_mail_next_user(struct doveadm_mail_cmd_context *ctx,
6fabfb7bbfd88d0c1de66981e52850f26067623bTimo Sirainen const struct mail_storage_service_input *input,
6fabfb7bbfd88d0c1de66981e52850f26067623bTimo Sirainen const char **error_r)
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const char *error, *ip;
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen int ret;
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen ip = net_ip2addr(&input->remote_ip);
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen if (ip[0] == '\0')
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen i_set_failure_prefix("doveadm(%s): ", input->username);
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen else
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen i_set_failure_prefix("doveadm(%s,%s): ", ip, input->username);
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen /* see if we want to execute this command via (another)
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen doveadm server */
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen ret = doveadm_mail_server_user(ctx, input, error_r);
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen if (ret != 0)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return ret;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
798cfe56c9871262770384da1239162b3800cce1Timo Sirainen ret = mail_storage_service_lookup(ctx->storage_service, input,
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen &ctx->cur_service_user, &error);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (ret <= 0) {
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen if (ret < 0) {
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen *error_r = t_strdup_printf("User lookup failed: %s",
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen error);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return ret;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (ctx->v.prerun != NULL) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (ctx->v.prerun(ctx, ctx->cur_service_user, error_r) < 0) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen mail_storage_service_user_free(&ctx->cur_service_user);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen return -1;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen }
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen }
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen ret = mail_storage_service_next(ctx->storage_service,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ctx->cur_service_user,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen &ctx->cur_mail_user);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen if (ret < 0) {
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen *error_r = "User init failed";
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen mail_storage_service_user_free(&ctx->cur_service_user);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen return ret;
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen }
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen
70c181da837ed85fc5b0426c010b65609bda5329Timo Sirainen if (ctx->cmd_input != NULL)
bd354c19cb93c07ade79477674328a54146ea332Timo Sirainen i_stream_seek(ctx->cmd_input, 0);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen if (ctx->v.run(ctx, ctx->cur_mail_user) < 0) {
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen i_assert(ctx->exit_code != 0);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen }
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen mail_user_unref(&ctx->cur_mail_user);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen mail_storage_service_user_free(&ctx->cur_service_user);
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen return 1;
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen}
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen
b42f37ae6f65ed986315b6885568d32115e589b1Timo Sirainenint doveadm_mail_single_user(struct doveadm_mail_cmd_context *ctx,
e9503210d3521a6833ed62dc332fc42ffb0e7a13Timo Sirainen const struct mail_storage_service_input *input,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const char **error_r)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen i_assert(input->username != NULL);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ctx->cur_client_ip = input->remote_ip;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ctx->cur_username = input->username;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ctx->storage_service_input = *input;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ctx->storage_service = mail_storage_service_init(master_service, NULL,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ctx->service_flags);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ctx->v.init(ctx, ctx->args);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (hook_doveadm_mail_init != NULL)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen hook_doveadm_mail_init(ctx);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return doveadm_mail_next_user(ctx, input, error_r);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic void sig_die(const siginfo_t *si, void *context ATTR_UNUSED)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen killed_signo = si->si_signo;
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen}
35136dd2baf8dc30e4e754294ed81ff48e8c1e64Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic void
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainendoveadm_mail_all_users(struct doveadm_mail_cmd_context *ctx, char *argv[],
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const char *wildcard_user)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen struct mail_storage_service_input input;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen unsigned int user_idx;
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainen const char *ip, *user, *error;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen int ret;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen ctx->service_flags |= MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen memset(&input, 0, sizeof(input));
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen input.service = "doveadm";
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ctx->storage_service_input = input;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ctx->storage_service = mail_storage_service_init(master_service, NULL,
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen ctx->service_flags);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen lib_signals_set_handler(SIGINT, 0, sig_die, NULL);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen lib_signals_set_handler(SIGTERM, 0, sig_die, NULL);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ctx->v.init(ctx, (const void *)argv);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen mail_storage_service_all_init(ctx->storage_service);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (hook_doveadm_mail_init != NULL)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen hook_doveadm_mail_init(ctx);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen user_idx = 0;
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen while ((ret = ctx->v.get_next_user(ctx, &user)) > 0) {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen if (wildcard_user != NULL) {
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen if (!wildcard_match_icase(user, wildcard_user))
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen continue;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen input.username = user;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ctx->cur_username = user;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen doveadm_print_sticky("username", user);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen T_BEGIN {
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen ret = doveadm_mail_next_user(ctx, &input, &error);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (ret < 0)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_error("%s", error);
2cfe9983ce7a6280636ee12beccc2e865111967bTimo Sirainen else if (ret == 0)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_info("User no longer exists, skipping");
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen } T_END;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (ret == -1)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen break;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (doveadm_verbose) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (++user_idx % 100 == 0) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen printf("\r%d", user_idx);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen fflush(stdout);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (killed_signo != 0) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_warning("Killed with signal %d", killed_signo);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ret = -1;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen break;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (doveadm_verbose)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen printf("\n");
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ip = net_ip2addr(&ctx->cur_client_ip);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (ip[0] == '\0')
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_set_failure_prefix("doveadm: ");
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen else
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_set_failure_prefix("doveadm(%s): ", ip);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (ret < 0) {
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_error("Failed to iterate through some users");
2526d52441ef368215ab6bf04fd0356d3b09d235Timo Sirainen ctx->exit_code = EX_TEMPFAIL;
2526d52441ef368215ab6bf04fd0356d3b09d235Timo Sirainen }
93fa87cf1a96c4f279ec4f5c311820313ba12c34Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic void
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainendoveadm_mail_cmd_init_noop(struct doveadm_mail_cmd_context *ctx ATTR_UNUSED,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const char *const args[] ATTR_UNUSED)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenstatic int
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainendoveadm_mail_cmd_get_next_user(struct doveadm_mail_cmd_context *ctx,
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen const char **username_r)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (ctx->users_list_input == NULL)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return mail_storage_service_all_next(ctx->storage_service, username_r);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen *username_r = i_stream_read_next_line(ctx->users_list_input);
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (ctx->users_list_input->stream_errno != 0) {
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen i_error("read(%s) failed: %s",
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen i_stream_get_name(ctx->users_list_input),
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen i_stream_get_error(ctx->users_list_input));
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return -1;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen }
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen return *username_r != NULL ? 1 : 0;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen}
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainenstatic void
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainendoveadm_mail_cmd_deinit_noop(struct doveadm_mail_cmd_context *ctx ATTR_UNUSED)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen{
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen}
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainenstruct doveadm_mail_cmd_context *
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainendoveadm_mail_cmd_init(const struct doveadm_mail_cmd *cmd,
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen const struct doveadm_settings *set)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen{
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen struct doveadm_mail_cmd_context *ctx;
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen ctx = cmd->alloc();
82f53ea81671bcc7b9bf24a34b04a4ba2752efd3Timo Sirainen ctx->set = set;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen ctx->cmd = cmd;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (ctx->v.init == NULL)
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen ctx->v.init = doveadm_mail_cmd_init_noop;
2e29e4797a48d78d669821722bdb54fd0a1d3b94Timo Sirainen if (ctx->v.get_next_user == NULL)
ctx->v.get_next_user = doveadm_mail_cmd_get_next_user;
if (ctx->v.deinit == NULL)
ctx->v.deinit = doveadm_mail_cmd_deinit_noop;
p_array_init(&ctx->module_contexts, ctx->pool, 5);
return ctx;
}
static void
doveadm_mail_cmd(const struct doveadm_mail_cmd *cmd, int argc, char *argv[])
{
struct doveadm_mail_cmd_context *ctx;
const char *getopt_args, *wildcard_user, *error;
int ret, c;
ctx = doveadm_mail_cmd_init(cmd, doveadm_settings);
ctx->full_args = (const void *)(argv + 1);
ctx->service_flags |= MAIL_STORAGE_SERVICE_FLAG_NO_LOG_INIT;
if (doveadm_debug)
ctx->service_flags |= MAIL_STORAGE_SERVICE_FLAG_DEBUG;
getopt_args = "AF:S:u:";
/* keep context's getopt_args first in case it contains '+' */
if (ctx->getopt_args != NULL)
getopt_args = t_strconcat(ctx->getopt_args, getopt_args, NULL);
i_assert(master_getopt_str_is_valid(getopt_args));
ctx->cur_username = getenv("USER");
wildcard_user = NULL;
while ((c = getopt(argc, argv, getopt_args)) > 0) {
switch (c) {
case 'A':
ctx->iterate_all_users = TRUE;
break;
case 'S':
doveadm_settings->doveadm_socket_path = optarg;
if (doveadm_settings->doveadm_worker_count == 0)
doveadm_settings->doveadm_worker_count = 1;
break;
case 'u':
ctx->service_flags |=
MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP;
ctx->cur_username = optarg;
if (strchr(ctx->cur_username, '*') != NULL ||
strchr(ctx->cur_username, '?') != NULL) {
wildcard_user = ctx->cur_username;
ctx->cur_username = NULL;
}
break;
case 'F':
ctx->service_flags |=
MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP;
wildcard_user = "*";
ctx->users_list_input =
i_stream_create_file(optarg, 1024);
break;
default:
if (ctx->v.parse_arg == NULL ||
!ctx->v.parse_arg(ctx, c))
doveadm_mail_help(cmd);
}
}
argv += optind;
if (argv[0] != NULL && cmd->usage_args == NULL) {
i_fatal_status(EX_USAGE, "doveadm %s: Unknown parameter: %s",
cmd->name, argv[0]);
}
ctx->args = (const void *)argv;
if (ctx->v.preinit != NULL)
ctx->v.preinit(ctx);
ctx->iterate_single_user =
!ctx->iterate_all_users && wildcard_user == NULL;
if (doveadm_print_is_initialized() && !ctx->iterate_single_user) {
doveadm_print_header("username", "Username",
DOVEADM_PRINT_HEADER_FLAG_STICKY |
DOVEADM_PRINT_HEADER_FLAG_HIDE_TITLE);
}
if (ctx->iterate_single_user) {
struct mail_storage_service_input input;
if (ctx->cur_username == NULL)
i_fatal_status(EX_USAGE, "USER environment is missing and -u option not used");
memset(&input, 0, sizeof(input));
input.service = "doveadm";
input.username = ctx->cur_username;
ret = doveadm_mail_single_user(ctx, &input, &error);
if (ret < 0)
i_fatal("%s", error);
else if (ret == 0)
i_fatal_status(EX_NOUSER, "User doesn't exist");
} else {
ctx->service_flags |= MAIL_STORAGE_SERVICE_FLAG_TEMP_PRIV_DROP;
doveadm_mail_all_users(ctx, argv, wildcard_user);
}
if (ctx->search_args != NULL)
mail_search_args_unref(&ctx->search_args);
doveadm_mail_server_flush();
ctx->v.deinit(ctx);
doveadm_print_flush();
/* service deinit unloads mail plugins, so do it late */
mail_storage_service_deinit(&ctx->storage_service);
if (ctx->users_list_input != NULL)
i_stream_unref(&ctx->users_list_input);
if (ctx->cmd_input != NULL)
i_stream_unref(&ctx->cmd_input);
if (ctx->exit_code != 0)
doveadm_exit_code = ctx->exit_code;
pool_unref(&ctx->pool);
}
static bool
doveadm_mail_cmd_try_find_multi_word(const struct doveadm_mail_cmd *cmd,
const char *cmdname, int *argc,
const char *const **argv)
{
unsigned int len;
if (*argc < 2)
return FALSE;
*argc -= 1;
*argv += 1;
len = strlen((*argv)[0]);
if (strncmp(cmdname, (*argv)[0], len) != 0)
return FALSE;
if (cmdname[len] == ' ') {
/* more args */
return doveadm_mail_cmd_try_find_multi_word(cmd, cmdname + len + 1,
argc, argv);
}
if (cmdname[len] != '\0')
return FALSE;
/* match */
return TRUE;
}
const struct doveadm_mail_cmd *
doveadm_mail_cmd_find_from_argv(const char *cmd_name, int *argc,
const char *const **argv)
{
const struct doveadm_mail_cmd *cmd;
unsigned int cmd_name_len;
const char *const *orig_argv;
int orig_argc;
i_assert(*argc > 0);
cmd_name_len = strlen(cmd_name);
array_foreach(&doveadm_mail_cmds, cmd) {
if (strcmp(cmd->name, cmd_name) == 0)
return cmd;
/* see if it matches a multi-word command */
if (strncmp(cmd->name, cmd_name, cmd_name_len) == 0 &&
cmd->name[cmd_name_len] == ' ') {
const char *subcmd = cmd->name + cmd_name_len + 1;
orig_argc = *argc;
orig_argv = *argv;
if (doveadm_mail_cmd_try_find_multi_word(cmd, subcmd,
argc, argv))
return cmd;
*argc = orig_argc;
*argv = orig_argv;
}
}
return NULL;
}
bool doveadm_mail_try_run(const char *cmd_name, int argc, char *argv[])
{
const struct doveadm_mail_cmd *cmd;
cmd = doveadm_mail_cmd_find_from_argv(cmd_name, &argc, (void *)&argv);
if (cmd == NULL)
return FALSE;
doveadm_mail_cmd(cmd, argc, argv);
return TRUE;
}
void doveadm_mail_register_cmd(const struct doveadm_mail_cmd *cmd)
{
/* for now we'll just assume that cmd will be permanently in memory */
array_append(&doveadm_mail_cmds, cmd, 1);
}
const struct doveadm_mail_cmd *doveadm_mail_cmd_find(const char *cmd_name)
{
const struct doveadm_mail_cmd *cmd;
array_foreach(&doveadm_mail_cmds, cmd) {
if (strcmp(cmd->name, cmd_name) == 0)
return cmd;
}
return NULL;
}
void doveadm_mail_usage(string_t *out)
{
const struct doveadm_mail_cmd *cmd;
array_foreach(&doveadm_mail_cmds, cmd) {
if (cmd->usage_args == &doveadm_mail_cmd_hide)
continue;
str_printfa(out, "%s\t[-u <user>|-A] [-S <socket_path>]",
cmd->name);
if (cmd->usage_args != NULL)
str_printfa(out, " %s", cmd->usage_args);
str_append_c(out, '\n');
}
}
void doveadm_mail_help(const struct doveadm_mail_cmd *cmd)
{
fprintf(stderr, "doveadm %s [-u <user>|-A] [-S <socket_path>] %s\n",
cmd->name, cmd->usage_args == NULL ? "" : cmd->usage_args);
exit(EX_USAGE);
}
void doveadm_mail_try_help_name(const char *cmd_name)
{
const struct doveadm_mail_cmd *cmd;
cmd = doveadm_mail_cmd_find(cmd_name);
if (cmd != NULL)
doveadm_mail_help(cmd);
}
bool doveadm_mail_has_subcommands(const char *cmd_name)
{
const struct doveadm_mail_cmd *cmd;
unsigned int len = strlen(cmd_name);
array_foreach(&doveadm_mail_cmds, cmd) {
if (strncmp(cmd->name, cmd_name, len) == 0 &&
cmd->name[len] == ' ')
return TRUE;
}
return FALSE;
}
void doveadm_mail_help_name(const char *cmd_name)
{
doveadm_mail_try_help_name(cmd_name);
i_fatal("Missing help for command %s", cmd_name);
}
static struct doveadm_mail_cmd cmd_force_resync = {
cmd_force_resync_alloc, "force-resync", "<mailbox mask>"
};
static struct doveadm_mail_cmd cmd_purge = {
cmd_purge_alloc, "purge", NULL
};
static struct doveadm_mail_cmd *mail_commands[] = {
&cmd_force_resync,
&cmd_purge,
&cmd_expunge,
&cmd_save,
&cmd_search,
&cmd_fetch,
&cmd_flags_add,
&cmd_flags_remove,
&cmd_flags_replace,
&cmd_import,
&cmd_index,
&cmd_altmove,
&cmd_copy,
&cmd_deduplicate,
&cmd_move,
&cmd_mailbox_list,
&cmd_mailbox_create,
&cmd_mailbox_delete,
&cmd_mailbox_rename,
&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,
&cmd_dsync_server
};
void doveadm_mail_init(void)
{
struct module_dir_load_settings mod_set;
unsigned int i;
i_array_init(&doveadm_mail_cmds, 32);
for (i = 0; i < N_ELEMENTS(mail_commands); i++)
doveadm_mail_register_cmd(mail_commands[i]);
memset(&mod_set, 0, sizeof(mod_set));
mod_set.abi_version = DOVECOT_ABI_VERSION;
mod_set.require_init_funcs = TRUE;
mod_set.debug = doveadm_debug;
mod_set.binary_name = "doveadm";
/* load all configured mail plugins */
mail_storage_service_modules =
module_dir_load_missing(mail_storage_service_modules,
doveadm_settings->mail_plugin_dir,
doveadm_settings->mail_plugins,
&mod_set);
}
void doveadm_mail_deinit(void)
{
mail_storage_hooks_deinit();
array_free(&doveadm_mail_cmds);
}