~ubuntu-branches/ubuntu/utopic/dovecot/utopic-proposed

« back to all changes in this revision

Viewing changes to src/imap/imap-sync.c

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2014-01-08 09:35:49 UTC
  • mfrom: (4.1.35 sid)
  • Revision ID: package-import@ubuntu.com-20140108093549-i72o93pux8p0dlaf
Tags: 1:2.2.9-1ubuntu1
* Merge from Debian unstable, remaining changes:
  + Add mail-stack-delivery package:
    - Update d/rules
    - d/control: convert existing dovecot-postfix package to a dummy
      package and add new mail-stack-delivery package.
    - Update maintainer scripts.
    - Rename d/dovecot-postfix.* to debian/mail-stack-delivery.*
    - d/mail-stack-delivery.preinst: Move previously installed backups and
      config files to a new package namespace.
    - d/mail-stack-delivery.prerm: Added to handle downgrades.
  + Use Snakeoil SSL certificates by default:
    - d/control: Depend on ssl-cert.
    - d/dovecot-core.postinst: Relax grep for SSL_* a bit.
  + Add autopkgtest to debian/tests/*.
  + Add ufw integration:
    - d/dovecot-core.ufw.profile: new ufw profile.
    - d/rules: install profile in dovecot-core.
    - d/control: dovecot-core - suggest ufw.
  + d/dovecot-core.dirs: Added usr/share/doc/dovecot-core
  + Add apport hook:
    - d/rules, d/source_dovecot.py
  + Add upstart job:
    - d/rules, d/dovecot-core.dovecot.upstart, d/control,
      d/dovecot-core.dirs, dovecot-imapd.{postrm, postinst, prerm},
      d/dovecot-pop3d.{postinst, postrm, prerm}.
      d/mail-stack-deliver.postinst: Convert init script to upstart.
  + Use the autotools-dev dh addon to update config.guess/config.sub for
    arm64.
* Dropped changes, included in Debian:
  - Update Dovecot name to reflect distribution in login greeting.
  - Update Drac plugin for >= 2.0.0 support.
* d/control: Drop dovecot-postfix package as its no longer required.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (c) 2002-2012 Dovecot authors, see the included COPYING file */
 
1
/* Copyright (c) 2002-2013 Dovecot authors, see the included COPYING file */
2
2
 
3
3
#include "imap-common.h"
4
4
#include "str.h"
5
5
#include "ostream.h"
 
6
#include "mail-user.h"
6
7
#include "mail-storage.h"
7
 
#include "mail-user.h"
 
8
#include "mail-search-build.h"
8
9
#include "imap-quote.h"
9
10
#include "imap-util.h"
 
11
#include "imap-fetch.h"
 
12
#include "imap-notify.h"
 
13
#include "imap-commands.h"
10
14
#include "imap-sync.h"
11
 
#include "imap-commands.h"
12
15
 
13
16
struct client_sync_context {
14
17
        /* if multiple commands are in progress, we may need to wait for them
29
32
        struct mailbox_sync_context *sync_ctx;
30
33
        struct mail *mail;
31
34
 
 
35
        struct mailbox_status status;
 
36
        struct mailbox_sync_status sync_status;
 
37
 
32
38
        struct mailbox_sync_rec sync_rec;
33
39
        ARRAY_TYPE(keywords) tmp_keywords;
34
40
        ARRAY_TYPE(seq_range) expunges;
35
41
        uint32_t seq;
36
42
 
37
43
        ARRAY_TYPE(seq_range) search_adds, search_removes;
 
44
        unsigned int search_update_idx;
38
45
 
39
46
        unsigned int messages_count;
40
47
 
41
48
        unsigned int failed:1;
 
49
        unsigned int finished:1;
42
50
        unsigned int no_newmail:1;
 
51
        unsigned int have_new_mails:1;
 
52
        unsigned int search_update_notifying:1;
43
53
};
44
54
 
45
55
static void uids_to_seqs(struct mailbox *box, ARRAY_TYPE(seq_range) *uids)
67
77
        } T_END;
68
78
}
69
79
 
70
 
static void
 
80
static int search_update_fetch_more(const struct imap_search_update *update)
 
81
{
 
82
        int ret;
 
83
 
 
84
        if ((ret = imap_fetch_more_no_lock_update(update->fetch_ctx)) <= 0)
 
85
                return ret;
 
86
        /* finished the FETCH */
 
87
        if (imap_fetch_end(update->fetch_ctx) < 0)
 
88
                return -1;
 
89
        return 1;
 
90
}
 
91
 
 
92
static int
 
93
imap_sync_send_fetch_to_search_update(struct imap_sync_context *ctx,
 
94
                                      const struct imap_search_update *update)
 
95
{
 
96
        struct mail_search_args *search_args;
 
97
        struct mail_search_arg *arg;
 
98
        ARRAY_TYPE(seq_range) seqs;
 
99
 
 
100
        if (ctx->search_update_notifying)
 
101
                return search_update_fetch_more(update);
 
102
 
 
103
        i_assert(!update->fetch_ctx->state.fetching);
 
104
 
 
105
        if (array_count(&ctx->search_adds) == 0 || !ctx->have_new_mails)
 
106
                return 1;
 
107
 
 
108
        search_args = mail_search_build_init();
 
109
        arg = mail_search_build_add(search_args, SEARCH_UIDSET);
 
110
        p_array_init(&arg->value.seqset, search_args->pool, 1);
 
111
 
 
112
        /* find the newly appended messages: ctx->messages_count is the message
 
113
           count before new messages found by sync, client->messages_count is
 
114
           the number of messages after. */
 
115
        t_array_init(&seqs, 1);
 
116
        seq_range_array_add_range(&seqs, ctx->messages_count+1,
 
117
                                  ctx->client->messages_count);
 
118
        mailbox_get_uid_range(ctx->client->mailbox, &seqs, &arg->value.seqset);
 
119
        /* remove messages not in the search_adds list */
 
120
        seq_range_array_intersect(&arg->value.seqset, &ctx->search_adds);
 
121
 
 
122
        imap_fetch_begin(update->fetch_ctx, ctx->client->mailbox, search_args);
 
123
        mail_search_args_unref(&search_args);
 
124
        return search_update_fetch_more(update);
 
125
}
 
126
 
 
127
static int
71
128
imap_sync_send_search_update(struct imap_sync_context *ctx,
72
 
                             const struct imap_search_update *update)
 
129
                             const struct imap_search_update *update,
 
130
                             bool removes_only)
73
131
{
74
132
        string_t *cmd;
 
133
        int ret = 1;
75
134
 
76
 
        mailbox_search_result_sync(update->result, &ctx->search_removes,
77
 
                                   &ctx->search_adds);
 
135
        if (!ctx->search_update_notifying) {
 
136
                mailbox_search_result_sync(update->result, &ctx->search_removes,
 
137
                                           &ctx->search_adds);
 
138
        }
78
139
        if (array_count(&ctx->search_adds) == 0 &&
79
140
            array_count(&ctx->search_removes) == 0)
80
 
                return;
 
141
                return 1;
 
142
 
 
143
        i_assert(array_count(&ctx->search_adds) == 0 || !removes_only);
 
144
        if (update->fetch_ctx != NULL) {
 
145
                ret = imap_sync_send_fetch_to_search_update(ctx, update);
 
146
                if (ret == 0) {
 
147
                        ctx->search_update_notifying = TRUE;
 
148
                        return 0;
 
149
                }
 
150
        }
 
151
        ctx->search_update_notifying = FALSE;
81
152
 
82
153
        cmd = t_str_new(256);
83
154
        str_append(cmd, "* ESEARCH (TAG ");
84
 
        imap_quote_append_string(cmd, update->tag, FALSE);
 
155
        imap_append_string(cmd, update->tag);
85
156
        str_append_c(cmd, ')');
86
157
        if (update->return_uids)
87
158
                str_append(cmd, " UID");
102
173
                str_append_c(cmd, ')');
103
174
        }
104
175
        str_append(cmd, "\r\n");
105
 
        o_stream_send(ctx->client->output, str_data(cmd), str_len(cmd));
 
176
        o_stream_nsend(ctx->client->output, str_data(cmd), str_len(cmd));
 
177
        return ret;
106
178
}
107
179
 
108
 
static void imap_sync_send_search_updates(struct imap_sync_context *ctx)
 
180
static int
 
181
imap_sync_send_search_updates(struct imap_sync_context *ctx, bool removes_only)
109
182
{
110
 
        const struct imap_search_update *update;
 
183
        const struct imap_search_update *updates;
 
184
        unsigned int i, count;
 
185
        int ret = 1;
111
186
 
112
187
        if (!array_is_created(&ctx->client->search_updates))
113
 
                return;
 
188
                return 1;
114
189
 
115
190
        if (!array_is_created(&ctx->search_removes)) {
116
191
                i_array_init(&ctx->search_removes, 64);
117
192
                i_array_init(&ctx->search_adds, 128);
118
193
        }
119
194
 
120
 
        array_foreach(&ctx->client->search_updates, update) T_BEGIN {
121
 
                imap_sync_send_search_update(ctx, update);
122
 
        } T_END;
 
195
        updates = array_get(&ctx->client->search_updates, &count);
 
196
        for (i = ctx->search_update_idx; i < count; i++) {
 
197
                T_BEGIN {
 
198
                        ret = imap_sync_send_search_update(ctx, &updates[i],
 
199
                                                           removes_only);
 
200
                } T_END;
 
201
                if (ret <= 0)
 
202
                        break;
 
203
        }
 
204
        ctx->search_update_idx = i;
 
205
        return ret;
123
206
}
124
207
 
125
208
struct imap_sync_context *
130
213
 
131
214
        i_assert(client->mailbox == box);
132
215
 
 
216
        if (client->notify_immediate_expunges) {
 
217
                /* NOTIFY enabled without SELECTED-DELAYED */
 
218
                flags &= ~MAILBOX_SYNC_FLAG_NO_EXPUNGES;
 
219
        }
 
220
 
133
221
        ctx = i_new(struct imap_sync_context, 1);
134
222
        ctx->client = client;
135
223
        ctx->box = box;
155
243
        /* send search updates the first time after sync is initialized.
156
244
           it now contains expunged messages that must be sent before
157
245
           EXPUNGE replies. */
158
 
        imap_sync_send_search_updates(ctx);
 
246
        if (imap_sync_send_search_updates(ctx, TRUE) == 0)
 
247
                i_unreached();
 
248
        ctx->search_update_idx = 0;
159
249
        return ctx;
160
250
}
161
251
 
162
252
static void
163
253
imap_sync_send_highestmodseq(struct imap_sync_context *ctx,
164
 
                             const struct mailbox_status *status,
165
 
                             const struct mailbox_sync_status *sync_status,
166
254
                             struct client_command_context *sync_cmd)
167
255
{
168
256
        struct client *client = ctx->client;
169
257
        uint64_t send_modseq = 0;
170
258
 
171
 
        if (sync_status->sync_delayed_expunges &&
 
259
        if (ctx->sync_status.sync_delayed_expunges &&
172
260
            client->highest_fetch_modseq > client->sync_last_full_modseq) {
173
261
                /* if client updates highest-modseq using returned MODSEQs
174
262
                   it loses expunges. try to avoid this by sending it a lower
175
263
                   pre-expunge HIGHESTMODSEQ reply. */
176
264
                send_modseq = client->sync_last_full_modseq;
177
 
        } else if (!sync_status->sync_delayed_expunges &&
178
 
                   status->highest_modseq > client->sync_last_full_modseq &&
179
 
                   status->highest_modseq > client->highest_fetch_modseq) {
 
265
        } else if (!ctx->sync_status.sync_delayed_expunges &&
 
266
                   ctx->status.highest_modseq > client->sync_last_full_modseq &&
 
267
                   ctx->status.highest_modseq > client->highest_fetch_modseq) {
180
268
                /* we've probably sent some VANISHED or EXISTS replies which
181
269
                   increased the highest-modseq. notify the client about
182
270
                   this. */
183
 
                send_modseq = status->highest_modseq;
 
271
                send_modseq = ctx->status.highest_modseq;
184
272
        }
185
273
 
186
274
        if (send_modseq == 0) {
187
275
                /* no sending */
188
276
        } else if (sync_cmd->sync != NULL && /* IDLE doesn't have ->sync */
 
277
                   sync_cmd->sync->tagline != NULL && /* NOTIFY doesn't have tagline */
189
278
                   strncmp(sync_cmd->sync->tagline, "OK ", 3) == 0 &&
190
279
                   sync_cmd->sync->tagline[3] != '[') {
191
280
                /* modify the tagged reply directly */
200
289
                        (unsigned long long)send_modseq));
201
290
        }
202
291
 
203
 
        if (!sync_status->sync_delayed_expunges) {
 
292
        if (!ctx->sync_status.sync_delayed_expunges) {
204
293
                /* no delayed expunges, remember this for future */
205
 
                client->sync_last_full_modseq = status->highest_modseq;
 
294
                client->sync_last_full_modseq = ctx->status.highest_modseq;
206
295
        }
207
296
        client->highest_fetch_modseq = 0;
208
297
}
209
298
 
210
 
int imap_sync_deinit(struct imap_sync_context *ctx,
211
 
                     struct client_command_context *sync_cmd)
 
299
static int imap_sync_finish(struct imap_sync_context *ctx, bool aborting)
212
300
{
213
301
        struct client *client = ctx->client;
214
 
        struct mailbox_status status;
215
 
        struct mailbox_sync_status sync_status;
216
 
        int ret;
 
302
        int ret = ctx->failed ? -1 : 0;
 
303
 
 
304
        if (ctx->finished)
 
305
                return ret;
 
306
        ctx->finished = TRUE;
217
307
 
218
308
        mail_free(&ctx->mail);
 
309
        /* the transaction is used only for fetching modseqs/flags.
 
310
           it can't really fail.. */
 
311
        (void)mailbox_transaction_commit(&ctx->t);
 
312
 
219
313
        if (array_is_created(&ctx->expunges))
220
314
                array_free(&ctx->expunges);
221
315
 
222
 
        if (mailbox_sync_deinit(&ctx->sync_ctx, &sync_status) < 0 ||
 
316
        if (mailbox_sync_deinit(&ctx->sync_ctx, &ctx->sync_status) < 0 ||
223
317
            ctx->failed) {
224
 
                mailbox_transaction_rollback(&ctx->t);
225
 
                array_free(&ctx->tmp_keywords);
226
 
                i_free(ctx);
 
318
                ctx->failed = TRUE;
227
319
                return -1;
228
320
        }
229
321
        mailbox_get_open_status(ctx->box, STATUS_UIDVALIDITY |
230
322
                                STATUS_MESSAGES | STATUS_RECENT |
231
 
                                STATUS_HIGHESTMODSEQ, &status);
232
 
 
233
 
        ret = mailbox_transaction_commit(&ctx->t);
234
 
 
235
 
        if (status.uidvalidity != client->uidvalidity) {
 
323
                                STATUS_HIGHESTMODSEQ, &ctx->status);
 
324
 
 
325
        if (ctx->status.uidvalidity != client->uidvalidity) {
236
326
                /* most clients would get confused by this. disconnect them. */
237
327
                client_disconnect_with_error(client,
238
328
                                             "Mailbox UIDVALIDITY changed");
239
329
        }
240
 
        if (!ctx->no_newmail) {
241
 
                if (status.messages < ctx->messages_count)
 
330
        if (!ctx->no_newmail && !aborting) {
 
331
                if (ctx->status.messages < ctx->messages_count)
242
332
                        i_panic("Message count decreased");
243
 
                client->messages_count = status.messages;
244
 
                if (status.messages != ctx->messages_count) {
245
 
                        client_send_line(client,
246
 
                                t_strdup_printf("* %u EXISTS", status.messages));
247
 
                }
248
 
                if (status.recent != client->recent_count &&
249
 
                    !ctx->no_newmail) {
250
 
                        client->recent_count = status.recent;
251
 
                        client_send_line(client,
252
 
                                t_strdup_printf("* %u RECENT", status.recent));
253
 
                }
254
 
        }
 
333
                if (ctx->status.messages != ctx->messages_count &&
 
334
                    client->notify_count_changes) {
 
335
                        client_send_line(client,
 
336
                                t_strdup_printf("* %u EXISTS", ctx->status.messages));
 
337
                        ctx->have_new_mails = TRUE;
 
338
                }
 
339
                if (ctx->status.recent != client->recent_count &&
 
340
                    client->notify_count_changes) {
 
341
                        client_send_line(client,
 
342
                                t_strdup_printf("* %u RECENT", ctx->status.recent));
 
343
                }
 
344
                client->messages_count = ctx->status.messages;
 
345
                client->recent_count = ctx->status.recent;
 
346
        }
 
347
        return ret;
 
348
}
 
349
 
 
350
static int imap_sync_notify_more(struct imap_sync_context *ctx)
 
351
{
 
352
        int ret = 1;
 
353
 
 
354
        if (ctx->have_new_mails && ctx->client->notify_ctx != NULL) {
 
355
                /* send FETCH replies for the new mails */
 
356
                if ((ret = imap_client_notify_newmails(ctx->client)) == 0)
 
357
                        return 0;
 
358
                if (ret < 0)
 
359
                        ctx->failed = TRUE;
 
360
        }
 
361
 
255
362
        /* send search updates the second time after syncing in done.
256
363
           now it contains added/removed messages. */
257
 
        imap_sync_send_search_updates(ctx);
258
 
 
259
 
        if ((client->enabled_features & MAILBOX_FEATURE_QRESYNC) != 0) {
260
 
                imap_sync_send_highestmodseq(ctx, &status, &sync_status,
261
 
                                             sync_cmd);
262
 
        }
 
364
        if ((ret = imap_sync_send_search_updates(ctx, FALSE)) < 0)
 
365
                ctx->failed = TRUE;
 
366
        return ret;
 
367
}
 
368
 
 
369
int imap_sync_deinit(struct imap_sync_context *ctx,
 
370
                     struct client_command_context *sync_cmd)
 
371
{
 
372
        int ret;
 
373
 
 
374
        ret = imap_sync_finish(ctx, TRUE);
 
375
        imap_client_notify_finished(ctx->client);
 
376
 
 
377
        if ((ctx->client->enabled_features & MAILBOX_FEATURE_QRESYNC) != 0)
 
378
                imap_sync_send_highestmodseq(ctx, sync_cmd);
263
379
 
264
380
        if (array_is_created(&ctx->search_removes)) {
265
381
                array_free(&ctx->search_removes);
306
422
        str_append(str, "FLAGS (");
307
423
        imap_write_flags(str, flags, keywords);
308
424
        str_append(str, "))");
309
 
        return client_send_line(ctx->client, str_c(str));
 
425
        return client_send_line_next(ctx->client, str_c(str));
310
426
}
311
427
 
312
428
static int imap_sync_send_modseq(struct imap_sync_context *ctx, string_t *str)
319
435
                str_printfa(str, "UID %u ", ctx->mail->uid);
320
436
        imap_sync_add_modseq(ctx, str);
321
437
        str_append_c(str, ')');
322
 
        return client_send_line(ctx->client, str_c(str));
 
438
        return client_send_line_next(ctx->client, str_c(str));
323
439
}
324
440
 
325
441
static void imap_sync_vanished(struct imap_sync_context *ctx)
366
482
                        str_printfa(line, ":%u", prev_uid);
367
483
        }
368
484
        str_append(line, "\r\n");
369
 
        o_stream_send(ctx->client->output, str_data(line), str_len(line));
 
485
        o_stream_nsend(ctx->client->output, str_data(line), str_len(line));
 
486
}
 
487
 
 
488
static int imap_sync_send_expunges(struct imap_sync_context *ctx, string_t *str)
 
489
{
 
490
        int ret = 1;
 
491
 
 
492
        if (!ctx->client->notify_count_changes) {
 
493
                /* NOTIFY: MessageEvent not specified for selected mailbox */
 
494
                return 1;
 
495
        }
 
496
 
 
497
        if (array_is_created(&ctx->expunges)) {
 
498
                /* Use a single VANISHED line */
 
499
                seq_range_array_add_range(&ctx->expunges,
 
500
                                          ctx->sync_rec.seq1,
 
501
                                          ctx->sync_rec.seq2);
 
502
                return 1;
 
503
        }
 
504
        if (ctx->seq == 0)
 
505
                ctx->seq = ctx->sync_rec.seq2;
 
506
        for (; ctx->seq >= ctx->sync_rec.seq1; ctx->seq--) {
 
507
                if (ret == 0) {
 
508
                        /* buffer full, continue later */
 
509
                        return 0;
 
510
                }
 
511
 
 
512
                str_truncate(str, 0);
 
513
                str_printfa(str, "* %u EXPUNGE", ctx->seq);
 
514
                ret = client_send_line_next(ctx->client, str_c(str));
 
515
        }
 
516
        return 1;
370
517
}
371
518
 
372
519
int imap_sync_more(struct imap_sync_context *ctx)
374
521
        string_t *str;
375
522
        int ret = 1;
376
523
 
 
524
        if (ctx->finished)
 
525
                return imap_sync_notify_more(ctx);
 
526
 
377
527
        /* finish syncing even when client has disconnected. otherwise our
378
528
           internal state (ctx->messages_count) can get messed up and unless
379
529
           we immediately stop handling all commands and syncs we could end up
405
555
                         ctx->sync_rec.type == MAILBOX_SYNC_TYPE_EXPUNGE);
406
556
                switch (ctx->sync_rec.type) {
407
557
                case MAILBOX_SYNC_TYPE_FLAGS:
 
558
                        if (!ctx->client->notify_flag_changes) {
 
559
                                /* NOTIFY: FlagChange not specified for
 
560
                                   selected mailbox */
 
561
                                break;
 
562
                        }
408
563
                        if (ctx->seq == 0)
409
564
                                ctx->seq = ctx->sync_rec.seq1;
410
565
 
417
572
                        }
418
573
                        break;
419
574
                case MAILBOX_SYNC_TYPE_EXPUNGE:
420
 
                        ctx->client->sync_seen_expunges = TRUE;
421
 
                        if (array_is_created(&ctx->expunges)) {
422
 
                                /* Use a single VANISHED line */
423
 
                                seq_range_array_add_range(&ctx->expunges,
424
 
                                                          ctx->sync_rec.seq1,
425
 
                                                          ctx->sync_rec.seq2);
426
 
                                ctx->messages_count -=
427
 
                                        ctx->sync_rec.seq2 -
428
 
                                        ctx->sync_rec.seq1 + 1;
429
 
                                break;
430
 
                        }
431
 
                        if (ctx->seq == 0)
432
 
                                ctx->seq = ctx->sync_rec.seq2;
433
 
                        ret = 1;
434
 
                        for (; ctx->seq >= ctx->sync_rec.seq1; ctx->seq--) {
435
 
                                if (ret == 0)
436
 
                                        break;
437
 
 
438
 
                                str_truncate(str, 0);
439
 
                                str_printfa(str, "* %u EXPUNGE", ctx->seq);
440
 
                                ret = client_send_line(ctx->client, str_c(str));
441
 
                        }
442
 
                        if (ctx->seq < ctx->sync_rec.seq1) {
 
575
                        ret = imap_sync_send_expunges(ctx, str);
 
576
                        if (ret > 0) {
443
577
                                /* update only after we're finished, so that
444
578
                                   the seq2 > messages_count check above
445
579
                                   doesn't break */
452
586
                        if ((ctx->client->enabled_features &
453
587
                             MAILBOX_FEATURE_CONDSTORE) == 0)
454
588
                                break;
 
589
                        if (!ctx->client->notify_flag_changes) {
 
590
                                /* NOTIFY: FlagChange not specified for
 
591
                                   selected mailbox. The RFC doesn't explicitly
 
592
                                   specify MODSEQ changes, but they're close
 
593
                                   enough to flag changes. */
 
594
                                break;
 
595
                        }
455
596
 
456
597
                        if (ctx->seq == 0)
457
598
                                ctx->seq = ctx->sync_rec.seq1;
472
613
 
473
614
                ctx->seq = 0;
474
615
        }
475
 
        if (array_is_created(&ctx->expunges))
476
 
                imap_sync_vanished(ctx);
 
616
        if (ret > 0) {
 
617
                if (array_is_created(&ctx->expunges))
 
618
                        imap_sync_vanished(ctx);
 
619
                if (imap_sync_finish(ctx, FALSE) < 0)
 
620
                        return -1;
 
621
                return imap_sync_more(ctx);
 
622
        }
477
623
        return ret;
478
624
}
479
625
 
493
639
{
494
640
        if (cmd->sync->callback != NULL)
495
641
                return cmd->sync->callback(cmd);
496
 
        else {
 
642
 
 
643
        if (cmd->sync->tagline != NULL)
497
644
                client_send_tagline(cmd, cmd->sync->tagline);
498
 
                return TRUE;
499
 
        }
 
645
        return TRUE;
500
646
}
501
647
 
502
648
static bool cmd_sync_continue(struct client_command_context *sync_cmd)
580
726
        client->sync_counter++;
581
727
 
582
728
        no_newmail = (client->set->parsed_workarounds & WORKAROUND_DELAY_NEWMAIL) != 0 &&
 
729
                client->notify_ctx == NULL && /* always disabled with NOTIFY */
583
730
                (imap_flags & IMAP_SYNC_FLAG_SAFE) == 0;
584
731
        if (no_newmail) {
585
732
                /* expunges might break the client just as badly as new mail
603
750
        }
604
751
 
605
752
        client_command_free(&sync_cmd);
606
 
        (void)cmd_sync_delayed(client);
 
753
        cmd_sync_delayed(client);
607
754
        return TRUE;
608
755
}
609
756
 
610
 
static bool
 
757
static bool ATTR_NULL(4, 5)
611
758
cmd_sync_full(struct client_command_context *cmd, enum mailbox_sync_flags flags,
612
759
              enum imap_sync_flags imap_flags, const char *tagline,
613
760
              imap_sync_callback_t *callback)
614
761
{
615
762
        struct client *client = cmd->client;
616
763
 
617
 
        i_assert(client->output_lock == cmd || client->output_lock == NULL);
 
764
        i_assert(client->output_cmd_lock == NULL);
618
765
 
619
766
        if (cmd->cancel)
620
767
                return TRUE;
622
769
        if (client->mailbox == NULL) {
623
770
                /* no mailbox selected, no point in delaying the sync */
624
771
                i_assert(callback == NULL);
625
 
                client_send_tagline(cmd, tagline);
 
772
                if (tagline != NULL)
 
773
                        client_send_tagline(cmd, tagline);
626
774
                return TRUE;
627
775
        }
628
776
 
637
785
        cmd->func = NULL;
638
786
        cmd->context = NULL;
639
787
 
640
 
        client->output_lock = NULL;
641
788
        if (client->input_lock == cmd)
642
789
                client->input_lock = NULL;
643
790
        return FALSE;
687
834
{
688
835
        struct client_command_context *cmd, *first_expunge, *first_nonexpunge;
689
836
 
690
 
        if (client->output_lock != NULL) {
 
837
        if (client->output_cmd_lock != NULL) {
691
838
                /* wait until we can send output to client */
692
839
                return FALSE;
693
840
        }