imap-sync.c revision 1939d1843ee6c7ca5e5baa3967b0332341440005
76b43e4417bab52e913da39b5f5bc2a130d3f149Timo Sirainen/* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */
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;
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 ctx->sync_ctx = mailbox_sync_init(box, flags);
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen ctx->mail = mail_alloc(ctx->t, MAIL_FETCH_FLAGS, 0);
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainen i_array_init(&ctx->tmp_keywords, client->keywords.announce_count + 8);
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainenint imap_sync_deinit(struct imap_sync_context *ctx)
bd74402ca1a39ec303075fefb1212d7e18a71531Timo Sirainen if (mailbox_sync_deinit(&ctx->sync_ctx, STATUS_UIDVALIDITY |
5fb3bff645380804c9db2510940c41db6b8fdb01Timo Sirainen STATUS_MESSAGES | STATUS_RECENT, &status) < 0 ||
bd74402ca1a39ec303075fefb1212d7e18a71531Timo Sirainen if (status.uidvalidity != ctx->client->uidvalidity) {
bd74402ca1a39ec303075fefb1212d7e18a71531Timo Sirainen /* most clients would get confused by this. disconnect them. */
bd74402ca1a39ec303075fefb1212d7e18a71531Timo Sirainen "Mailbox UIDVALIDITY changed");
150e64c376365becf1ec5c9d45912ecb840eea96Timo Sirainen ctx->client->messages_count = status.messages;
ef11d3930c3602fc86349a4e3a53442df470b601Timo Sirainen t_strdup_printf("* %u EXISTS", status.messages));
17b03c9db961e1c004284907d969eb11b08a795eTimo Sirainen if (status.recent != ctx->client->recent_count &&
ef11d3930c3602fc86349a4e3a53442df470b601Timo Sirainen t_strdup_printf("* %u RECENT", status.recent));
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainenstatic int imap_sync_send_flags(struct imap_sync_context *ctx, string_t *str)
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainen const char *const *keywords;
8039af9679af6fb56116b353fe44f7dd4c08f031Timo Sirainen keywords = client_get_keyword_names(ctx->client, &ctx->tmp_keywords,
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen if (ctx->imap_flags & IMAP_SYNC_FLAG_SEND_UID)
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainen return client_send_line(ctx->client, str_c(str));
a4bc2c3962b94f83c7bb7bebe7af364f4dee7883Timo Sirainenint imap_sync_more(struct imap_sync_context *ctx)
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen /* get next one */
c979eeda1f46483d9c963e265786b701d7683d77Timo Sirainen if (!mailbox_sync_next(ctx->sync_ctx, &ctx->sync_rec)) {
c979eeda1f46483d9c963e265786b701d7683d77Timo Sirainen /* finished */
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) {
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen for (; ctx->seq <= ctx->sync_rec.seq2; ctx->seq++) {
c4267cf4c40fb1f866b5958ff122ef836b8c5dfbTimo Sirainen for (; ctx->seq >= ctx->sync_rec.seq1; ctx->seq--) {
68efcccb384f2d6871164b072457e87473502c51Timo Sirainen ret = client_send_line(ctx->client, str_c(str));
d42c9a8f362b76740418c4f9f9441eb7fc661e57Timo Sirainen /* update only after we're finished, so that
d42c9a8f362b76740418c4f9f9441eb7fc661e57Timo Sirainen the seq2 > messages_count check above
d42c9a8f362b76740418c4f9f9441eb7fc661e57Timo Sirainen doesn't break */
88286b0527bcc0711e312e9db65ca121a45213e3Timo Sirainen /* failure / buffer full */
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainenstatic bool cmd_finish_sync(struct client_command_context *cmd)
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainenstatic bool cmd_sync_continue(struct client_command_context *sync_cmd)
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen struct imap_sync_context *ctx = sync_cmd->context;
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) ;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen if (cmd->state == CLIENT_COMMAND_STATE_WAIT_SYNC &&
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen cmd->sync->counter+1 == client->sync_counter) {
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainenstatic void get_common_sync_flags(struct client *client,
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen unsigned int count = 0, fast_count = 0, noexpunges_count = 0;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen for (cmd = client->command_queue; cmd != NULL; cmd = cmd->next) {
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen if ((cmd->sync->flags & MAILBOX_SYNC_FLAG_FAST) != 0)
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen if (cmd->sync->flags & MAILBOX_SYNC_FLAG_NO_EXPUNGES)
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen i_assert(noexpunges_count == 0 || noexpunges_count == count);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen i_assert((*flags_r & (MAILBOX_SYNC_AUTO_STOP |
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainenstatic bool cmd_sync_client(struct client_command_context *sync_cmd)
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen /* there may be multiple commands waiting. use their combined flags */
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen get_common_sync_flags(client, &flags, &imap_flags);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen no_newmail = (client_workarounds & WORKAROUND_DELAY_NEWMAIL) != 0 &&
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen /* expunges might break the client just as badly as new mail
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen notifications. */
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen ctx = imap_sync_init(client, client->mailbox, imap_flags, flags);
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->state = CLIENT_COMMAND_STATE_WAIT_OUTPUT;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen o_stream_set_flush_pending(client->output, TRUE);
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainencmd_sync_full(struct client_command_context *cmd, enum mailbox_sync_flags flags,
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen enum imap_sync_flags imap_flags, const char *tagline,
42507d758b053bb483de58fba55c73a9eb5d3fbaTimo Sirainen i_assert(client->output_lock == cmd || client->output_lock == NULL);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen /* no mailbox selected, no point in delaying the sync */
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen cmd->sync = p_new(cmd->pool, struct client_sync_context, 1);
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen cmd->sync->tagline = p_strdup(cmd->pool, tagline);
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainenbool cmd_sync(struct client_command_context *cmd, enum mailbox_sync_flags flags,
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen enum imap_sync_flags imap_flags, const char *tagline)
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen return cmd_sync_full(cmd, flags, imap_flags, tagline, NULL);
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainenbool cmd_sync_callback(struct client_command_context *cmd,
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen return cmd_sync_full(cmd, flags, imap_flags, NULL, callback);
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainenstatic bool cmd_sync_drop_fast(struct client *client)
1939d1843ee6c7ca5e5baa3967b0332341440005Timo Sirainen for (cmd = client->command_queue; cmd->next != NULL; cmd = cmd->next) ;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen if (cmd->state == CLIENT_COMMAND_STATE_WAIT_SYNC &&
ccd83028a34cc6e2b6370eb7ecf1cf25e717c2d3Timo Sirainen (cmd->sync->flags & MAILBOX_SYNC_FLAG_FAST) != 0) {
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen struct client_command_context *cmd, *first_expunge, *first_nonexpunge;
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen /* wait until we can send output to client */
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen mailbox_transaction_get_count(client->mailbox) > 0)) {
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen /* wait until mailbox can be synced */
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen /* separate syncs that can send expunges from those that can't */
c96eb61168670cfdd7596baba18856d3f086a093Timo Sirainen for (cmd = client->command_queue; cmd != NULL; cmd = cmd->next) {
279b22f320f6139da5c1b0e2a5ead6692e7db947Timo Sirainen if (cmd->sync->flags & MAILBOX_SYNC_FLAG_NO_EXPUNGES) {
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) {