Mercurial > dovecot > original-hg > dovecot-1.2
changeset 7353:33304b5f6070 HEAD
Syncing supports now calling a callback after sync instead of just sending a
tagged reply. Use it with EXPUNGE to retry EXPUNGE in case the syncing had
seen new \Deleted flags (Outlook workaround).
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Wed, 05 Mar 2008 02:54:33 +0200 |
parents | 4f63124e756e |
children | de47a37ca0c1 |
files | src/imap/client.h src/imap/cmd-expunge.c src/imap/imap-sync.c src/imap/imap-sync.h |
diffstat | 4 files changed, 90 insertions(+), 30 deletions(-) [+] |
line wrap: on
line diff
--- a/src/imap/client.h Wed Mar 05 02:53:05 2008 +0200 +++ b/src/imap/client.h Wed Mar 05 02:54:33 2008 +0200 @@ -48,12 +48,7 @@ struct imap_parser *parser; enum client_command_state state; - /* if multiple commands are in progress, we may need to wait for them - to finish before syncing mailbox. */ - unsigned int sync_counter; - enum mailbox_sync_flags sync_flags; - enum imap_sync_flags sync_imap_flags; - const char *sync_tagline; + struct client_sync_context *sync; unsigned int uid:1; /* used UID command */ unsigned int cancel:1; /* command is wanted to be cancelled */ @@ -89,6 +84,9 @@ struct client_command_context *input_lock; struct client_command_context *output_lock; + /* syncing marks this TRUE when it sees \Deleted flags. this is by + EXPUNGE for Outlook-workaround. */ + unsigned int sync_seen_deletes:1; unsigned int disconnected:1; unsigned int destroyed:1; unsigned int handling_input:1;
--- a/src/imap/cmd-expunge.c Wed Mar 05 02:53:05 2008 +0200 +++ b/src/imap/cmd-expunge.c Wed Mar 05 02:54:33 2008 +0200 @@ -38,6 +38,19 @@ } } +static bool cmd_expunge_callback(struct client_command_context *cmd) +{ + if (cmd->client->sync_seen_deletes) { + /* Outlook workaround: session 1 set \Deleted flag and + session 2 tried to expunge without having seen it yet. + expunge again. */ + return cmd_expunge(cmd); + } + + client_send_tagline(cmd, "OK Expunge completed."); + return TRUE; +} + bool cmd_expunge(struct client_command_context *cmd) { struct client *client = cmd->client; @@ -45,9 +58,10 @@ if (!client_verify_open_mailbox(cmd)) return TRUE; + cmd->client->sync_seen_deletes = FALSE; if (imap_expunge(client->mailbox, NULL)) { - return cmd_sync(cmd, 0, IMAP_SYNC_FLAG_SAFE, - "OK Expunge completed."); + return cmd_sync_callback(cmd, 0, IMAP_SYNC_FLAG_SAFE, + cmd_expunge_callback); } else { client_send_storage_error(cmd, mailbox_get_storage(client->mailbox));
--- a/src/imap/imap-sync.c Wed Mar 05 02:53:05 2008 +0200 +++ b/src/imap/imap-sync.c Wed Mar 05 02:54:33 2008 +0200 @@ -8,6 +8,16 @@ #include "imap-sync.h" #include "commands.h" +struct client_sync_context { + /* if multiple commands are in progress, we may need to wait for them + to finish before syncing mailbox. */ + unsigned int counter; + enum mailbox_sync_flags flags; + enum imap_sync_flags imap_flags; + const char *tagline; + imap_sync_callback_t *callback; +}; + struct imap_sync_context { struct client *client; struct mailbox *box; @@ -103,6 +113,9 @@ keywords = client_get_keyword_names(ctx->client, &ctx->tmp_keywords, mail_get_keyword_indexes(ctx->mail)); + if ((flags & MAIL_DELETED) != 0) + ctx->client->sync_seen_deletes = TRUE; + str_truncate(str, 0); str_printfa(str, "* %u FETCH (", ctx->seq); if (ctx->imap_flags & IMAP_SYNC_FLAG_SEND_UID) @@ -185,6 +198,16 @@ return ret; } +static bool cmd_finish_sync(struct client_command_context *cmd) +{ + if (cmd->sync->callback != NULL) + return cmd->sync->callback(cmd); + else { + client_send_tagline(cmd, cmd->sync->tagline); + return TRUE; + } +} + static bool cmd_sync_continue(struct client_command_context *sync_cmd) { struct client_command_context *cmd; @@ -210,13 +233,12 @@ for (cmd = client->command_queue; cmd != NULL; cmd = cmd->next) { if (cmd->state == CLIENT_COMMAND_STATE_WAIT_SYNC && cmd != sync_cmd && - cmd->sync_counter+1 == client->sync_counter) { - client_send_tagline(cmd, cmd->sync_tagline); - client_command_free(cmd); + cmd->sync->counter+1 == client->sync_counter) { + if (cmd_finish_sync(cmd)) + client_command_free(cmd); } } - client_send_tagline(sync_cmd, sync_cmd->sync_tagline); - return TRUE; + return cmd_finish_sync(sync_cmd); } static void get_common_sync_flags(struct client *client, @@ -230,14 +252,14 @@ *imap_flags_r = 0; for (cmd = client->command_queue; cmd != NULL; cmd = cmd->next) { - if (cmd->sync_tagline != NULL && - cmd->sync_counter == client->sync_counter) { - if ((cmd->sync_flags & MAILBOX_SYNC_FLAG_FAST) != 0) + if (cmd->sync != NULL && + cmd->sync->counter == client->sync_counter) { + if ((cmd->sync->flags & MAILBOX_SYNC_FLAG_FAST) != 0) fast_count++; - if (cmd->sync_flags & MAILBOX_SYNC_FLAG_NO_EXPUNGES) + if (cmd->sync->flags & MAILBOX_SYNC_FLAG_NO_EXPUNGES) noexpunges_count++; - *flags_r |= cmd->sync_flags; - *imap_flags_r |= cmd->sync_imap_flags; + *flags_r |= cmd->sync->flags; + *imap_flags_r |= cmd->sync->imap_flags; count++; } } @@ -290,8 +312,10 @@ return TRUE; } -bool cmd_sync(struct client_command_context *cmd, enum mailbox_sync_flags flags, - enum imap_sync_flags imap_flags, const char *tagline) +static bool +cmd_sync_full(struct client_command_context *cmd, enum mailbox_sync_flags flags, + enum imap_sync_flags imap_flags, const char *tagline, + imap_sync_callback_t *callback) { struct client *client = cmd->client; @@ -302,14 +326,17 @@ if (client->mailbox == NULL) { /* no mailbox selected, no point in delaying the sync */ + i_assert(callback == NULL); client_send_tagline(cmd, tagline); return TRUE; } - cmd->sync_counter = client->sync_counter; - cmd->sync_flags = flags; - cmd->sync_imap_flags = imap_flags; - cmd->sync_tagline = p_strdup(cmd->pool, tagline); + cmd->sync = p_new(cmd->pool, struct client_sync_context, 1); + cmd->sync->counter = client->sync_counter; + cmd->sync->flags = flags; + cmd->sync->imap_flags = imap_flags; + cmd->sync->tagline = p_strdup(cmd->pool, tagline); + cmd->sync->callback = callback; cmd->state = CLIENT_COMMAND_STATE_WAIT_SYNC; cmd->func = NULL; @@ -321,6 +348,20 @@ return FALSE; } +bool cmd_sync(struct client_command_context *cmd, enum mailbox_sync_flags flags, + enum imap_sync_flags imap_flags, const char *tagline) +{ + return cmd_sync_full(cmd, flags, imap_flags, tagline, NULL); +} + +bool cmd_sync_callback(struct client_command_context *cmd, + enum mailbox_sync_flags flags, + enum imap_sync_flags imap_flags, + imap_sync_callback_t *callback) +{ + return cmd_sync_full(cmd, flags, imap_flags, NULL, callback); +} + static bool cmd_sync_drop_fast(struct client *client) { struct client_command_context *cmd, *next; @@ -330,10 +371,11 @@ next = cmd->next; if (cmd->state == CLIENT_COMMAND_STATE_WAIT_SYNC && - (cmd->sync_flags & MAILBOX_SYNC_FLAG_FAST) != 0) { - client_send_tagline(cmd, cmd->sync_tagline); - client_command_free(cmd); - ret = TRUE; + (cmd->sync->flags & MAILBOX_SYNC_FLAG_FAST) != 0) { + if (cmd_finish_sync(cmd)) { + client_command_free(cmd); + ret = TRUE; + } } } return ret; @@ -358,7 +400,7 @@ /* find a command that we can sync */ for (cmd = client->command_queue; cmd != NULL; cmd = cmd->next) { if (cmd->state == CLIENT_COMMAND_STATE_WAIT_SYNC) { - if (cmd->sync_counter == client->sync_counter) + if (cmd->sync->counter == client->sync_counter) break; } }
--- a/src/imap/imap-sync.h Wed Mar 05 02:53:05 2008 +0200 +++ b/src/imap/imap-sync.h Wed Mar 05 02:54:33 2008 +0200 @@ -6,6 +6,8 @@ IMAP_SYNC_FLAG_SAFE = 0x02 }; +typedef bool imap_sync_callback_t(struct client_command_context *cmd); + struct client; struct imap_sync_context * @@ -16,6 +18,10 @@ bool cmd_sync(struct client_command_context *cmd, enum mailbox_sync_flags flags, enum imap_sync_flags imap_flags, const char *tagline); +bool cmd_sync_callback(struct client_command_context *cmd, + enum mailbox_sync_flags flags, + enum imap_sync_flags imap_flags, + imap_sync_callback_t *callback); bool cmd_sync_delayed(struct client *client); #endif