doveadm-mail-expunge.c revision 23878bd03d1de531e3261a25598beec621351910
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen/* Copyright (c) 2010 Dovecot authors, see the included COPYING file */
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen#include "lib.h"
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen#include "array.h"
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen#include "mail-index.h"
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen#include "mail-storage.h"
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen#include "mail-search.h"
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen#include "doveadm-mail-list-iter.h"
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen#include "doveadm-mail-iter.h"
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen#include "doveadm-mail.h"
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainenstruct expunge_cmd_context {
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen struct doveadm_mail_cmd_context ctx;
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen struct mail_search_args *search_args;
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen};
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainenstatic int
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainencmd_expunge_box(const struct mailbox_info *info,
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen struct mail_search_args *search_args)
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen{
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen struct doveadm_mail_iter *iter;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen struct mailbox_transaction_context *trans;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen struct mail *mail;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen if (doveadm_mail_iter_init(info, search_args, &trans, &iter) < 0)
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen return -1;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen mail = mail_alloc(trans, 0, NULL);
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen while (doveadm_mail_iter_next(iter, mail)) {
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen if (doveadm_debug) {
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen i_debug("expunge: box=%s uid=%u",
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen info->name, mail->uid);
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen }
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen mail_expunge(mail);
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen }
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen mail_free(&mail);
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen return doveadm_mail_iter_deinit(&iter);
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen}
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainenstatic bool
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainenexpunge_search_args_is_mailbox_ok(struct mail_search_arg *args);
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainenstatic bool
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainenexpunge_search_args_is_mailbox_or_ok(struct mail_search_arg *args)
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen{
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen struct mail_search_arg *arg;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen for (arg = args; arg != NULL; arg = arg->next) {
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen switch (arg->type) {
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen case SEARCH_OR:
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen if (!expunge_search_args_is_mailbox_or_ok(arg->value.subargs))
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen return FALSE;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen break;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen case SEARCH_SUB:
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen case SEARCH_INTHREAD:
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen if (!expunge_search_args_is_mailbox_ok(arg->value.subargs))
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen return FALSE;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen break;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen case SEARCH_MAILBOX:
f77da594de6318312a7f31589c9e4c38e2b74c73Timo Sirainen case SEARCH_MAILBOX_GUID:
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen case SEARCH_MAILBOX_GLOB:
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen break;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen default:
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen return FALSE;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen }
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen }
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen return TRUE;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen}
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainenstatic bool
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainenexpunge_search_args_is_mailbox_ok(struct mail_search_arg *args)
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen{
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen struct mail_search_arg *arg;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen bool have_or = FALSE;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen /* a) we find one mailbox here in the SUB block */
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen for (arg = args; arg != NULL; arg = arg->next) {
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen switch (arg->type) {
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen case SEARCH_MAILBOX:
f77da594de6318312a7f31589c9e4c38e2b74c73Timo Sirainen case SEARCH_MAILBOX_GUID:
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen case SEARCH_MAILBOX_GLOB:
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen return TRUE;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen case SEARCH_OR:
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen have_or = TRUE;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen break;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen case SEARCH_SUB:
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen case SEARCH_INTHREAD:
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen if (expunge_search_args_is_mailbox_ok(arg->value.subargs))
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen return TRUE;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen break;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen default:
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen break;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen }
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen }
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen /* b) there is at least one OR block, and all of the ORs must have
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen mailbox */
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen if (!have_or)
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen return FALSE;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen for (arg = args; arg != NULL; arg = arg->next) {
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen if (arg->type == SEARCH_OR &&
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen !expunge_search_args_is_mailbox_or_ok(arg->value.subargs))
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen return FALSE;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen }
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen return TRUE;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen}
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainenstatic bool
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainenexpunge_search_args_is_msgset_ok(struct mail_search_arg *args);
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainenstatic bool
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainenexpunge_search_args_is_msgset_or_ok(struct mail_search_arg *args)
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen{
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen struct mail_search_arg *arg;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen /* we're done if all OR branches contain something else besides
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen MAILBOXes */
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen for (arg = args; arg != NULL; arg = arg->next) {
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen switch (arg->type) {
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen case SEARCH_MAILBOX:
f77da594de6318312a7f31589c9e4c38e2b74c73Timo Sirainen case SEARCH_MAILBOX_GUID:
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen case SEARCH_MAILBOX_GLOB:
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen return FALSE;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen case SEARCH_OR:
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen if (!expunge_search_args_is_msgset_or_ok(arg->value.subargs))
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen return FALSE;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen break;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen case SEARCH_SUB:
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen if (!expunge_search_args_is_msgset_ok(arg->value.subargs))
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen return FALSE;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen break;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen default:
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen break;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen }
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen }
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen return TRUE;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen}
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainenstatic bool
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainenexpunge_search_args_is_msgset_ok(struct mail_search_arg *args)
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen{
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen struct mail_search_arg *arg;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen /* all args can't be just MAILBOXes */
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen for (arg = args; arg != NULL; arg = arg->next) {
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen switch (arg->type) {
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen case SEARCH_MAILBOX:
f77da594de6318312a7f31589c9e4c38e2b74c73Timo Sirainen case SEARCH_MAILBOX_GUID:
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen case SEARCH_MAILBOX_GLOB:
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen break;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen case SEARCH_OR:
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen /* if each OR branch has something else than just
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen MAILBOXes, we're ok */
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen if (expunge_search_args_is_msgset_or_ok(arg->value.subargs))
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen return TRUE;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen break;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen case SEARCH_SUB:
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen if (expunge_search_args_is_msgset_ok(arg->value.subargs))
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen return TRUE;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen break;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen default:
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen return TRUE;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen }
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen }
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen return FALSE;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen}
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainenstatic void
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainencmd_expunge_run(struct doveadm_mail_cmd_context *_ctx, struct mail_user *user)
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen{
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen struct expunge_cmd_context *ctx = (struct expunge_cmd_context *)_ctx;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen const enum mailbox_list_iter_flags iter_flags =
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen MAILBOX_LIST_ITER_RAW_LIST |
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen MAILBOX_LIST_ITER_VIRTUAL_NAMES |
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen MAILBOX_LIST_ITER_NO_AUTO_INBOX |
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen MAILBOX_LIST_ITER_RETURN_NO_FLAGS;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen struct doveadm_mail_list_iter *iter;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen const struct mailbox_info *info;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen if (!expunge_search_args_is_mailbox_ok(ctx->search_args->args)) {
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen i_fatal("expunge: To avoid accidents, search query "
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen "must contain MAILBOX in all search branches");
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen }
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen if (!expunge_search_args_is_msgset_ok(ctx->search_args->args)) {
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen i_fatal("expunge: To avoid accidents, each branch in "
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen "search query must contain something else "
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen "besides MAILBOX");
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen }
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen iter = doveadm_mail_list_iter_init(user, ctx->search_args, iter_flags);
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen while ((info = doveadm_mail_list_iter_next(iter)) != NULL) T_BEGIN {
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen (void)cmd_expunge_box(info, ctx->search_args);
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen } T_END;
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen doveadm_mail_list_iter_deinit(&iter);
4eecd3e2aadb20768a60f701e329b4345d04430cTimo Sirainen}
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen
23878bd03d1de531e3261a25598beec621351910Timo Sirainenstatic void cmd_expunge_init(struct doveadm_mail_cmd_context *_ctx,
23878bd03d1de531e3261a25598beec621351910Timo Sirainen const char *const args[])
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen{
23878bd03d1de531e3261a25598beec621351910Timo Sirainen struct expunge_cmd_context *ctx = (struct expunge_cmd_context *)_ctx;
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen if (args[0] == NULL)
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen doveadm_mail_help_name("expunge");
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen ctx->search_args = doveadm_mail_build_search_args(args);
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen mail_search_args_simplify(ctx->search_args);
23878bd03d1de531e3261a25598beec621351910Timo Sirainen}
23878bd03d1de531e3261a25598beec621351910Timo Sirainen
23878bd03d1de531e3261a25598beec621351910Timo Sirainenstatic struct doveadm_mail_cmd_context *cmd_expunge_alloc(void)
23878bd03d1de531e3261a25598beec621351910Timo Sirainen{
23878bd03d1de531e3261a25598beec621351910Timo Sirainen struct expunge_cmd_context *ctx;
23878bd03d1de531e3261a25598beec621351910Timo Sirainen
23878bd03d1de531e3261a25598beec621351910Timo Sirainen ctx = doveadm_mail_cmd_alloc(struct expunge_cmd_context);
23878bd03d1de531e3261a25598beec621351910Timo Sirainen ctx->ctx.init = cmd_expunge_init;
23878bd03d1de531e3261a25598beec621351910Timo Sirainen ctx->ctx.run = cmd_expunge_run;
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen return &ctx->ctx;
cf63dc8723b971cc80638fccbf494d961cbafc7fTimo Sirainen}
23878bd03d1de531e3261a25598beec621351910Timo Sirainen
23878bd03d1de531e3261a25598beec621351910Timo Sirainenstruct doveadm_mail_cmd cmd_expunge = {
23878bd03d1de531e3261a25598beec621351910Timo Sirainen cmd_expunge_alloc, "expunge", "<search query>"
23878bd03d1de531e3261a25598beec621351910Timo Sirainen};