|
tss@7086
|
1 |
/* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */
|
|
tss@2322
|
2 |
|
|
tss@2322
|
3 |
#include "common.h"
|
|
tss@2322
|
4 |
#include "str.h"
|
|
tss@7195
|
5 |
#include "ostream.h"
|
|
tss@3016
|
6 |
#include "mail-storage.h"
|
|
tss@2322
|
7 |
#include "imap-util.h"
|
|
tss@2322
|
8 |
#include "imap-sync.h"
|
|
tss@2427
|
9 |
#include "commands.h"
|
|
tss@2322
|
10 |
|
|
tss@7353
|
11 |
struct client_sync_context {
|
|
tss@7353
|
12 |
/* if multiple commands are in progress, we may need to wait for them
|
|
tss@7353
|
13 |
to finish before syncing mailbox. */
|
|
tss@7353
|
14 |
unsigned int counter;
|
|
tss@7353
|
15 |
enum mailbox_sync_flags flags;
|
|
tss@7353
|
16 |
enum imap_sync_flags imap_flags;
|
|
tss@7353
|
17 |
const char *tagline;
|
|
tss@7353
|
18 |
imap_sync_callback_t *callback;
|
|
tss@7353
|
19 |
};
|
|
tss@7353
|
20 |
|
|
tss@2427
|
21 |
struct imap_sync_context {
|
|
tss@2427
|
22 |
struct client *client;
|
|
tss@2427
|
23 |
struct mailbox *box;
|
|
tss@3765
|
24 |
enum imap_sync_flags imap_flags;
|
|
tss@2427
|
25 |
|
|
tss@2427
|
26 |
struct mailbox_transaction_context *t;
|
|
tss@2427
|
27 |
struct mailbox_sync_context *sync_ctx;
|
|
tss@3209
|
28 |
struct mail *mail;
|
|
tss@2427
|
29 |
|
|
tss@2427
|
30 |
struct mailbox_sync_rec sync_rec;
|
|
tss@7057
|
31 |
ARRAY_TYPE(keywords) tmp_keywords;
|
|
tss@2427
|
32 |
uint32_t seq;
|
|
tss@2427
|
33 |
|
|
tss@2427
|
34 |
unsigned int messages_count;
|
|
tss@2427
|
35 |
|
|
tss@5762
|
36 |
unsigned int failed:1;
|
|
tss@5762
|
37 |
unsigned int no_newmail:1;
|
|
tss@2427
|
38 |
};
|
|
tss@2427
|
39 |
|
|
tss@2427
|
40 |
struct imap_sync_context *
|
|
tss@2427
|
41 |
imap_sync_init(struct client *client, struct mailbox *box,
|
|
tss@3765
|
42 |
enum imap_sync_flags imap_flags, enum mailbox_sync_flags flags)
|
|
tss@2322
|
43 |
{
|
|
tss@2427
|
44 |
struct imap_sync_context *ctx;
|
|
tss@2427
|
45 |
|
|
tss@2427
|
46 |
i_assert(client->mailbox == box);
|
|
tss@2427
|
47 |
|
|
tss@2427
|
48 |
ctx = i_new(struct imap_sync_context, 1);
|
|
tss@2427
|
49 |
ctx->client = client;
|
|
tss@2427
|
50 |
ctx->box = box;
|
|
tss@3765
|
51 |
ctx->imap_flags = imap_flags;
|
|
tss@2427
|
52 |
|
|
tss@2884
|
53 |
ctx->sync_ctx = mailbox_sync_init(box, flags);
|
|
tss@3209
|
54 |
ctx->t = mailbox_transaction_begin(box, 0);
|
|
tss@3209
|
55 |
ctx->mail = mail_alloc(ctx->t, MAIL_FETCH_FLAGS, 0);
|
|
tss@2427
|
56 |
ctx->messages_count = client->messages_count;
|
|
tss@7057
|
57 |
i_array_init(&ctx->tmp_keywords, client->keywords.announce_count + 8);
|
|
tss@3515
|
58 |
|
|
tss@7057
|
59 |
client_send_mailbox_flags(client, FALSE);
|
|
tss@2427
|
60 |
return ctx;
|
|
tss@2427
|
61 |
}
|
|
tss@2427
|
62 |
|
|
tss@2427
|
63 |
int imap_sync_deinit(struct imap_sync_context *ctx)
|
|
tss@2427
|
64 |
{
|
|
tss@2322
|
65 |
struct mailbox_status status;
|
|
tss@5089
|
66 |
int ret;
|
|
tss@2427
|
67 |
|
|
tss@3879
|
68 |
mail_free(&ctx->mail);
|
|
tss@3209
|
69 |
|
|
tss@5848
|
70 |
if (mailbox_sync_deinit(&ctx->sync_ctx, STATUS_UIDVALIDITY |
|
|
tss@4848
|
71 |
STATUS_MESSAGES | STATUS_RECENT, &status) < 0 ||
|
|
tss@4848
|
72 |
ctx->failed) {
|
|
tss@3879
|
73 |
mailbox_transaction_rollback(&ctx->t);
|
|
tss@2427
|
74 |
i_free(ctx);
|
|
tss@2427
|
75 |
return -1;
|
|
tss@2427
|
76 |
}
|
|
tss@2427
|
77 |
|
|
tss@6512
|
78 |
ret = mailbox_transaction_commit(&ctx->t);
|
|
tss@2427
|
79 |
|
|
tss@5848
|
80 |
if (status.uidvalidity != ctx->client->uidvalidity) {
|
|
tss@5848
|
81 |
/* most clients would get confused by this. disconnect them. */
|
|
tss@5848
|
82 |
client_disconnect_with_error(ctx->client,
|
|
tss@5848
|
83 |
"Mailbox UIDVALIDITY changed");
|
|
tss@5848
|
84 |
}
|
|
tss@5765
|
85 |
if (!ctx->no_newmail) {
|
|
tss@5916
|
86 |
if (status.messages < ctx->messages_count)
|
|
tss@5916
|
87 |
i_panic("Message count decreased");
|
|
tss@5762
|
88 |
ctx->client->messages_count = status.messages;
|
|
tss@5765
|
89 |
if (status.messages != ctx->messages_count) {
|
|
tss@5765
|
90 |
client_send_line(ctx->client,
|
|
tss@5765
|
91 |
t_strdup_printf("* %u EXISTS", status.messages));
|
|
tss@5765
|
92 |
}
|
|
tss@7055
|
93 |
if (status.recent != ctx->client->recent_count &&
|
|
tss@7055
|
94 |
!ctx->no_newmail) {
|
|
tss@5765
|
95 |
ctx->client->recent_count = status.recent;
|
|
tss@5765
|
96 |
client_send_line(ctx->client,
|
|
tss@5765
|
97 |
t_strdup_printf("* %u RECENT", status.recent));
|
|
tss@5765
|
98 |
}
|
|
tss@2427
|
99 |
}
|
|
tss@2427
|
100 |
|
|
tss@7057
|
101 |
array_free(&ctx->tmp_keywords);
|
|
tss@2427
|
102 |
i_free(ctx);
|
|
tss@5089
|
103 |
return ret;
|
|
tss@2427
|
104 |
}
|
|
tss@2427
|
105 |
|
|
tss@7057
|
106 |
static int imap_sync_send_flags(struct imap_sync_context *ctx, string_t *str)
|
|
tss@6986
|
107 |
{
|
|
tss@6986
|
108 |
enum mail_flags flags;
|
|
tss@7057
|
109 |
const char *const *keywords;
|
|
tss@6986
|
110 |
|
|
tss@6986
|
111 |
mail_set_seq(ctx->mail, ctx->seq);
|
|
tss@6986
|
112 |
flags = mail_get_flags(ctx->mail);
|
|
tss@7057
|
113 |
keywords = client_get_keyword_names(ctx->client, &ctx->tmp_keywords,
|
|
tss@7057
|
114 |
mail_get_keyword_indexes(ctx->mail));
|
|
tss@6986
|
115 |
|
|
tss@7353
|
116 |
if ((flags & MAIL_DELETED) != 0)
|
|
tss@7353
|
117 |
ctx->client->sync_seen_deletes = TRUE;
|
|
tss@7353
|
118 |
|
|
tss@6986
|
119 |
str_truncate(str, 0);
|
|
tss@6986
|
120 |
str_printfa(str, "* %u FETCH (", ctx->seq);
|
|
tss@6986
|
121 |
if (ctx->imap_flags & IMAP_SYNC_FLAG_SEND_UID)
|
|
tss@6986
|
122 |
str_printfa(str, "UID %u ", ctx->mail->uid);
|
|
tss@6986
|
123 |
|
|
tss@6986
|
124 |
str_append(str, "FLAGS (");
|
|
tss@7057
|
125 |
imap_write_flags(str, flags, keywords);
|
|
tss@6986
|
126 |
str_append(str, "))");
|
|
tss@6986
|
127 |
return client_send_line(ctx->client, str_c(str));
|
|
tss@6986
|
128 |
}
|
|
tss@6986
|
129 |
|
|
tss@2427
|
130 |
int imap_sync_more(struct imap_sync_context *ctx)
|
|
tss@2427
|
131 |
{
|
|
tss@2322
|
132 |
string_t *str;
|
|
tss@3107
|
133 |
int ret = 1;
|
|
tss@2322
|
134 |
|
|
tss@2322
|
135 |
str = t_str_new(256);
|
|
tss@2427
|
136 |
for (;;) {
|
|
tss@2427
|
137 |
if (ctx->seq == 0) {
|
|
tss@2427
|
138 |
/* get next one */
|
|
tss@6279
|
139 |
if (!mailbox_sync_next(ctx->sync_ctx, &ctx->sync_rec)) {
|
|
tss@6279
|
140 |
/* finished */
|
|
tss@6279
|
141 |
ret = 1;
|
|
tss@2427
|
142 |
break;
|
|
tss@3107
|
143 |
}
|
|
tss@2427
|
144 |
}
|
|
tss@2427
|
145 |
|
|
tss@4008
|
146 |
if (ctx->sync_rec.seq2 > ctx->messages_count) {
|
|
tss@4008
|
147 |
/* don't send change notifications of messages we
|
|
tss@4008
|
148 |
haven't even announced to client yet */
|
|
tss@6355
|
149 |
if (ctx->sync_rec.seq1 > ctx->messages_count) {
|
|
tss@6355
|
150 |
ctx->seq = 0;
|
|
tss@4008
|
151 |
continue;
|
|
tss@6355
|
152 |
}
|
|
tss@4008
|
153 |
ctx->sync_rec.seq2 = ctx->messages_count;
|
|
tss@4008
|
154 |
}
|
|
tss@4008
|
155 |
|
|
tss@2427
|
156 |
switch (ctx->sync_rec.type) {
|
|
tss@2322
|
157 |
case MAILBOX_SYNC_TYPE_FLAGS:
|
|
tss@2427
|
158 |
if (ctx->seq == 0)
|
|
tss@2427
|
159 |
ctx->seq = ctx->sync_rec.seq1;
|
|
tss@2427
|
160 |
|
|
tss@3652
|
161 |
ret = 1;
|
|
tss@2427
|
162 |
for (; ctx->seq <= ctx->sync_rec.seq2; ctx->seq++) {
|
|
tss@3652
|
163 |
if (ret <= 0)
|
|
tss@3652
|
164 |
break;
|
|
tss@3652
|
165 |
|
|
tss@7057
|
166 |
ret = imap_sync_send_flags(ctx, str);
|
|
tss@2322
|
167 |
}
|
|
tss@2322
|
168 |
break;
|
|
tss@2322
|
169 |
case MAILBOX_SYNC_TYPE_EXPUNGE:
|
|
tss@4038
|
170 |
if (ctx->seq == 0)
|
|
tss@2427
|
171 |
ctx->seq = ctx->sync_rec.seq2;
|
|
tss@3652
|
172 |
ret = 1;
|
|
tss@2427
|
173 |
for (; ctx->seq >= ctx->sync_rec.seq1; ctx->seq--) {
|
|
tss@3652
|
174 |
if (ret <= 0)
|
|
tss@3652
|
175 |
break;
|
|
tss@3652
|
176 |
|
|
tss@2322
|
177 |
str_truncate(str, 0);
|
|
tss@2427
|
178 |
str_printfa(str, "* %u EXPUNGE", ctx->seq);
|
|
tss@3107
|
179 |
ret = client_send_line(ctx->client, str_c(str));
|
|
tss@2322
|
180 |
}
|
|
tss@4038
|
181 |
if (ctx->seq < ctx->sync_rec.seq1) {
|
|
tss@4038
|
182 |
/* update only after we're finished, so that
|
|
tss@4038
|
183 |
the seq2 > messages_count check above
|
|
tss@4038
|
184 |
doesn't break */
|
|
tss@4038
|
185 |
ctx->messages_count -=
|
|
tss@4038
|
186 |
ctx->sync_rec.seq2 -
|
|
tss@4038
|
187 |
ctx->sync_rec.seq1 + 1;
|
|
tss@4038
|
188 |
}
|
|
tss@2322
|
189 |
break;
|
|
tss@2322
|
190 |
}
|
|
tss@3652
|
191 |
if (ret <= 0) {
|
|
tss@3652
|
192 |
/* failure / buffer full */
|
|
tss@3652
|
193 |
break;
|
|
tss@3652
|
194 |
}
|
|
tss@3652
|
195 |
|
|
tss@2427
|
196 |
ctx->seq = 0;
|
|
tss@2427
|
197 |
}
|
|
tss@3107
|
198 |
return ret;
|
|
tss@2427
|
199 |
}
|
|
tss@2427
|
200 |
|
|
tss@7353
|
201 |
static bool cmd_finish_sync(struct client_command_context *cmd)
|
|
tss@7353
|
202 |
{
|
|
tss@7353
|
203 |
if (cmd->sync->callback != NULL)
|
|
tss@7353
|
204 |
return cmd->sync->callback(cmd);
|
|
tss@7353
|
205 |
else {
|
|
tss@7353
|
206 |
client_send_tagline(cmd, cmd->sync->tagline);
|
|
tss@7353
|
207 |
return TRUE;
|
|
tss@7353
|
208 |
}
|
|
tss@7353
|
209 |
}
|
|
tss@7353
|
210 |
|
|
tss@7195
|
211 |
static bool cmd_sync_continue(struct client_command_context *sync_cmd)
|
|
tss@2427
|
212 |
{
|
|
tss@7434
|
213 |
struct client_command_context *cmd, *prev;
|
|
tss@7195
|
214 |
struct client *client = sync_cmd->client;
|
|
tss@7195
|
215 |
struct imap_sync_context *ctx = sync_cmd->context;
|
|
tss@3652
|
216 |
int ret;
|
|
tss@2427
|
217 |
|
|
tss@7195
|
218 |
i_assert(ctx->client == client);
|
|
tss@7195
|
219 |
|
|
tss@7195
|
220 |
if ((ret = imap_sync_more(ctx)) == 0)
|
|
tss@7195
|
221 |
return FALSE;
|
|
tss@7195
|
222 |
if (ret < 0)
|
|
tss@7195
|
223 |
ctx->failed = TRUE;
|
|
tss@7195
|
224 |
|
|
tss@7195
|
225 |
client->syncing = FALSE;
|
|
tss@7195
|
226 |
if (imap_sync_deinit(ctx) < 0) {
|
|
tss@7195
|
227 |
client_send_untagged_storage_error(client,
|
|
tss@7195
|
228 |
mailbox_get_storage(client->mailbox));
|
|
tss@4939
|
229 |
}
|
|
tss@7195
|
230 |
sync_cmd->context = NULL;
|
|
tss@2427
|
231 |
|
|
tss@7434
|
232 |
/* Finish all commands that waited for this sync. Go through the queue
|
|
tss@7434
|
233 |
backwards, so that tagged replies are sent in the same order as
|
|
tss@7434
|
234 |
they were received. This fixes problems with clients that rely on
|
|
tss@7434
|
235 |
this (Apple Mail 3.2) */
|
|
tss@7434
|
236 |
for (cmd = client->command_queue; cmd->next != NULL; cmd = cmd->next) ;
|
|
tss@7434
|
237 |
for (; cmd != NULL; cmd = prev) {
|
|
tss@7434
|
238 |
prev = cmd->prev;
|
|
tss@7432
|
239 |
|
|
tss@7195
|
240 |
if (cmd->state == CLIENT_COMMAND_STATE_WAIT_SYNC &&
|
|
tss@7195
|
241 |
cmd != sync_cmd &&
|
|
tss@7353
|
242 |
cmd->sync->counter+1 == client->sync_counter) {
|
|
tss@7353
|
243 |
if (cmd_finish_sync(cmd))
|
|
tss@7431
|
244 |
client_command_free(&cmd);
|
|
tss@7195
|
245 |
}
|
|
tss@2322
|
246 |
}
|
|
tss@7353
|
247 |
return cmd_finish_sync(sync_cmd);
|
|
tss@2427
|
248 |
}
|
|
tss@2427
|
249 |
|
|
tss@7195
|
250 |
static void get_common_sync_flags(struct client *client,
|
|
tss@7195
|
251 |
enum mailbox_sync_flags *flags_r,
|
|
tss@7195
|
252 |
enum imap_sync_flags *imap_flags_r)
|
|
tss@2427
|
253 |
{
|
|
tss@7195
|
254 |
struct client_command_context *cmd;
|
|
tss@7195
|
255 |
unsigned int count = 0, fast_count = 0, noexpunges_count = 0;
|
|
tss@7195
|
256 |
|
|
tss@7195
|
257 |
*flags_r = 0;
|
|
tss@7195
|
258 |
*imap_flags_r = 0;
|
|
tss@7195
|
259 |
|
|
tss@7195
|
260 |
for (cmd = client->command_queue; cmd != NULL; cmd = cmd->next) {
|
|
tss@7353
|
261 |
if (cmd->sync != NULL &&
|
|
tss@7353
|
262 |
cmd->sync->counter == client->sync_counter) {
|
|
tss@7353
|
263 |
if ((cmd->sync->flags & MAILBOX_SYNC_FLAG_FAST) != 0)
|
|
tss@7195
|
264 |
fast_count++;
|
|
tss@7353
|
265 |
if (cmd->sync->flags & MAILBOX_SYNC_FLAG_NO_EXPUNGES)
|
|
tss@7195
|
266 |
noexpunges_count++;
|
|
tss@7353
|
267 |
*flags_r |= cmd->sync->flags;
|
|
tss@7353
|
268 |
*imap_flags_r |= cmd->sync->imap_flags;
|
|
tss@7195
|
269 |
count++;
|
|
tss@7195
|
270 |
}
|
|
tss@7195
|
271 |
}
|
|
tss@7421
|
272 |
i_assert(noexpunges_count == 0 || noexpunges_count == count);
|
|
tss@7195
|
273 |
if (fast_count != count)
|
|
tss@7195
|
274 |
*flags_r &= ~MAILBOX_SYNC_FLAG_FAST;
|
|
tss@7195
|
275 |
|
|
tss@7195
|
276 |
i_assert((*flags_r & (MAILBOX_SYNC_AUTO_STOP |
|
|
tss@7195
|
277 |
MAILBOX_SYNC_FLAG_FIX_INCONSISTENT)) == 0);
|
|
tss@7195
|
278 |
}
|
|
tss@7195
|
279 |
|
|
tss@7195
|
280 |
static bool cmd_sync_client(struct client_command_context *sync_cmd)
|
|
tss@7195
|
281 |
{
|
|
tss@7195
|
282 |
struct client *client = sync_cmd->client;
|
|
tss@7195
|
283 |
struct imap_sync_context *ctx;
|
|
tss@7195
|
284 |
enum mailbox_sync_flags flags;
|
|
tss@7195
|
285 |
enum imap_sync_flags imap_flags;
|
|
tss@5762
|
286 |
bool no_newmail;
|
|
tss@2427
|
287 |
|
|
tss@7195
|
288 |
/* there may be multiple commands waiting. use their combined flags */
|
|
tss@7195
|
289 |
get_common_sync_flags(client, &flags, &imap_flags);
|
|
tss@7195
|
290 |
client->sync_counter++;
|
|
tss@2322
|
291 |
|
|
tss@5762
|
292 |
no_newmail = (client_workarounds & WORKAROUND_DELAY_NEWMAIL) != 0 &&
|
|
tss@6454
|
293 |
(imap_flags & IMAP_SYNC_FLAG_SAFE) == 0;
|
|
tss@5762
|
294 |
if (no_newmail) {
|
|
tss@5762
|
295 |
/* expunges might break the client just as badly as new mail
|
|
tss@5762
|
296 |
notifications. */
|
|
tss@5762
|
297 |
flags |= MAILBOX_SYNC_FLAG_NO_EXPUNGES;
|
|
tss@3358
|
298 |
}
|
|
tss@3204
|
299 |
|
|
tss@7195
|
300 |
client->syncing = TRUE;
|
|
tss@2322
|
301 |
|
|
tss@7195
|
302 |
ctx = imap_sync_init(client, client->mailbox, imap_flags, flags);
|
|
tss@7195
|
303 |
ctx->no_newmail = no_newmail;
|
|
tss@7195
|
304 |
|
|
tss@7195
|
305 |
/* handle the syncing using sync_cmd. it doesn't actually matter which
|
|
tss@7195
|
306 |
one of the pending commands it is. */
|
|
tss@7195
|
307 |
sync_cmd->func = cmd_sync_continue;
|
|
tss@7195
|
308 |
sync_cmd->context = ctx;
|
|
tss@7195
|
309 |
sync_cmd->state = CLIENT_COMMAND_STATE_WAIT_OUTPUT;
|
|
tss@7195
|
310 |
if (!cmd_sync_continue(sync_cmd)) {
|
|
tss@7195
|
311 |
o_stream_set_flush_pending(client->output, TRUE);
|
|
tss@7195
|
312 |
return FALSE;
|
|
tss@7195
|
313 |
}
|
|
tss@7195
|
314 |
|
|
tss@7431
|
315 |
client_command_free(&sync_cmd);
|
|
tss@7195
|
316 |
(void)cmd_sync_delayed(client);
|
|
tss@7195
|
317 |
return TRUE;
|
|
tss@7195
|
318 |
}
|
|
tss@7195
|
319 |
|
|
tss@7353
|
320 |
static bool
|
|
tss@7353
|
321 |
cmd_sync_full(struct client_command_context *cmd, enum mailbox_sync_flags flags,
|
|
tss@7353
|
322 |
enum imap_sync_flags imap_flags, const char *tagline,
|
|
tss@7353
|
323 |
imap_sync_callback_t *callback)
|
|
tss@7195
|
324 |
{
|
|
tss@7195
|
325 |
struct client *client = cmd->client;
|
|
tss@7195
|
326 |
|
|
tss@7195
|
327 |
i_assert(client->output_lock == cmd || client->output_lock == NULL);
|
|
tss@7195
|
328 |
|
|
tss@7195
|
329 |
if (cmd->cancel)
|
|
tss@7195
|
330 |
return TRUE;
|
|
tss@7195
|
331 |
|
|
tss@7195
|
332 |
if (client->mailbox == NULL) {
|
|
tss@7195
|
333 |
/* no mailbox selected, no point in delaying the sync */
|
|
tss@7353
|
334 |
i_assert(callback == NULL);
|
|
tss@7195
|
335 |
client_send_tagline(cmd, tagline);
|
|
tss@7195
|
336 |
return TRUE;
|
|
tss@7195
|
337 |
}
|
|
tss@7195
|
338 |
|
|
tss@7353
|
339 |
cmd->sync = p_new(cmd->pool, struct client_sync_context, 1);
|
|
tss@7353
|
340 |
cmd->sync->counter = client->sync_counter;
|
|
tss@7353
|
341 |
cmd->sync->flags = flags;
|
|
tss@7353
|
342 |
cmd->sync->imap_flags = imap_flags;
|
|
tss@7353
|
343 |
cmd->sync->tagline = p_strdup(cmd->pool, tagline);
|
|
tss@7353
|
344 |
cmd->sync->callback = callback;
|
|
tss@7195
|
345 |
cmd->state = CLIENT_COMMAND_STATE_WAIT_SYNC;
|
|
tss@7195
|
346 |
|
|
tss@7195
|
347 |
cmd->func = NULL;
|
|
tss@7195
|
348 |
cmd->context = NULL;
|
|
tss@7195
|
349 |
|
|
tss@7195
|
350 |
client->output_lock = NULL;
|
|
tss@4939
|
351 |
if (client->input_lock == cmd)
|
|
tss@4939
|
352 |
client->input_lock = NULL;
|
|
tss@7195
|
353 |
return FALSE;
|
|
tss@2322
|
354 |
}
|
|
tss@7195
|
355 |
|
|
tss@7353
|
356 |
bool cmd_sync(struct client_command_context *cmd, enum mailbox_sync_flags flags,
|
|
tss@7353
|
357 |
enum imap_sync_flags imap_flags, const char *tagline)
|
|
tss@7353
|
358 |
{
|
|
tss@7353
|
359 |
return cmd_sync_full(cmd, flags, imap_flags, tagline, NULL);
|
|
tss@7353
|
360 |
}
|
|
tss@7353
|
361 |
|
|
tss@7353
|
362 |
bool cmd_sync_callback(struct client_command_context *cmd,
|
|
tss@7353
|
363 |
enum mailbox_sync_flags flags,
|
|
tss@7353
|
364 |
enum imap_sync_flags imap_flags,
|
|
tss@7353
|
365 |
imap_sync_callback_t *callback)
|
|
tss@7353
|
366 |
{
|
|
tss@7353
|
367 |
return cmd_sync_full(cmd, flags, imap_flags, NULL, callback);
|
|
tss@7353
|
368 |
}
|
|
tss@7353
|
369 |
|
|
tss@7195
|
370 |
static bool cmd_sync_drop_fast(struct client *client)
|
|
tss@7195
|
371 |
{
|
|
tss@7434
|
372 |
struct client_command_context *cmd, *prev;
|
|
tss@7195
|
373 |
bool ret = FALSE;
|
|
tss@7195
|
374 |
|
|
tss@7434
|
375 |
if (client->command_queue == NULL)
|
|
tss@7434
|
376 |
return FALSE;
|
|
tss@7434
|
377 |
|
|
tss@7434
|
378 |
for (cmd = client->command_queue; cmd->next != NULL; cmd = cmd->next) ;
|
|
tss@7434
|
379 |
for (; cmd != NULL; cmd = prev) {
|
|
tss@7434
|
380 |
prev = cmd->next;
|
|
tss@7195
|
381 |
|
|
tss@7195
|
382 |
if (cmd->state == CLIENT_COMMAND_STATE_WAIT_SYNC &&
|
|
tss@7353
|
383 |
(cmd->sync->flags & MAILBOX_SYNC_FLAG_FAST) != 0) {
|
|
tss@7353
|
384 |
if (cmd_finish_sync(cmd)) {
|
|
tss@7431
|
385 |
client_command_free(&cmd);
|
|
tss@7353
|
386 |
ret = TRUE;
|
|
tss@7353
|
387 |
}
|
|
tss@7195
|
388 |
}
|
|
tss@7195
|
389 |
}
|
|
tss@7195
|
390 |
return ret;
|
|
tss@7195
|
391 |
}
|
|
tss@7195
|
392 |
|
|
tss@7195
|
393 |
bool cmd_sync_delayed(struct client *client)
|
|
tss@7195
|
394 |
{
|
|
tss@7421
|
395 |
struct client_command_context *cmd, *first_expunge, *first_nonexpunge;
|
|
tss@7195
|
396 |
|
|
tss@7195
|
397 |
if (client->output_lock != NULL) {
|
|
tss@7195
|
398 |
/* wait until we can send output to client */
|
|
tss@7195
|
399 |
return FALSE;
|
|
tss@7195
|
400 |
}
|
|
tss@7195
|
401 |
|
|
tss@7195
|
402 |
if (client->syncing ||
|
|
tss@7195
|
403 |
(client->mailbox != NULL &&
|
|
tss@7195
|
404 |
mailbox_transaction_get_count(client->mailbox) > 0)) {
|
|
tss@7195
|
405 |
/* wait until mailbox can be synced */
|
|
tss@7195
|
406 |
return cmd_sync_drop_fast(client);
|
|
tss@7195
|
407 |
}
|
|
tss@7195
|
408 |
|
|
tss@7421
|
409 |
/* separate syncs that can send expunges from those that can't */
|
|
tss@7421
|
410 |
first_expunge = first_nonexpunge = NULL;
|
|
tss@7195
|
411 |
for (cmd = client->command_queue; cmd != NULL; cmd = cmd->next) {
|
|
tss@7421
|
412 |
if (cmd->sync != NULL &&
|
|
tss@7421
|
413 |
cmd->sync->counter == client->sync_counter) {
|
|
tss@7421
|
414 |
if (cmd->sync->flags & MAILBOX_SYNC_FLAG_NO_EXPUNGES) {
|
|
tss@7421
|
415 |
if (first_nonexpunge == NULL)
|
|
tss@7421
|
416 |
first_nonexpunge = cmd;
|
|
tss@7421
|
417 |
} else {
|
|
tss@7421
|
418 |
if (first_expunge == NULL)
|
|
tss@7421
|
419 |
first_expunge = cmd;
|
|
tss@7421
|
420 |
}
|
|
tss@7195
|
421 |
}
|
|
tss@7195
|
422 |
}
|
|
tss@7421
|
423 |
if (first_expunge != NULL && first_nonexpunge != NULL) {
|
|
tss@7421
|
424 |
/* sync expunges after nonexpunges */
|
|
tss@7421
|
425 |
for (cmd = first_expunge; cmd != NULL; cmd = cmd->next) {
|
|
tss@7421
|
426 |
if (cmd->sync != NULL &&
|
|
tss@7421
|
427 |
cmd->sync->counter == client->sync_counter &&
|
|
tss@7421
|
428 |
(cmd->sync->flags &
|
|
tss@7421
|
429 |
MAILBOX_SYNC_FLAG_NO_EXPUNGES) == 0)
|
|
tss@7421
|
430 |
cmd->sync->counter++;
|
|
tss@7421
|
431 |
}
|
|
tss@7421
|
432 |
first_expunge = NULL;
|
|
tss@7421
|
433 |
}
|
|
tss@7421
|
434 |
cmd = first_nonexpunge != NULL ? first_nonexpunge : first_expunge;
|
|
tss@7195
|
435 |
|
|
tss@7195
|
436 |
if (cmd == NULL)
|
|
tss@7195
|
437 |
return cmd_sync_drop_fast(client);
|
|
tss@7195
|
438 |
i_assert(client->mailbox != NULL);
|
|
tss@7195
|
439 |
return cmd_sync_client(cmd);
|
|
tss@7195
|
440 |
}
|