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