imap-sync.c revision d64280bc41338078701e79aefaab3169686b683d
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2002-2017 Dovecot authors, see the included COPYING file */
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "imap-common.h"
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen#include "str.h"
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen#include "ostream.h"
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen#include "mail-user.h"
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen#include "mail-storage.h"
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen#include "mail-search-build.h"
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen#include "imap-quote.h"
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen#include "imap-util.h"
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen#include "imap-fetch.h"
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen#include "imap-notify.h"
08d6658a4e2ec8104cd1307f6baa75fdb07a24f8Mark Washenberger#include "imap-commands.h"
55d35a8b8036093b94fb1bb0f0339fc43fad52e1Timo Sirainen#include "imap-sync-private.h"
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainenstruct client_sync_context {
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen /* if multiple commands are in progress, we may need to wait for them
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen to finish before syncing mailbox. */
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen unsigned int counter;
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen enum mailbox_sync_flags flags;
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen enum imap_sync_flags imap_flags;
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen const char *tagline;
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen};
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainenstatic void uids_to_seqs(struct mailbox *box, ARRAY_TYPE(seq_range) *uids)
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen{
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen T_BEGIN {
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen ARRAY_TYPE(seq_range) seqs;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen const struct seq_range *range;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen uint32_t seq1, seq2;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen t_array_init(&seqs, array_count(uids));
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen array_foreach(uids, range) {
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen mailbox_get_seq_range(box, range->seq1, range->seq2,
5afa8e2edf4f313cd56e5909f92f39c3b5b7b4d3Timo Sirainen &seq1, &seq2);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen /* since we have to notify about expunged messages,
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen we expect that all the referenced UIDs exist */
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen i_assert(seq1 != 0);
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen i_assert(seq2 - seq1 == range->seq2 - range->seq1);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen seq_range_array_add_range(&seqs, seq1, seq2);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen }
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen /* replace uids with seqs */
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen array_clear(uids);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen array_append_array(uids, &seqs);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen } T_END;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen}
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic int search_update_fetch_more(const struct imap_search_update *update)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen int ret;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if ((ret = imap_fetch_more_no_lock_update(update->fetch_ctx)) <= 0)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return ret;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* finished the FETCH */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (imap_fetch_end(update->fetch_ctx) < 0)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return -1;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return 1;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen}
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic int
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenimap_sync_send_fetch_to_search_update(struct imap_sync_context *ctx,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen const struct imap_search_update *update)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen struct mail_search_args *search_args;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen struct mail_search_arg *arg;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ARRAY_TYPE(seq_range) seqs;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (ctx->search_update_notifying)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return search_update_fetch_more(update);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen i_assert(!update->fetch_ctx->state.fetching);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (array_count(&ctx->search_adds) == 0 || !ctx->have_new_mails)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return 1;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen search_args = mail_search_build_init();
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen arg = mail_search_build_add(search_args, SEARCH_UIDSET);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen p_array_init(&arg->value.seqset, search_args->pool, 1);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* find the newly appended messages: ctx->messages_count is the message
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen count before new messages found by sync, client->messages_count is
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen the number of messages after. */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen t_array_init(&seqs, 1);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen seq_range_array_add_range(&seqs, ctx->messages_count+1,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ctx->client->messages_count);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen mailbox_get_uid_range(ctx->client->mailbox, &seqs, &arg->value.seqset);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* remove messages not in the search_adds list */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen seq_range_array_intersect(&arg->value.seqset, &ctx->search_adds);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen imap_fetch_begin(update->fetch_ctx, ctx->client->mailbox, search_args);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen mail_search_args_unref(&search_args);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return search_update_fetch_more(update);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen}
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic int
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainenimap_sync_send_search_update(struct imap_sync_context *ctx,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen const struct imap_search_update *update,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen bool removes_only)
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen{
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen string_t *cmd;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen int ret = 1;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (!ctx->search_update_notifying) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen mailbox_search_result_sync(update->result, &ctx->search_removes,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen &ctx->search_adds);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen if (array_count(&ctx->search_adds) == 0 &&
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen array_count(&ctx->search_removes) == 0)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return 1;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen i_assert(array_count(&ctx->search_adds) == 0 || !removes_only);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (update->fetch_ctx != NULL) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ret = imap_sync_send_fetch_to_search_update(ctx, update);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (ret == 0) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ctx->search_update_notifying = TRUE;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return 0;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ctx->search_update_notifying = FALSE;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen cmd = t_str_new(256);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen str_append(cmd, "* ESEARCH (TAG ");
686ad6d723004b807fd558f3ef9d1f88afa7e127Timo Sirainen imap_append_string(cmd, update->tag);
303a87c31cb4aa198326694e231df53a043e63c7Timo Sirainen str_append_c(cmd, ')');
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen if (update->return_uids)
303a87c31cb4aa198326694e231df53a043e63c7Timo Sirainen str_append(cmd, " UID");
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen else {
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen /* convert to sequences */
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen uids_to_seqs(ctx->client->mailbox, &ctx->search_removes);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen uids_to_seqs(ctx->client->mailbox, &ctx->search_adds);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen }
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen if (array_count(&ctx->search_removes) != 0) {
303a87c31cb4aa198326694e231df53a043e63c7Timo Sirainen str_printfa(cmd, " REMOVEFROM (0 ");
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen imap_write_seq_range(cmd, &ctx->search_removes);
303a87c31cb4aa198326694e231df53a043e63c7Timo Sirainen str_append_c(cmd, ')');
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen }
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen if (array_count(&ctx->search_adds) != 0) {
303a87c31cb4aa198326694e231df53a043e63c7Timo Sirainen str_printfa(cmd, " ADDTO (0 ");
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen imap_write_seq_range(cmd, &ctx->search_adds);
303a87c31cb4aa198326694e231df53a043e63c7Timo Sirainen str_append_c(cmd, ')');
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen }
f2bd9e507b8befdd95a983f86664febf5c19bd95Timo Sirainen str_append(cmd, "\r\n");
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend(ctx->client->output, str_data(cmd), str_len(cmd));
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return ret;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen}
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic int
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenimap_sync_send_search_updates(struct imap_sync_context *ctx, bool removes_only)
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen const struct imap_search_update *updates;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen unsigned int i, count;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen int ret = 1;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen if (!array_is_created(&ctx->client->search_updates))
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return 1;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen if (!array_is_created(&ctx->search_removes)) {
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen i_array_init(&ctx->search_removes, 64);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen i_array_init(&ctx->search_adds, 128);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen }
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen updates = array_get(&ctx->client->search_updates, &count);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen for (i = ctx->search_update_idx; i < count; i++) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen T_BEGIN {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ret = imap_sync_send_search_update(ctx, &updates[i],
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen removes_only);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen } T_END;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (ret <= 0)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen break;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ctx->search_update_idx = i;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return ret;
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen}
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainenstruct imap_sync_context *
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainenimap_sync_init(struct client *client, struct mailbox *box,
39e6fcc3e8b1ccb13087c232cb6bdea04d1a20a4Timo Sirainen enum imap_sync_flags imap_flags, enum mailbox_sync_flags flags)
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen{
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen struct imap_sync_context *ctx;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen i_assert(client->mailbox == box);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (client->notify_immediate_expunges) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* NOTIFY enabled without SELECTED-DELAYED */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen flags &= ~MAILBOX_SYNC_FLAG_NO_EXPUNGES;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen ctx = i_new(struct imap_sync_context, 1);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen ctx->client = client;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen ctx->box = box;
39e6fcc3e8b1ccb13087c232cb6bdea04d1a20a4Timo Sirainen ctx->imap_flags = imap_flags;
d64280bc41338078701e79aefaab3169686b683dTimo Sirainen i_array_init(&ctx->module_contexts, 5);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen /* make sure user can't DoS the system by causing Dovecot to create
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen tons of useless namespaces. */
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen mail_user_drop_useless_namespaces(client->user);
3398d5e2b883812de5d569721c8294b581e1d9e6Timo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen ctx->sync_ctx = mailbox_sync_init(box, flags);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen ctx->t = mailbox_transaction_begin(box, 0);
cddfd1355db6b60c71d7ee3c0b4f23b3efcc9ad1Timo Sirainen mailbox_transaction_set_reason(ctx->t, "Mailbox sync");
ba5c8b0ae7460752adaf911901bf263788f62c72Phil Carmody ctx->mail = mail_alloc(ctx->t, MAIL_FETCH_FLAGS, NULL);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen ctx->messages_count = client->messages_count;
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainen i_array_init(&ctx->tmp_keywords, client->keywords.announce_count + 8);
bc3698b8892df8003b410daea6f5bbcd20433808Timo Sirainen
06e72c658de3ce1252594b151313df90acf73271Timo Sirainen if ((client->enabled_features & MAILBOX_FEATURE_QRESYNC) != 0) {
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen i_array_init(&ctx->expunges, 128);
06e72c658de3ce1252594b151313df90acf73271Timo Sirainen /* always send UIDs in FETCH replies */
06e72c658de3ce1252594b151313df90acf73271Timo Sirainen ctx->imap_flags |= IMAP_SYNC_FLAG_SEND_UID;
06e72c658de3ce1252594b151313df90acf73271Timo Sirainen }
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainen client_send_mailbox_flags(client, FALSE);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen /* send search updates the first time after sync is initialized.
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen it now contains expunged messages that must be sent before
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen EXPUNGE replies. */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (imap_sync_send_search_updates(ctx, TRUE) == 0)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen i_unreached();
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ctx->search_update_idx = 0;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen return ctx;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen}
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainenstatic void
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainenimap_sync_send_highestmodseq(struct imap_sync_context *ctx,
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen struct client_command_context *sync_cmd)
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen{
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen struct client *client = ctx->client;
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen uint64_t send_modseq = 0;
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (ctx->sync_status.sync_delayed_expunges &&
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen client->highest_fetch_modseq > client->sync_last_full_modseq) {
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen /* if client updates highest-modseq using returned MODSEQs
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen it loses expunges. try to avoid this by sending it a lower
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen pre-expunge HIGHESTMODSEQ reply. */
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen send_modseq = client->sync_last_full_modseq;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen } else if (!ctx->sync_status.sync_delayed_expunges &&
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ctx->status.highest_modseq > client->sync_last_full_modseq &&
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ctx->status.highest_modseq > client->highest_fetch_modseq) {
07974f50bd55b06fd6d465f2c0e491794786e2faTimo Sirainen /* we've probably sent some VANISHED or EXISTS replies which
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen increased the highest-modseq. notify the client about
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen this. */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen send_modseq = ctx->status.highest_modseq;
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen }
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen if (send_modseq == 0) {
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen /* no sending */
07974f50bd55b06fd6d465f2c0e491794786e2faTimo Sirainen } else if (sync_cmd->sync != NULL && /* IDLE doesn't have ->sync */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen sync_cmd->sync->tagline != NULL && /* NOTIFY doesn't have tagline */
07974f50bd55b06fd6d465f2c0e491794786e2faTimo Sirainen strncmp(sync_cmd->sync->tagline, "OK ", 3) == 0 &&
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen sync_cmd->sync->tagline[3] != '[') {
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen /* modify the tagged reply directly */
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen sync_cmd->sync->tagline = p_strdup_printf(sync_cmd->pool,
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen "OK [HIGHESTMODSEQ %llu] %s",
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen (unsigned long long)send_modseq,
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen sync_cmd->sync->tagline + 3);
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen } else {
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen /* send an untagged OK reply */
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen client_send_line(client, t_strdup_printf(
2d9644d34a78b24dc7769cd96497e700a0fb1cf1Timo Sirainen "* OK [HIGHESTMODSEQ %llu] Highest",
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen (unsigned long long)send_modseq));
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen }
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (!ctx->sync_status.sync_delayed_expunges) {
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen /* no delayed expunges, remember this for future */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client->sync_last_full_modseq = ctx->status.highest_modseq;
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen }
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen client->highest_fetch_modseq = 0;
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen}
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen
270f00aeab7bede38764291e21a314211b884ab4Timo Sirainenstatic int imap_sync_finish(struct imap_sync_context *ctx, bool aborting)
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen{
17da42c31202b1b3e7e308121ea17d922c24da1bTimo Sirainen struct client *client = ctx->client;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen int ret = ctx->failed ? -1 : 0;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (ctx->finished)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return ret;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ctx->finished = TRUE;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen mail_free(&ctx->mail);
7891195e3975d554df183670dba1fcecfa0a30c3Timo Sirainen /* the transaction is used only for fetching modseqs/flags.
7891195e3975d554df183670dba1fcecfa0a30c3Timo Sirainen it can't really fail.. */
7891195e3975d554df183670dba1fcecfa0a30c3Timo Sirainen (void)mailbox_transaction_commit(&ctx->t);
7891195e3975d554df183670dba1fcecfa0a30c3Timo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (array_is_created(&ctx->expunges))
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen array_free(&ctx->expunges);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (mailbox_sync_deinit(&ctx->sync_ctx, &ctx->sync_status) < 0 ||
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen ctx->failed) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ctx->failed = TRUE;
89b3a53140d31bfa0f34378bf7ee1f52da954961Timo Sirainen ret = -1;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen }
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen mailbox_get_open_status(ctx->box, STATUS_UIDVALIDITY |
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainen STATUS_MESSAGES | STATUS_RECENT |
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen STATUS_HIGHESTMODSEQ, &ctx->status);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (ctx->status.uidvalidity != client->uidvalidity) {
bd74402ca1a39ec303075fefb1212d7e18a71531Timo Sirainen /* most clients would get confused by this. disconnect them. */
17da42c31202b1b3e7e308121ea17d922c24da1bTimo Sirainen client_disconnect_with_error(client,
bd74402ca1a39ec303075fefb1212d7e18a71531Timo Sirainen "Mailbox UIDVALIDITY changed");
bd74402ca1a39ec303075fefb1212d7e18a71531Timo Sirainen }
505561860cdfee4eac51469fd27a59983ef72e8eTimo Sirainen if (mailbox_is_inconsistent(ctx->box)) {
505561860cdfee4eac51469fd27a59983ef72e8eTimo Sirainen client_disconnect_with_error(client,
505561860cdfee4eac51469fd27a59983ef72e8eTimo Sirainen "IMAP session state is inconsistent, please relogin.");
505561860cdfee4eac51469fd27a59983ef72e8eTimo Sirainen /* we can't trust status information anymore, so don't try to
505561860cdfee4eac51469fd27a59983ef72e8eTimo Sirainen sync message counts. */
505561860cdfee4eac51469fd27a59983ef72e8eTimo Sirainen return -1;
505561860cdfee4eac51469fd27a59983ef72e8eTimo Sirainen }
270f00aeab7bede38764291e21a314211b884ab4Timo Sirainen if (!ctx->no_newmail && !aborting) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (ctx->status.messages < ctx->messages_count)
c6ae908f6a2313573625d782bdd4e0ff3882c44aTimo Sirainen i_panic("Message count decreased");
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (ctx->status.messages != ctx->messages_count &&
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client->notify_count_changes) {
17da42c31202b1b3e7e308121ea17d922c24da1bTimo Sirainen client_send_line(client,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen t_strdup_printf("* %u EXISTS", ctx->status.messages));
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ctx->have_new_mails = TRUE;
ef11d3930c3602fc86349a4e3a53442df470b601Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (ctx->status.recent != client->recent_count &&
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client->notify_count_changes) {
17da42c31202b1b3e7e308121ea17d922c24da1bTimo Sirainen client_send_line(client,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen t_strdup_printf("* %u RECENT", ctx->status.recent));
ef11d3930c3602fc86349a4e3a53442df470b601Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client->messages_count = ctx->status.messages;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client->recent_count = ctx->status.recent;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return ret;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen}
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic int imap_sync_notify_more(struct imap_sync_context *ctx)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen int ret = 1;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (ctx->have_new_mails && ctx->client->notify_ctx != NULL) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* send FETCH replies for the new mails */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if ((ret = imap_client_notify_newmails(ctx->client)) == 0)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return 0;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (ret < 0)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ctx->failed = TRUE;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen /* send search updates the second time after syncing in done.
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen now it contains added/removed messages. */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if ((ret = imap_sync_send_search_updates(ctx, FALSE)) < 0)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ctx->failed = TRUE;
d64280bc41338078701e79aefaab3169686b683dTimo Sirainen
d64280bc41338078701e79aefaab3169686b683dTimo Sirainen if (ret > 0)
d64280bc41338078701e79aefaab3169686b683dTimo Sirainen ret = ctx->client->v.sync_notify_more(ctx);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return ret;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen}
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenint imap_sync_deinit(struct imap_sync_context *ctx,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen struct client_command_context *sync_cmd)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen int ret;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
270f00aeab7bede38764291e21a314211b884ab4Timo Sirainen ret = imap_sync_finish(ctx, TRUE);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen imap_client_notify_finished(ctx->client);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
59714981ae172b5113be7ca9b8be518b759fc86dTimo Sirainen if ((ctx->client->enabled_features & MAILBOX_FEATURE_QRESYNC) != 0 &&
59714981ae172b5113be7ca9b8be518b759fc86dTimo Sirainen !ctx->client->nonpermanent_modseqs)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen imap_sync_send_highestmodseq(ctx, sync_cmd);
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen if (array_is_created(&ctx->search_removes)) {
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen array_free(&ctx->search_removes);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen array_free(&ctx->search_adds);
3dd0679b6f24be0287cc42d7a60bbf59cdf8b637Timo Sirainen }
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainen array_free(&ctx->tmp_keywords);
d64280bc41338078701e79aefaab3169686b683dTimo Sirainen array_free(&ctx->module_contexts);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen i_free(ctx);
ccb77e2f63626ec46e5745ef4f38baa8e8e504fcTimo Sirainen return ret;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen}
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainenstatic void imap_sync_add_modseq(struct imap_sync_context *ctx, string_t *str)
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen{
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen uint64_t modseq;
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen modseq = mail_get_modseq(ctx->mail);
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen if (ctx->client->highest_fetch_modseq < modseq)
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen ctx->client->highest_fetch_modseq = modseq;
6384258c2f84e635d8ceffc3eeddad71f7538040Timo Sirainen str_printfa(str, "MODSEQ (%llu)", (unsigned long long)modseq);
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen}
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainenstatic int imap_sync_send_flags(struct imap_sync_context *ctx, string_t *str)
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen{
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen enum mail_flags flags;
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainen const char *const *keywords;
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen mail_set_seq(ctx->mail, ctx->seq);
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen flags = mail_get_flags(ctx->mail);
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainen keywords = client_get_keyword_names(ctx->client, &ctx->tmp_keywords,
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainen mail_get_keyword_indexes(ctx->mail));
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen if ((flags & MAIL_DELETED) != 0)
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen ctx->client->sync_seen_deletes = TRUE;
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen str_truncate(str, 0);
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen str_printfa(str, "* %u FETCH (", ctx->seq);
23bdbb7b1831785c6ba6df190f6369da882d2b9dTimo Sirainen if ((ctx->imap_flags & IMAP_SYNC_FLAG_SEND_UID) != 0)
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen str_printfa(str, "UID %u ", ctx->mail->uid);
45c763dbebee268eda4a1e8bcc1ff82606b5ed0dTimo Sirainen if ((ctx->client->enabled_features & MAILBOX_FEATURE_CONDSTORE) != 0 &&
59714981ae172b5113be7ca9b8be518b759fc86dTimo Sirainen !ctx->client->nonpermanent_modseqs) {
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen imap_sync_add_modseq(ctx, str);
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen str_append_c(str, ' ');
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen }
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen str_append(str, "FLAGS (");
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainen imap_write_flags(str, flags, keywords);
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen str_append(str, "))");
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen return client_send_line_next(ctx->client, str_c(str));
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen}
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainenstatic int imap_sync_send_modseq(struct imap_sync_context *ctx, string_t *str)
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen{
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen mail_set_seq(ctx->mail, ctx->seq);
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen str_truncate(str, 0);
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen str_printfa(str, "* %u FETCH (", ctx->seq);
23bdbb7b1831785c6ba6df190f6369da882d2b9dTimo Sirainen if ((ctx->imap_flags & IMAP_SYNC_FLAG_SEND_UID) != 0)
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen str_printfa(str, "UID %u ", ctx->mail->uid);
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen imap_sync_add_modseq(ctx, str);
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen str_append_c(str, ')');
e34d170f8f0e084bd94bfbc1a7085ece67e508dfTimo Sirainen return client_send_line_next(ctx->client, str_c(str));
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen}
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainenstatic void imap_sync_vanished(struct imap_sync_context *ctx)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen{
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen const struct seq_range *seqs;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen unsigned int i, count;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen string_t *line;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen uint32_t seq, prev_uid, start_uid;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen bool comma = FALSE;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen /* Convert expunge sequences to UIDs and send them in VANISHED line. */
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen seqs = array_get(&ctx->expunges, &count);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (count == 0)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen return;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen line = t_str_new(256);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen str_append(line, "* VANISHED ");
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen for (i = 0; i < count; i++) {
c8625391da3ee51b31e69b88895708a3d149dd1bTimo Sirainen start_uid = 0; prev_uid = (uint32_t)-1;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen for (seq = seqs[i].seq1; seq <= seqs[i].seq2; seq++) {
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen mail_set_seq(ctx->mail, seq);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (prev_uid + 1 != ctx->mail->uid) {
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (start_uid != 0) {
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (!comma)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen comma = TRUE;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen else
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen str_append_c(line, ',');
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen str_printfa(line, "%u", start_uid);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (start_uid != prev_uid) {
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen str_printfa(line, ":%u",
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen prev_uid);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen }
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen }
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen start_uid = ctx->mail->uid;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen }
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen prev_uid = ctx->mail->uid;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen }
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (!comma)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen comma = TRUE;
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen else
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen str_append_c(line, ',');
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen str_printfa(line, "%u", start_uid);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen if (start_uid != prev_uid)
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen str_printfa(line, ":%u", prev_uid);
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen }
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen str_append(line, "\r\n");
e2a88d59c0d47d63ce1ad5b1fd95e487124a3fd4Timo Sirainen o_stream_nsend(ctx->client->output, str_data(line), str_len(line));
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen}
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainenstatic int imap_sync_send_expunges(struct imap_sync_context *ctx, string_t *str)
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen{
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen int ret = 1;
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (!ctx->client->notify_count_changes) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* NOTIFY: MessageEvent not specified for selected mailbox */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return 1;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen if (array_is_created(&ctx->expunges)) {
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen /* Use a single VANISHED line */
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen seq_range_array_add_range(&ctx->expunges,
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen ctx->sync_rec.seq1,
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen ctx->sync_rec.seq2);
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen return 1;
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen }
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen if (ctx->seq == 0)
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen ctx->seq = ctx->sync_rec.seq2;
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen for (; ctx->seq >= ctx->sync_rec.seq1; ctx->seq--) {
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen if (ret == 0) {
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen /* buffer full, continue later */
270f00aeab7bede38764291e21a314211b884ab4Timo Sirainen return 0;
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen }
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen str_truncate(str, 0);
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen str_printfa(str, "* %u EXPUNGE", ctx->seq);
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen ret = client_send_line_next(ctx->client, str_c(str));
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen }
270f00aeab7bede38764291e21a314211b884ab4Timo Sirainen return 1;
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen}
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainenint imap_sync_more(struct imap_sync_context *ctx)
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen{
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen string_t *str;
68efcccb384f2d6871164b072457e87473502c51Timo Sirainen int ret = 1;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (ctx->finished)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return imap_sync_notify_more(ctx);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
0b7651dc6ad21cce8579b5957252ae0daf972668Timo Sirainen /* finish syncing even when client has disconnected. otherwise our
0b7651dc6ad21cce8579b5957252ae0daf972668Timo Sirainen internal state (ctx->messages_count) can get messed up and unless
0b7651dc6ad21cce8579b5957252ae0daf972668Timo Sirainen we immediately stop handling all commands and syncs we could end up
0b7651dc6ad21cce8579b5957252ae0daf972668Timo Sirainen assert-crashing. */
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen str = t_str_new(256);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen for (;;) {
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen if (ctx->seq == 0) {
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen /* get next one */
c979eeda1f46483d9c963e265786b701d7683d77Timo Sirainen if (!mailbox_sync_next(ctx->sync_ctx, &ctx->sync_rec)) {
c979eeda1f46483d9c963e265786b701d7683d77Timo Sirainen /* finished */
c979eeda1f46483d9c963e265786b701d7683d77Timo Sirainen ret = 1;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen break;
68efcccb384f2d6871164b072457e87473502c51Timo Sirainen }
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen }
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
a54be2bd26d6f0860d194d3aeedfa6b7fc14d24cTimo Sirainen if (ctx->sync_rec.seq2 > ctx->messages_count) {
a54be2bd26d6f0860d194d3aeedfa6b7fc14d24cTimo Sirainen /* don't send change notifications of messages we
a54be2bd26d6f0860d194d3aeedfa6b7fc14d24cTimo Sirainen haven't even announced to client yet */
10cfe8a2bdc5ccfc05380689c71c27209327538fTimo Sirainen if (ctx->sync_rec.seq1 > ctx->messages_count) {
10cfe8a2bdc5ccfc05380689c71c27209327538fTimo Sirainen ctx->seq = 0;
a54be2bd26d6f0860d194d3aeedfa6b7fc14d24cTimo Sirainen continue;
10cfe8a2bdc5ccfc05380689c71c27209327538fTimo Sirainen }
a54be2bd26d6f0860d194d3aeedfa6b7fc14d24cTimo Sirainen ctx->sync_rec.seq2 = ctx->messages_count;
a54be2bd26d6f0860d194d3aeedfa6b7fc14d24cTimo Sirainen }
a54be2bd26d6f0860d194d3aeedfa6b7fc14d24cTimo Sirainen
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen /* EXPUNGEs must come last */
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen i_assert(!array_is_created(&ctx->expunges) ||
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen array_count(&ctx->expunges) == 0 ||
923eb3dde28e4d8841c14fd6b4a69635b7070c3eTimo Sirainen ctx->sync_rec.type == MAILBOX_SYNC_TYPE_EXPUNGE);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen switch (ctx->sync_rec.type) {
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen case MAILBOX_SYNC_TYPE_FLAGS:
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (!ctx->client->notify_flag_changes) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* NOTIFY: FlagChange not specified for
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen selected mailbox */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen break;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen if (ctx->seq == 0)
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen ctx->seq = ctx->sync_rec.seq1;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainen ret = 1;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen for (; ctx->seq <= ctx->sync_rec.seq2; ctx->seq++) {
0b7651dc6ad21cce8579b5957252ae0daf972668Timo Sirainen if (ret == 0)
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainen break;
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainen
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainen ret = imap_sync_send_flags(ctx, str);
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen }
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen break;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen case MAILBOX_SYNC_TYPE_EXPUNGE:
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen ret = imap_sync_send_expunges(ctx, str);
85ee28daca146e18a99a22f46c0d639e57a6ac95Timo Sirainen if (ret > 0) {
d42c9a8f362b76740418c4f9f9441eb7fc661e57Timo Sirainen /* update only after we're finished, so that
d42c9a8f362b76740418c4f9f9441eb7fc661e57Timo Sirainen the seq2 > messages_count check above
d42c9a8f362b76740418c4f9f9441eb7fc661e57Timo Sirainen doesn't break */
d42c9a8f362b76740418c4f9f9441eb7fc661e57Timo Sirainen ctx->messages_count -=
d42c9a8f362b76740418c4f9f9441eb7fc661e57Timo Sirainen ctx->sync_rec.seq2 -
d42c9a8f362b76740418c4f9f9441eb7fc661e57Timo Sirainen ctx->sync_rec.seq1 + 1;
d42c9a8f362b76740418c4f9f9441eb7fc661e57Timo Sirainen }
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen break;
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen case MAILBOX_SYNC_TYPE_MODSEQ:
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen if ((ctx->client->enabled_features &
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen MAILBOX_FEATURE_CONDSTORE) == 0)
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen break;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (!ctx->client->notify_flag_changes) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* NOTIFY: FlagChange not specified for
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen selected mailbox. The RFC doesn't explicitly
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen specify MODSEQ changes, but they're close
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen enough to flag changes. */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen break;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen if (ctx->seq == 0)
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen ctx->seq = ctx->sync_rec.seq1;
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen ret = 1;
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen for (; ctx->seq <= ctx->sync_rec.seq2; ctx->seq++) {
0b7651dc6ad21cce8579b5957252ae0daf972668Timo Sirainen if (ret == 0)
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen break;
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen ret = imap_sync_send_modseq(ctx, str);
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen }
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen break;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen }
0b7651dc6ad21cce8579b5957252ae0daf972668Timo Sirainen if (ret == 0) {
0b7651dc6ad21cce8579b5957252ae0daf972668Timo Sirainen /* buffer full */
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainen break;
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainen }
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainen
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen ctx->seq = 0;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (ret > 0) {
270f00aeab7bede38764291e21a314211b884ab4Timo Sirainen if (array_is_created(&ctx->expunges))
270f00aeab7bede38764291e21a314211b884ab4Timo Sirainen imap_sync_vanished(ctx);
270f00aeab7bede38764291e21a314211b884ab4Timo Sirainen if (imap_sync_finish(ctx, FALSE) < 0)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return -1;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return imap_sync_more(ctx);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
68efcccb384f2d6871164b072457e87473502c51Timo Sirainen return ret;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen}
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen
5735ada0f82788ee1b5228978d5bd8dad5a04219Timo Sirainenbool imap_sync_is_allowed(struct client *client)
5735ada0f82788ee1b5228978d5bd8dad5a04219Timo Sirainen{
5735ada0f82788ee1b5228978d5bd8dad5a04219Timo Sirainen if (client->syncing)
5735ada0f82788ee1b5228978d5bd8dad5a04219Timo Sirainen return FALSE;
5735ada0f82788ee1b5228978d5bd8dad5a04219Timo Sirainen
5735ada0f82788ee1b5228978d5bd8dad5a04219Timo Sirainen if (client->mailbox != NULL &&
5735ada0f82788ee1b5228978d5bd8dad5a04219Timo Sirainen mailbox_transaction_get_count(client->mailbox) > 0)
5735ada0f82788ee1b5228978d5bd8dad5a04219Timo Sirainen return FALSE;
5735ada0f82788ee1b5228978d5bd8dad5a04219Timo Sirainen
5735ada0f82788ee1b5228978d5bd8dad5a04219Timo Sirainen return TRUE;
5735ada0f82788ee1b5228978d5bd8dad5a04219Timo Sirainen}
5735ada0f82788ee1b5228978d5bd8dad5a04219Timo Sirainen
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainenstatic bool cmd_finish_sync(struct client_command_context *cmd)
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (cmd->sync->tagline != NULL)
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen client_send_tagline(cmd, cmd->sync->tagline);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return TRUE;
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen}
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainenstatic bool cmd_sync_continue(struct client_command_context *sync_cmd)
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen{
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainen struct client_command_context *cmd, *prev;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen struct client *client = sync_cmd->client;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen struct imap_sync_context *ctx = sync_cmd->context;
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainen int ret;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen i_assert(ctx->client == client);
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen if ((ret = imap_sync_more(ctx)) == 0)
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen return FALSE;
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainen if (ret < 0)
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen ctx->failed = TRUE;
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainen
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen client->syncing = FALSE;
28cd2599128e102198758cf6080588305feb6bcdTimo Sirainen if (imap_sync_deinit(ctx, sync_cmd) < 0) {
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen client_send_untagged_storage_error(client,
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen mailbox_get_storage(client->mailbox));
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen }
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen sync_cmd->context = NULL;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainen /* Finish all commands that waited for this sync. Go through the queue
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainen backwards, so that tagged replies are sent in the same order as
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainen they were received. This fixes problems with clients that rely on
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainen this (Apple Mail 3.2) */
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainen for (cmd = client->command_queue; cmd->next != NULL; cmd = cmd->next) ;
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainen for (; cmd != NULL; cmd = prev) {
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainen prev = cmd->prev;
3419b088ffe531799bdb47b3ff3fce85c8b7569aTimo Sirainen
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen if (cmd->state == CLIENT_COMMAND_STATE_WAIT_SYNC &&
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen cmd != sync_cmd &&
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen cmd->sync->counter+1 == client->sync_counter) {
71caf493c651b8eab5adb170db0237f293928e92Timo Sirainen cmd_finish_sync(cmd);
71caf493c651b8eab5adb170db0237f293928e92Timo Sirainen client_command_free(&cmd);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen }
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen }
71caf493c651b8eab5adb170db0237f293928e92Timo Sirainen cmd_finish_sync(sync_cmd);
71caf493c651b8eab5adb170db0237f293928e92Timo Sirainen return TRUE;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen}
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainenstatic void get_common_sync_flags(struct client *client,
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen enum mailbox_sync_flags *flags_r,
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen enum imap_sync_flags *imap_flags_r)
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen{
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen struct client_command_context *cmd;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen unsigned int count = 0, fast_count = 0, noexpunges_count = 0;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen *flags_r = 0;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen *imap_flags_r = 0;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen for (cmd = client->command_queue; cmd != NULL; cmd = cmd->next) {
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen if (cmd->sync != NULL &&
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen cmd->sync->counter == client->sync_counter) {
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen if ((cmd->sync->flags & MAILBOX_SYNC_FLAG_FAST) != 0)
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen fast_count++;
23bdbb7b1831785c6ba6df190f6369da882d2b9dTimo Sirainen if ((cmd->sync->flags & MAILBOX_SYNC_FLAG_NO_EXPUNGES) != 0)
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen noexpunges_count++;
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen *flags_r |= cmd->sync->flags;
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen *imap_flags_r |= cmd->sync->imap_flags;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen count++;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen }
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen }
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen i_assert(noexpunges_count == 0 || noexpunges_count == count);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen if (fast_count != count)
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen *flags_r &= ~MAILBOX_SYNC_FLAG_FAST;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
2372e16bfae0a245bfde6e908cde0919aa11ee0bTimo Sirainen i_assert((*flags_r & MAILBOX_SYNC_FLAG_FIX_INCONSISTENT) == 0);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen}
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainenstatic bool cmd_sync_client(struct client_command_context *sync_cmd)
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen{
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen struct client *client = sync_cmd->client;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen struct imap_sync_context *ctx;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen enum mailbox_sync_flags flags;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen enum imap_sync_flags imap_flags;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen bool no_newmail;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen /* there may be multiple commands waiting. use their combined flags */
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen get_common_sync_flags(client, &flags, &imap_flags);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen client->sync_counter++;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
a8284e999d091cd29210fa75ecdc8076376a7345Timo Sirainen no_newmail = (client->set->parsed_workarounds & WORKAROUND_DELAY_NEWMAIL) != 0 &&
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client->notify_ctx == NULL && /* always disabled with NOTIFY */
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen (imap_flags & IMAP_SYNC_FLAG_SAFE) == 0;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen if (no_newmail) {
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen /* expunges might break the client just as badly as new mail
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen notifications. */
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen flags |= MAILBOX_SYNC_FLAG_NO_EXPUNGES;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen }
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen client->syncing = TRUE;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen ctx = imap_sync_init(client, client->mailbox, imap_flags, flags);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen ctx->no_newmail = no_newmail;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen /* handle the syncing using sync_cmd. it doesn't actually matter which
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen one of the pending commands it is. */
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen sync_cmd->func = cmd_sync_continue;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen sync_cmd->context = ctx;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen sync_cmd->state = CLIENT_COMMAND_STATE_WAIT_OUTPUT;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen if (!cmd_sync_continue(sync_cmd)) {
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen o_stream_set_flush_pending(client->output, TRUE);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen return FALSE;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen }
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
2d340205d897e23fbecb40c8e63a4ca49bd6739bTimo Sirainen client_command_free(&sync_cmd);
b66d803de86bfb411165b3465b0d9ef64ecfe2a1Timo Sirainen cmd_sync_delayed(client);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen return TRUE;
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen}
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
71caf493c651b8eab5adb170db0237f293928e92Timo Sirainenbool cmd_sync(struct client_command_context *cmd, enum mailbox_sync_flags flags,
71caf493c651b8eab5adb170db0237f293928e92Timo Sirainen enum imap_sync_flags imap_flags, const char *tagline)
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen{
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen struct client *client = cmd->client;
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen
5a7acd67806132cbc1ec9578df60d712d307e4beTimo Sirainen i_assert(client->output_cmd_lock == NULL);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen if (cmd->cancel)
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen return TRUE;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
567b56c2d6a1063cad997c956f3ed1d9d735f14eTimo Sirainen cmd->stats.last_run_timeval = ioloop_timeval;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen if (client->mailbox == NULL) {
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen /* no mailbox selected, no point in delaying the sync */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (tagline != NULL)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen client_send_tagline(cmd, tagline);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen return TRUE;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen }
362db49a9acfb297266cb9a09600689dcffce3ccTimo Sirainen cmd->tagline_reply = p_strdup(cmd->pool, tagline);
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen cmd->sync = p_new(cmd->pool, struct client_sync_context, 1);
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen cmd->sync->counter = client->sync_counter;
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen cmd->sync->flags = flags;
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen cmd->sync->imap_flags = imap_flags;
362db49a9acfb297266cb9a09600689dcffce3ccTimo Sirainen cmd->sync->tagline = cmd->tagline_reply;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen cmd->state = CLIENT_COMMAND_STATE_WAIT_SYNC;
294f1a51763015cda0e2d874c5027d6fe7a2cd54Timo Sirainen
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen cmd->func = NULL;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen cmd->context = NULL;
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen if (client->input_lock == cmd)
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen client->input_lock = NULL;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen return FALSE;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen}
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainenstatic bool cmd_sync_drop_fast(struct client *client)
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen{
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainen struct client_command_context *cmd, *prev;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen bool ret = FALSE;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainen if (client->command_queue == NULL)
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainen return FALSE;
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainen
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainen for (cmd = client->command_queue; cmd->next != NULL; cmd = cmd->next) ;
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainen for (; cmd != NULL; cmd = prev) {
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainen prev = cmd->next;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen if (cmd->state != CLIENT_COMMAND_STATE_WAIT_SYNC)
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen continue;
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen i_assert(cmd->sync != NULL);
35283613d4c04ce18836e9fc431582c87b3710a0Timo Sirainen if ((cmd->sync->flags & MAILBOX_SYNC_FLAG_FAST) != 0) {
71caf493c651b8eab5adb170db0237f293928e92Timo Sirainen cmd_finish_sync(cmd);
71caf493c651b8eab5adb170db0237f293928e92Timo Sirainen client_command_free(&cmd);
71caf493c651b8eab5adb170db0237f293928e92Timo Sirainen ret = TRUE;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen }
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen }
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen return ret;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen}
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
d2470b3dfe91ca07459185384ee25080b42a1636Timo Sirainenstatic bool cmd_sync_delayed_real(struct client *client)
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen{
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen struct client_command_context *cmd, *first_expunge, *first_nonexpunge;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
5a7acd67806132cbc1ec9578df60d712d307e4beTimo Sirainen if (client->output_cmd_lock != NULL) {
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen /* wait until we can send output to client */
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen return FALSE;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen }
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
5735ada0f82788ee1b5228978d5bd8dad5a04219Timo Sirainen if (!imap_sync_is_allowed(client)) {
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen /* wait until mailbox can be synced */
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen return cmd_sync_drop_fast(client);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen }
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen /* separate syncs that can send expunges from those that can't */
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen first_expunge = first_nonexpunge = NULL;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen for (cmd = client->command_queue; cmd != NULL; cmd = cmd->next) {
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen if (cmd->sync != NULL &&
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen cmd->sync->counter == client->sync_counter) {
23bdbb7b1831785c6ba6df190f6369da882d2b9dTimo Sirainen if ((cmd->sync->flags & MAILBOX_SYNC_FLAG_NO_EXPUNGES) != 0) {
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen if (first_nonexpunge == NULL)
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen first_nonexpunge = cmd;
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen } else {
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen if (first_expunge == NULL)
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen first_expunge = cmd;
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen }
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen }
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen }
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen if (first_expunge != NULL && first_nonexpunge != NULL) {
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen /* sync expunges after nonexpunges */
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen for (cmd = first_expunge; cmd != NULL; cmd = cmd->next) {
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen if (cmd->sync != NULL &&
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen cmd->sync->counter == client->sync_counter &&
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen (cmd->sync->flags &
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen MAILBOX_SYNC_FLAG_NO_EXPUNGES) == 0)
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen cmd->sync->counter++;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen }
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen first_expunge = NULL;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen }
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen cmd = first_nonexpunge != NULL ? first_nonexpunge : first_expunge;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen if (cmd == NULL)
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen return cmd_sync_drop_fast(client);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen i_assert(client->mailbox != NULL);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen return cmd_sync_client(cmd);
d756ebcfa96bd7cff02097c8f26df9df368b81b1Timo Sirainen}
d2470b3dfe91ca07459185384ee25080b42a1636Timo Sirainen
d2470b3dfe91ca07459185384ee25080b42a1636Timo Sirainenbool cmd_sync_delayed(struct client *client)
d2470b3dfe91ca07459185384ee25080b42a1636Timo Sirainen{
d2470b3dfe91ca07459185384ee25080b42a1636Timo Sirainen bool ret;
d2470b3dfe91ca07459185384ee25080b42a1636Timo Sirainen
d2470b3dfe91ca07459185384ee25080b42a1636Timo Sirainen T_BEGIN {
d2470b3dfe91ca07459185384ee25080b42a1636Timo Sirainen ret = cmd_sync_delayed_real(client);
d2470b3dfe91ca07459185384ee25080b42a1636Timo Sirainen } T_END;
d2470b3dfe91ca07459185384ee25080b42a1636Timo Sirainen return ret;
d2470b3dfe91ca07459185384ee25080b42a1636Timo Sirainen}