dovecot-1.1: Syncing supports now calling a callback after sync ...

dovecot at dovecot.org dovecot at dovecot.org
Wed Mar 5 02:54:36 EET 2008


details:   http://hg.dovecot.org/dovecot-1.1/rev/33304b5f6070
changeset: 7353:33304b5f6070
user:      Timo Sirainen <tss at iki.fi>
date:      Wed Mar 05 02:54:33 2008 +0200
description:
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).

diffstat:

4 files changed, 92 insertions(+), 32 deletions(-)
src/imap/client.h      |   10 ++---
src/imap/cmd-expunge.c |   18 ++++++++-
src/imap/imap-sync.c   |   90 +++++++++++++++++++++++++++++++++++-------------
src/imap/imap-sync.h   |    6 +++

diffs (255 lines):

diff -r 4f63124e756e -r 33304b5f6070 src/imap/client.h
--- 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 client_command_context {
 	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 {
 	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;
diff -r 4f63124e756e -r 33304b5f6070 src/imap/cmd-expunge.c
--- 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 @@ bool cmd_uid_expunge(struct client_comma
 	}
 }
 
+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 @@ bool cmd_expunge(struct client_command_c
 	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));
diff -r 4f63124e756e -r 33304b5f6070 src/imap/imap-sync.c
--- 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;
@@ -102,6 +112,9 @@ static int imap_sync_send_flags(struct i
 	flags = mail_get_flags(ctx->mail);
 	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);
@@ -185,6 +198,16 @@ int imap_sync_more(struct imap_sync_cont
 	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 @@ static bool cmd_sync_continue(struct cli
 	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);
-		}
-	}
-	client_send_tagline(sync_cmd, sync_cmd->sync_tagline);
-	return TRUE;
+		    cmd->sync->counter+1 == client->sync_counter) {
+			if (cmd_finish_sync(cmd))
+				client_command_free(cmd);
+		}
+	}
+	return cmd_finish_sync(sync_cmd);
 }
 
 static void get_common_sync_flags(struct client *client,
@@ -230,14 +252,14 @@ static void get_common_sync_flags(struct
 	*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 @@ static bool cmd_sync_client(struct clien
 	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 @@ bool cmd_sync(struct client_command_cont
 
 	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 @@ bool cmd_sync(struct client_command_cont
 	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 @@ static bool cmd_sync_drop_fast(struct cl
 		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 @@ bool cmd_sync_delayed(struct client *cli
 	/* 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;
 		}
 	}
diff -r 4f63124e756e -r 33304b5f6070 src/imap/imap-sync.h
--- 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
@@ -5,6 +5,8 @@ enum imap_sync_flags {
 	IMAP_SYNC_FLAG_SEND_UID	= 0x01,
 	IMAP_SYNC_FLAG_SAFE	= 0x02
 };
+
+typedef bool imap_sync_callback_t(struct client_command_context *cmd);
 
 struct client;
 
@@ -16,6 +18,10 @@ int imap_sync_more(struct imap_sync_cont
 
 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


More information about the dovecot-cvs mailing list