# %{fetch_hdr_bytes} - Number of bytes with mail header data sent to client
# %{fetch_body_count} - Number of mails with mail body data sent to client
# %{fetch_body_bytes} - Number of bytes with mail body data sent to client
+# %{deleted} - Number of mails where client added \Deleted flag
+# %{expunged} - Number of mails that client expunged
+# %{trashed} - Number of mails that client copied/moved to the
+# special_use=\Trash mailbox.
#imap_logout_format = in=%i out=%o
# Override the IMAP CAPABILITY response. If the value begins with '+',
client->mailbox = NULL;
storage = mailbox_get_storage(mailbox);
- if (imap_expunge(mailbox, NULL) < 0) {
+ if (imap_expunge(mailbox, NULL, &client->expunged_count) < 0) {
errstr = mailbox_get_last_error(mailbox, &error);
if (error != MAIL_ERROR_PERM)
client_send_untagged_storage_error(client, storage);
return ret;
}
+static void copy_update_trashed(struct client *client, struct mailbox *box,
+ unsigned int count)
+{
+ const struct mailbox_settings *set;
+
+ set = mailbox_settings_find(mailbox_get_namespace(box),
+ mailbox_get_vname(box));
+ if (set != NULL && set->special_use[0] != '\0' &&
+ str_array_icase_find(t_strsplit_spaces(set->special_use, " "),
+ "\\Trash"))
+ client->trashed_count += count;
+}
+
static bool cmd_copy_full(struct client_command_context *cmd, bool move)
{
struct client *client = cmd->client;
pool_unref(&changes.pool);
} else if (move) {
i_assert(copy_count == seq_range_count(&changes.saved_uids));
+ copy_update_trashed(client, destbox, copy_count);
str_printfa(msg, "* OK [COPYUID %u %s ",
changes.uid_validity, src_uidset);
pool_unref(&changes.pool);
} else {
i_assert(copy_count == seq_range_count(&changes.saved_uids));
+ copy_update_trashed(client, destbox, copy_count);
str_printfa(msg, "OK [COPYUID %u %s ", changes.uid_validity,
src_uidset);
int ret;
ret = imap_expunge(client->mailbox, search_args == NULL ? NULL :
- search_args->args);
+ search_args->args, &client->expunged_count);
if (search_args != NULL)
mail_search_args_unref(&search_args);
if (ret < 0) {
const char *set, *reply, *tagged_reply;
string_t *str;
int ret;
+ bool update_deletes;
+ unsigned int deleted_count;
if (!client_read_args(cmd, 0, 0, &args))
return FALSE;
&modified_set);
}
+ update_deletes = (ctx.flags & MAIL_DELETED) != 0 &&
+ ctx.modify_type != MODIFY_REMOVE;
+ deleted_count = 0;
while (mailbox_search_next(search_ctx, &mail)) {
if (ctx.max_modseq < (uint64_t)-1) {
/* check early so there's less work for transaction
continue;
}
}
+ if (update_deletes) {
+ if ((mail_get_flags(mail) & MAIL_DELETED) == 0)
+ deleted_count++;
+ }
if (ctx.modify_type == MODIFY_REPLACE || ctx.flags != 0)
mail_update_flags(mail, ctx.modify_type, ctx.flags);
if (ctx.modify_type == MODIFY_REPLACE || ctx.keywords != NULL) {
client_send_box_error(cmd, client->mailbox);
return TRUE;
}
+ client->deleted_count += deleted_count;
if (array_count(&modified_set) == 0)
tagged_reply = "OK Store completed.";
{ '\0', NULL, "fetch_hdr_bytes" },
{ '\0', NULL, "fetch_body_count" },
{ '\0', NULL, "fetch_body_bytes" },
+ { '\0', NULL, "deleted" },
+ { '\0', NULL, "expunged" },
+ { '\0', NULL, "trashed" },
{ '\0', NULL, NULL }
};
struct var_expand_table *tab;
tab[4].value = dec2str(client->fetch_hdr_bytes);
tab[5].value = dec2str(client->fetch_body_count);
tab[6].value = dec2str(client->fetch_body_bytes);
+ tab[7].value = dec2str(client->deleted_count);
+ tab[8].value = dec2str(client->expunged_count);
+ tab[9].value = dec2str(client->trashed_count);
str = t_str_new(128);
var_expand(str, client->set->imap_logout_format, tab);
/* For imap_logout_format statistics: */
unsigned int fetch_hdr_count, fetch_body_count;
uint64_t fetch_hdr_bytes, fetch_body_bytes;
+ unsigned int deleted_count, expunged_count, trashed_count;
/* SEARCHRES extension: Last saved SEARCH result */
ARRAY_TYPE(seq_range) search_saved_uidset;
#include "mail-search-build.h"
#include "imap-expunge.h"
-int imap_expunge(struct mailbox *box, struct mail_search_arg *next_search_arg)
+int imap_expunge(struct mailbox *box, struct mail_search_arg *next_search_arg,
+ unsigned int *expunged_count)
{
struct mail_search_context *ctx;
struct mailbox_transaction_context *t;
mail_search_args_unref(&search_args);
while (mailbox_search_next(ctx, &mail)) {
+ *expunged_count += 1;
mail_expunge(mail);
expunges = TRUE;
}
struct mail_search_arg;
-int imap_expunge(struct mailbox *box, struct mail_search_arg *next_search_arg)
+int imap_expunge(struct mailbox *box, struct mail_search_arg *next_search_arg,
+ unsigned int *expunged_count)
ATTR_NULL(2);
#endif