1 /* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */
2
3 #include "imap-common.h"
4 #include "mail-storage.h"
5 #include "mail-search-build.h"
6 #include "imap-search-args.h"
7 #include "imap-expunge.h"
8
9 #define IMAP_EXPUNGE_BATCH_SIZE 1000
10
11 /* get a seqset of all the mails with \Deleted */
imap_expunge_get_seqset(struct mailbox * box,struct mail_search_arg * next_search_arg,ARRAY_TYPE (seq_range)* seqset)12 static int imap_expunge_get_seqset(struct mailbox *box,
13 struct mail_search_arg *next_search_arg,
14 ARRAY_TYPE(seq_range) *seqset)
15 {
16 struct mailbox_transaction_context *t;
17 struct mail_search_args *search_args;
18 struct mail_search_context *ctx;
19 struct mail *mail;
20 int ret;
21
22 search_args = mail_search_build_init();
23 search_args->args = p_new(search_args->pool, struct mail_search_arg, 1);
24 search_args->args->type = SEARCH_FLAGS;
25 search_args->args->value.flags = MAIL_DELETED;
26 search_args->args->next = next_search_arg;
27
28 /* Refresh the flags so we'll expunge all messages marked as \Deleted
29 by any session. */
30 t = mailbox_transaction_begin(box, MAILBOX_TRANSACTION_FLAG_REFRESH,
31 "EXPUNGE");
32 ctx = mailbox_search_init(t, search_args, NULL, 0, NULL);
33
34 /* collect the seqs into a seqset */
35 while (mailbox_search_next(ctx, &mail))
36 seq_range_array_add(seqset, mail->seq);
37
38 ret = mailbox_search_deinit(&ctx);
39 /* commit in case a plugin made changes - failures should not abort the expunge */
40 (void) mailbox_transaction_commit(&t);
41 mail_search_args_unref(&search_args);
42
43 if (ret < 0)
44 array_free(seqset);
45
46 return ret;
47 }
48
imap_expunge(struct mailbox * box,struct mail_search_arg * next_search_arg,unsigned int * expunged_count)49 int imap_expunge(struct mailbox *box, struct mail_search_arg *next_search_arg,
50 unsigned int *expunged_count)
51 {
52 struct imap_search_seqset_iter *seqset_iter;
53 struct mail_search_args *search_args;
54 struct mailbox_status status;
55 bool expunges = FALSE;
56 int ret;
57
58 if (mailbox_is_readonly(box)) {
59 /* silently ignore */
60 return 0;
61 }
62
63 mailbox_get_open_status(box, STATUS_MESSAGES, &status);
64
65 search_args = mail_search_build_init();
66 search_args->args = p_new(search_args->pool, struct mail_search_arg, 1);
67 search_args->args->type = SEARCH_SEQSET;
68 p_array_init(&search_args->args->value.seqset, search_args->pool, 16);
69
70 if (imap_expunge_get_seqset(box, next_search_arg,
71 &search_args->args->value.seqset) < 0) {
72 mail_search_args_unref(&search_args);
73 return -1;
74 }
75
76 seqset_iter = imap_search_seqset_iter_init(search_args, status.messages,
77 IMAP_EXPUNGE_BATCH_SIZE);
78
79 do {
80 struct mailbox_transaction_context *t;
81 struct mail_search_context *ctx;
82 struct mail *mail;
83
84 t = mailbox_transaction_begin(box, 0, "EXPUNGE");
85 ctx = mailbox_search_init(t, search_args, NULL, 0, NULL);
86
87 while (mailbox_search_next(ctx, &mail)) {
88 *expunged_count += 1;
89 mail_expunge(mail);
90 expunges = TRUE;
91 }
92
93 ret = mailbox_search_deinit(&ctx);
94 if (ret < 0) {
95 mailbox_transaction_rollback(&t);
96 break;
97 } else {
98 ret = mailbox_transaction_commit(&t);
99 if (ret < 0)
100 break;
101 }
102 } while (imap_search_seqset_iter_next(seqset_iter));
103
104 imap_search_seqset_iter_deinit(&seqset_iter);
105 mail_search_args_unref(&search_args);
106
107 if (ret < 0)
108 return ret;
109
110 return expunges ? 1 : 0;
111 }
112