imap-sync.c revision 51327f2489a4e0e615eb9f7d921473cf8512bb79
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (c) 2002-2010 Dovecot authors, see the included COPYING file */
b321df9603081896b70ec44635af96d674a9839aTimo Sirainen /* if multiple commands are in progress, we may need to wait for them
9d75363d3fbabc2fbc2d80f06672e3ed8965804aTimo Sirainen to finish before syncing mailbox. */
9d75363d3fbabc2fbc2d80f06672e3ed8965804aTimo Sirainen unsigned int counter;
5c99eaa4e3e07ee065580d163240b4ce95b66befTimo Sirainen ARRAY_TYPE(seq_range) search_adds, search_removes;
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainenstatic void uids_to_seqs(struct mailbox *box, ARRAY_TYPE(seq_range) *uids)
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen mailbox_get_seq_range(box, range->seq1, range->seq2,
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen /* since we have to notify about expunged messages,
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen we expect that all the referenced UIDs exist */
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen i_assert(seq2 - seq1 == range->seq2 - range->seq1);
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen /* replace uids with seqs */
430c0b0c370bebeeceba2e206be76bc134742f41Timo Sirainenimap_sync_send_search_update(struct imap_sync_context *ctx,
430c0b0c370bebeeceba2e206be76bc134742f41Timo Sirainen mailbox_search_result_sync(update->result, &ctx->search_removes,
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen imap_quote_append_string(cmd, update->tag, FALSE);
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen /* convert to sequences */
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen uids_to_seqs(ctx->client->mailbox, &ctx->search_removes);
b4f2560c29dacd066ba89e782d95ceed7ac473a3Timo Sirainen uids_to_seqs(ctx->client->mailbox, &ctx->search_adds);
b4f2560c29dacd066ba89e782d95ceed7ac473a3Timo Sirainen imap_write_seq_range(cmd, &ctx->search_removes);
ac713658d206e8d001fef7c0e36945793f2eb942Timo Sirainen o_stream_send(ctx->client->output, str_data(cmd), str_len(cmd));
ac713658d206e8d001fef7c0e36945793f2eb942Timo Sirainenstatic void imap_sync_send_search_updates(struct imap_sync_context *ctx)
517d1e7142d57299c733b30423e35e7e1f8d01d6Timo Sirainen if (!array_is_created(&ctx->client->search_updates))
446e518e4fe86ff40e33543445f4e99edf840a21Timo Sirainen if (!array_is_created(&ctx->search_removes)) {
446e518e4fe86ff40e33543445f4e99edf840a21Timo Sirainen array_foreach(&ctx->client->search_updates, update) T_BEGIN {
d368bfd671ae6d04a69eb7f418521d49b8bbf77aTimo Sirainenimap_sync_init(struct client *client, struct mailbox *box,
446e518e4fe86ff40e33543445f4e99edf840a21Timo Sirainen enum imap_sync_flags imap_flags, enum mailbox_sync_flags flags)
f968e62caa52a8924bd05ebf76ff515b5c18e17bTimo Sirainen /* make sure user can't DoS the system by causing Dovecot to create
a3dd97fb6d92a89c3de0597fed2d4b044c7aeb84Timo Sirainen tons of useless namespaces. */
a3dd97fb6d92a89c3de0597fed2d4b044c7aeb84Timo Sirainen mail_user_drop_useless_namespaces(client->user);
a3dd97fb6d92a89c3de0597fed2d4b044c7aeb84Timo Sirainen ctx->sync_ctx = mailbox_sync_init(box, flags);
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen ctx->mail = mail_alloc(ctx->t, MAIL_FETCH_FLAGS, 0);
f968e62caa52a8924bd05ebf76ff515b5c18e17bTimo Sirainen i_array_init(&ctx->tmp_keywords, client->keywords.announce_count + 8);
f968e62caa52a8924bd05ebf76ff515b5c18e17bTimo Sirainen if ((client->enabled_features & MAILBOX_FEATURE_QRESYNC) != 0) {
a3dd97fb6d92a89c3de0597fed2d4b044c7aeb84Timo Sirainen /* always send UIDs in FETCH replies */
b24ffea8baa472d9b542e54ed3f9939eefd020adTimo Sirainen /* send search updates the first time after sync is initialized.
b24ffea8baa472d9b542e54ed3f9939eefd020adTimo Sirainen it now contains expunged messages that must be sent before
b24ffea8baa472d9b542e54ed3f9939eefd020adTimo Sirainen EXPUNGE replies. */
4ed1b49d815ec41a5e4b6a23d23e94b958da1923Timo Sirainenimap_sync_send_highestmodseq(struct imap_sync_context *ctx,
b44650b0f48a4b5f0dc240ed836833a00b643b9fTimo Sirainen const struct mailbox_sync_status *sync_status,
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen client->highest_fetch_modseq > client->sync_last_full_modseq) {
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen /* if client updates highest-modseq using returned MODSEQs
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen it loses expunges. try to avoid this by sending it a lower
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen pre-expunge HIGHESTMODSEQ reply. */
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen } else if (!sync_status->sync_delayed_expunges &&
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen status->highest_modseq > client->sync_last_full_modseq &&
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen status->highest_modseq > client->highest_fetch_modseq) {
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen /* we've probably sent some VANISHED or EXISTS replies which
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen increased the highest-modseq. notify the client about
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen /* no sending */
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen } else if (sync_cmd->sync != NULL && /* IDLE doesn't have ->sync */
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen strncmp(sync_cmd->sync->tagline, "OK ", 3) == 0 &&
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen /* modify the tagged reply directly */
0727e38ac12efb8963a339daf56255e2be1f29fcTimo Sirainen sync_cmd->sync->tagline = p_strdup_printf(sync_cmd->pool,
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen "OK [HIGHESTMODSEQ %llu] %s",
8ff9812659728d4166df8e003a1dd3524ae8514eTimo Sirainen (unsigned long long)send_modseq,
966cb0c1aa58578339cea6f79b4a423a851ab074Timo Sirainen /* send an untagged OK reply */
d5abbb932a0a598f002da39a8b3326643b1b5efcTimo Sirainen "* OK [HIGHESTMODSEQ %llu] Highest",
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen (unsigned long long)send_modseq));
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen /* no delayed expunges, remember this for future */
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen client->sync_last_full_modseq = status->highest_modseq;
dd93aba1901a457346990f49c54a738947dc7128Timo Sirainenint imap_sync_deinit(struct imap_sync_context *ctx,
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen if (mailbox_sync_deinit(&ctx->sync_ctx, &sync_status) < 0 ||
e48d89622047bd8bbd0475b881ca9377d592f535Timo Sirainen mailbox_get_open_status(ctx->box, STATUS_UIDVALIDITY |
f3d506e525a720f214020ca0f989a1966b30edaeTimo Sirainen if (status.uidvalidity != client->uidvalidity) {
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen /* most clients would get confused by this. disconnect them. */
849969f639a00eab26791db3cb1b66430420c0cdTimo Sirainen "Mailbox UIDVALIDITY changed");
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen t_strdup_printf("* %u EXISTS", status.messages));
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen t_strdup_printf("* %u RECENT", status.recent));
849969f639a00eab26791db3cb1b66430420c0cdTimo Sirainen /* send search updates the second time after syncing in done.
849969f639a00eab26791db3cb1b66430420c0cdTimo Sirainen now it contains added/removed messages. */
9d75363d3fbabc2fbc2d80f06672e3ed8965804aTimo Sirainen if ((client->enabled_features & MAILBOX_FEATURE_QRESYNC) != 0) {
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen imap_sync_send_highestmodseq(ctx, &status, &sync_status,
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainenstatic void imap_sync_add_modseq(struct imap_sync_context *ctx, string_t *str)
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen if (ctx->client->highest_fetch_modseq < modseq)
2028d80c2704bbf62b29b2c624b0ee3c3a03c462Timo Sirainen str_printfa(str, "MODSEQ (%llu)", (unsigned long long)modseq);
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainenstatic int imap_sync_send_flags(struct imap_sync_context *ctx, string_t *str)
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen const char *const *keywords;
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen keywords = client_get_keyword_names(ctx->client, &ctx->tmp_keywords,
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen if (ctx->imap_flags & IMAP_SYNC_FLAG_SEND_UID)
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen return client_send_line(ctx->client, str_c(str));
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainenstatic int imap_sync_send_modseq(struct imap_sync_context *ctx, string_t *str)
unsigned int i, count;
if (count == 0)
for (i = 0; i < count; i++) {
if (start_uid != 0) {
if (!comma)
prev_uid);
if (!comma)
case MAILBOX_SYNC_TYPE_FLAGS:
if (ret == 0)
if (ret == 0)
case MAILBOX_SYNC_TYPE_MODSEQ:
MAILBOX_FEATURE_CONDSTORE) == 0)
if (ret == 0)
if (ret == 0) {
return ret;
return FALSE;
return FALSE;
return TRUE;
return TRUE;
int ret;
return FALSE;
if (ret < 0)
*flags_r = 0;
*imap_flags_r = 0;
fast_count++;
count++;
bool no_newmail;
if (no_newmail) {
return FALSE;
return TRUE;
return TRUE;
return TRUE;
return FALSE;
return FALSE;
return ret;
return FALSE;