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