diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:51:24 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:51:24 +0000 |
commit | f7548d6d28c313cf80e6f3ef89aed16a19815df1 (patch) | |
tree | a3f6f2a3f247293bee59ecd28e8cd8ceb6ca064a /src/doveadm/doveadm-mail-mailbox-cache.c | |
parent | Initial commit. (diff) | |
download | dovecot-f7548d6d28c313cf80e6f3ef89aed16a19815df1.tar.xz dovecot-f7548d6d28c313cf80e6f3ef89aed16a19815df1.zip |
Adding upstream version 1:2.3.19.1+dfsg1.upstream/1%2.3.19.1+dfsg1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/doveadm/doveadm-mail-mailbox-cache.c')
-rw-r--r-- | src/doveadm/doveadm-mail-mailbox-cache.c | 440 |
1 files changed, 440 insertions, 0 deletions
diff --git a/src/doveadm/doveadm-mail-mailbox-cache.c b/src/doveadm/doveadm-mail-mailbox-cache.c new file mode 100644 index 0000000..718fca4 --- /dev/null +++ b/src/doveadm/doveadm-mail-mailbox-cache.c @@ -0,0 +1,440 @@ +/* Copyright (c) 2018 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "str.h" +#include "time-util.h" +#include "mail-index-private.h" +#include "mail-cache-private.h" +#include "mail-namespace.h" +#include "mail-storage-private.h" +#include "doveadm-print.h" +#include "doveadm-mail-iter.h" +#include "doveadm-mailbox-list-iter.h" +#include "doveadm-mail.h" + +struct mailbox_cache_cmd_context { + struct doveadm_mail_cmd_context ctx; + + const char *const *boxes; + const char *const *fields; + uint64_t last_used; + enum mail_cache_decision_type decision; + bool all_fields; + bool set_decision; + bool set_last_used; + bool remove; +}; + +static int cmd_mailbox_cache_open_box(struct doveadm_mail_cmd_context *ctx, + struct mail_user *user, + const char *boxname, + struct mailbox **box_r) +{ + struct mailbox *box = doveadm_mailbox_find(user, boxname); + + if (mailbox_open(box) < 0 || mailbox_sync(box, 0) < 0) { + i_error("Cannot open mailbox %s: %s", + mailbox_get_vname(box), + mailbox_get_last_internal_error(box, NULL)); + doveadm_mail_failed_mailbox(ctx, box); + mailbox_free(&box); + return -1; + } + + *box_r = box; + + return 0; +} + +static void cmd_mailbox_cache_decision_init(struct doveadm_mail_cmd_context *_ctx, + const char *const args[]) +{ + struct mailbox_cache_cmd_context *ctx = + container_of(_ctx, struct mailbox_cache_cmd_context, ctx); + const char *fields; + + doveadm_print_header("mailbox", "mailbox", DOVEADM_PRINT_HEADER_FLAG_STICKY); + doveadm_print_header_simple("field"); + doveadm_print_header_simple("decision"); + doveadm_print_header_simple("last-used"); + + if (!ctx->all_fields && + !doveadm_cmd_param_str(_ctx->cctx, "fieldstr", &fields)) { + i_fatal("Missing fields parameter"); + } else if (!ctx->all_fields) { + ctx->fields = t_strsplit_spaces(fields, ", "); + } + + ctx->boxes = args; +} + +static bool +cmd_mailbox_cache_parse_arg(struct doveadm_mail_cmd_context *_ctx, int c) +{ + struct mailbox_cache_cmd_context *ctx = + container_of(_ctx, struct mailbox_cache_cmd_context, ctx); + + switch(c) { + case 'a': + ctx->all_fields = TRUE; + return TRUE; + /* this is handled in doveadm-mail as 'fieldstr' field */ + case 'f': + return TRUE; + case 'l': + if (str_to_uint64(optarg, &ctx->last_used) < 0) { + i_error("Invalid last-used '%s': not a number", optarg); + return FALSE; + } + ctx->set_last_used = TRUE; + return TRUE; + case 'd': + if (ctx->set_decision) { + i_error("Only one decision flag allowed"); + return FALSE; + } + if (strcmp(optarg, "no") == 0) { + ctx->decision = MAIL_CACHE_DECISION_NO; + } else if (strcmp(optarg, "temp") == 0) { + ctx->decision = MAIL_CACHE_DECISION_TEMP; + } else if (strcmp(optarg, "yes") == 0) { + ctx->decision = MAIL_CACHE_DECISION_YES; + } else { + i_error("Invalid decision '%s': " \ + "must be one of yes, temp, no", + optarg); + return FALSE; + } + ctx->set_decision = TRUE; + return TRUE; + } + return FALSE; +} + +static const char * +cmd_mailbox_cache_decision_to_str(enum mail_cache_decision_type decision) +{ + string_t *ret = t_str_new(10); + switch((decision & ENUM_NEGATE(MAIL_CACHE_DECISION_FORCED))) { + case MAIL_CACHE_DECISION_NO: + str_append(ret, "no"); + break; + case MAIL_CACHE_DECISION_TEMP: + str_append(ret, "temp"); + break; + case MAIL_CACHE_DECISION_YES: + str_append(ret, "yes"); + break; + } + return str_c(ret); +} + +static void +cmd_mailbox_cache_decision_process_field(struct mailbox_cache_cmd_context *ctx, + struct mail_cache_field_private *field) +{ + if (ctx->set_decision) { + field->field.decision = ctx->decision; + field->decision_dirty = TRUE; + } + + if (ctx->set_last_used) { + field->field.last_used = (time_t)ctx->last_used; + field->decision_dirty = TRUE; + } + + doveadm_print(cmd_mailbox_cache_decision_to_str(field->field.decision)); + doveadm_print(t_strflocaltime("%F %T %Z", field->field.last_used)); +} + +static void +cmd_mailbox_cache_decision_run_per_field(struct mailbox_cache_cmd_context *ctx, + struct mail_cache *cache) +{ + const char *const *field_name; + for(field_name = ctx->fields; *field_name != NULL; field_name++) { + doveadm_print(*field_name); + /* see if the field exists */ + unsigned int idx = mail_cache_register_lookup(cache, + *field_name); + if (idx == UINT_MAX) { + doveadm_print("<not found>"); + doveadm_print(""); + continue; + } + + cmd_mailbox_cache_decision_process_field(ctx, &cache->fields[idx]); + } +} + +static void +cmd_mailbox_cache_decision_run_all_fields(struct mailbox_cache_cmd_context *ctx, + struct mail_cache *cache) +{ + /* get all fields */ + for(unsigned int i = 0; i < cache->fields_count; i++) { + doveadm_print(cache->fields[i].field.name); + cmd_mailbox_cache_decision_process_field(ctx, &cache->fields[i]); + } +} + +static int cmd_mailbox_cache_decision_run_box(struct mailbox_cache_cmd_context *ctx, + struct mailbox *box) +{ + struct mailbox_transaction_context *t = + mailbox_transaction_begin(box, ctx->ctx.transaction_flags, + "mailbox cache decision"); + struct mail_cache *cache = t->box->cache; + struct mail_cache_view *view; + + if (mail_cache_open_and_verify(cache) < 0 || + MAIL_CACHE_IS_UNUSABLE(cache)) { + mailbox_transaction_rollback(&t); + i_error("Cache is unusable"); + ctx->ctx.exit_code = EX_TEMPFAIL; + return -1; + } + + view = mail_cache_view_open(cache, t->box->view); + + if (ctx->all_fields) + cmd_mailbox_cache_decision_run_all_fields(ctx, cache); + else + cmd_mailbox_cache_decision_run_per_field(ctx, cache); + + /* update headers */ + if (ctx->set_decision || ctx->set_last_used) + mail_cache_header_fields_update(cache); + + mail_cache_view_close(&view); + + if (mailbox_transaction_commit(&t) < 0) { + i_error("mailbox_transaction_commit() failed: %s", + mailbox_get_last_internal_error(box, NULL)); + doveadm_mail_failed_mailbox(&ctx->ctx, box); + return -1; + } + return 0; +} + +static int cmd_mailbox_cache_decision_run(struct doveadm_mail_cmd_context *_ctx, + struct mail_user *user) +{ + struct mailbox_cache_cmd_context *ctx = + container_of(_ctx, struct mailbox_cache_cmd_context, ctx); + const char *const *boxname; + int ret = 0; + + if (_ctx->exit_code != 0) + return -1; + + for(boxname = ctx->boxes; ret == 0 && *boxname != NULL; boxname++) { + struct mailbox *box; + if ((ret = cmd_mailbox_cache_open_box(_ctx, user, *boxname, &box)) < 0) + break; + doveadm_print_sticky("mailbox", mailbox_get_vname(box)); + ret = cmd_mailbox_cache_decision_run_box(ctx, box); + mailbox_free(&box); + } + + return ret; +} + +static int cmd_mailbox_cache_remove_box(struct mailbox_cache_cmd_context *ctx, + const struct mailbox_info *info) +{ + struct doveadm_mail_iter *iter; + struct mailbox *box; + struct mail *mail; + void *empty = NULL; + int ret = 0, count = 0; + + if (doveadm_mail_iter_init(&ctx->ctx, info, ctx->ctx.search_args, + 0, NULL, 0, &iter) < 0) + return -1; + + box = doveadm_mail_iter_get_mailbox(iter); + + struct mail_index_transaction *t = + mail_index_transaction_begin(box->view, MAIL_INDEX_TRANSACTION_FLAG_EXTERNAL); + struct mail_cache_view *view = + mail_cache_view_open(box->cache, box->view); + + while (doveadm_mail_iter_next(iter, &mail)) { + count++; + doveadm_print(mailbox_get_vname(box)); + doveadm_print(dec2str(mail->uid)); + /* drop cache pointer */ + mail_index_update_ext(t, mail->seq, view->cache->ext_id, &empty, NULL); + doveadm_print("ok"); + } + + if (mail_index_transaction_commit(&t) < 0) { + i_error("mail_index_transaction_commit() failed: %s", + mailbox_get_last_internal_error(box, NULL)); + doveadm_mail_failed_mailbox(&ctx->ctx, box); + ret = -1; + } else { + mail_cache_expunge_count(view->cache, count); + } + + mail_cache_view_close(&view); + + if (doveadm_mail_iter_deinit(&iter) < 0) + ret = -1; + + return ret; +} + +static int cmd_mailbox_cache_remove_run(struct doveadm_mail_cmd_context *_ctx, + struct mail_user *user) +{ + struct mailbox_cache_cmd_context *ctx = + container_of(_ctx, struct mailbox_cache_cmd_context, ctx); + const enum mailbox_list_iter_flags iter_flags = + MAILBOX_LIST_ITER_NO_AUTO_BOXES | + MAILBOX_LIST_ITER_RETURN_NO_FLAGS; + struct doveadm_mailbox_list_iter *iter; + const struct mailbox_info *info; + int ret = 0; + + iter = doveadm_mailbox_list_iter_init(&ctx->ctx, user, ctx->ctx.search_args, + iter_flags); + while ((info = doveadm_mailbox_list_iter_next(iter)) != NULL) T_BEGIN { + if (cmd_mailbox_cache_remove_box(ctx, info) < 0) + ret = -1; + } T_END; + if (doveadm_mailbox_list_iter_deinit(&iter) < 0) + ret = -1; + return ret; +} + +static void cmd_mailbox_cache_remove_init(struct doveadm_mail_cmd_context *_ctx, + const char *const args[]) +{ + struct mailbox_cache_cmd_context *ctx = + container_of(_ctx, struct mailbox_cache_cmd_context, ctx); + + if (args[0] == NULL) + doveadm_mail_help_name("mailbox cache remove"); + + doveadm_print_header_simple("mailbox"); + doveadm_print_header_simple("uid"); + doveadm_print_header_simple("result"); + + ctx->ctx.search_args = doveadm_mail_build_search_args(args); +} + +static int cmd_mailbox_cache_purge_run_box(struct mailbox_cache_cmd_context *ctx, + struct mailbox *box) +{ + if (mail_cache_purge(box->cache, (uint32_t)-1, + "doveadm mailbox cache purge") < 0) { + mailbox_set_index_error(box); + doveadm_mail_failed_mailbox(&ctx->ctx, box); + return -1; + } + return 0; +} + +static int cmd_mailbox_cache_purge_run(struct doveadm_mail_cmd_context *_ctx, + struct mail_user *user) +{ + struct mailbox_cache_cmd_context *ctx = + container_of(_ctx, struct mailbox_cache_cmd_context, ctx); + const char *const *boxname; + int ret = 0; + + if (_ctx->exit_code != 0) + return -1; + + for(boxname = ctx->boxes; ret == 0 && *boxname != NULL; boxname++) { + struct mailbox *box; + if ((ret = cmd_mailbox_cache_open_box(_ctx, user, *boxname, &box)) < 0) + break; + ret = cmd_mailbox_cache_purge_run_box(ctx, box); + mailbox_free(&box); + } + + return ret; +} + +static void cmd_mailbox_cache_purge_init(struct doveadm_mail_cmd_context *_ctx, + const char *const args[]) +{ + struct mailbox_cache_cmd_context *ctx = + container_of(_ctx, struct mailbox_cache_cmd_context, ctx); + + ctx->boxes = args; +} + +static struct doveadm_mail_cmd_context *cmd_mailbox_cache_decision_alloc(void) +{ + struct mailbox_cache_cmd_context *ctx = + doveadm_mail_cmd_alloc(struct mailbox_cache_cmd_context); + ctx->ctx.v.init = cmd_mailbox_cache_decision_init; + ctx->ctx.v.parse_arg = cmd_mailbox_cache_parse_arg; + ctx->ctx.v.run = cmd_mailbox_cache_decision_run; + ctx->ctx.getopt_args = "al:f:d:"; + doveadm_print_init(DOVEADM_PRINT_TYPE_TABLE); + return &ctx->ctx; +} + +static struct doveadm_mail_cmd_context *cmd_mailbox_cache_remove_alloc(void) +{ + struct mailbox_cache_cmd_context *ctx = + doveadm_mail_cmd_alloc(struct mailbox_cache_cmd_context); + ctx->ctx.v.init = cmd_mailbox_cache_remove_init; + ctx->ctx.v.parse_arg = cmd_mailbox_cache_parse_arg; + ctx->ctx.v.run = cmd_mailbox_cache_remove_run; + ctx->ctx.getopt_args = ""; + doveadm_print_init(DOVEADM_PRINT_TYPE_TABLE); + return &ctx->ctx; +} + +static struct doveadm_mail_cmd_context *cmd_mailbox_cache_purge_alloc(void) +{ + struct mailbox_cache_cmd_context *ctx = + doveadm_mail_cmd_alloc(struct mailbox_cache_cmd_context); + ctx->ctx.v.init = cmd_mailbox_cache_purge_init; + ctx->ctx.v.run = cmd_mailbox_cache_purge_run; + ctx->ctx.getopt_args = ""; + doveadm_print_init(DOVEADM_PRINT_TYPE_TABLE); + return &ctx->ctx; +} + +struct doveadm_cmd_ver2 doveadm_cmd_mailbox_cache_decision = { + .name = "mailbox cache decision", + .mail_cmd = cmd_mailbox_cache_decision_alloc, + .usage = DOVEADM_CMD_MAIL_USAGE_PREFIX"--all --fields <fields> " \ + "--last-used <timestamp> --decision <decision> " \ + "<mailbox> [<mailbox> ... ]", +DOVEADM_CMD_PARAMS_START +DOVEADM_CMD_MAIL_COMMON +DOVEADM_CMD_PARAM('a', "all", CMD_PARAM_BOOL, 0) +DOVEADM_CMD_PARAM('f', "fieldstr", CMD_PARAM_STR, 0) +DOVEADM_CMD_PARAM('l', "last-used", CMD_PARAM_INT64, 0) +DOVEADM_CMD_PARAM('d', "decision", CMD_PARAM_STR, 0) +DOVEADM_CMD_PARAM('\0', "mailbox", CMD_PARAM_ARRAY, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAMS_END +}; + +struct doveadm_cmd_ver2 doveadm_cmd_mailbox_cache_remove = { + .name = "mailbox cache remove", + .mail_cmd = cmd_mailbox_cache_remove_alloc, + .usage = DOVEADM_CMD_MAIL_USAGE_PREFIX"<search string>", +DOVEADM_CMD_PARAMS_START +DOVEADM_CMD_MAIL_COMMON +DOVEADM_CMD_PARAM('\0', "query", CMD_PARAM_ARRAY, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAMS_END +}; + +struct doveadm_cmd_ver2 doveadm_cmd_mailbox_cache_purge = { + .name = "mailbox cache purge", + .mail_cmd = cmd_mailbox_cache_purge_alloc, + .usage = DOVEADM_CMD_MAIL_USAGE_PREFIX"<mailbox> [...]", +DOVEADM_CMD_PARAMS_START +DOVEADM_CMD_MAIL_COMMON +DOVEADM_CMD_PARAM('\0', "mailbox", CMD_PARAM_ARRAY, CMD_PARAM_FLAG_POSITIONAL) +DOVEADM_CMD_PARAMS_END +}; |