changeset 9434:373b22cbabac HEAD

imap: IDLE now sends "Still here" notifications to same user's connections at the same time. Perhaps this will save some battery power with mobile clients that open multiple connections.
author Timo Sirainen <tss@iki.fi>
date Thu, 15 Oct 2009 18:27:16 -0400
parents 6c6460531514
children 0aa7357761a5
files src/imap/cmd-idle.c
diffstat 1 files changed, 28 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/src/imap/cmd-idle.c	Thu Oct 15 15:56:06 2009 -0400
+++ b/src/imap/cmd-idle.c	Thu Oct 15 18:27:16 2009 -0400
@@ -4,7 +4,9 @@
 #include "ioloop.h"
 #include "istream.h"
 #include "ostream.h"
+#include "crc32.h"
 #include "commands.h"
+#include "mail-user.h"
 #include "imap-sync.h"
 
 #include <stdlib.h>
@@ -25,6 +27,7 @@
 	unsigned int sync_pending:1;
 };
 
+static void idle_add_keepalive_timeout(struct cmd_idle_context *ctx);
 static bool cmd_idle_continue(struct client_command_context *cmd);
 
 static void
@@ -112,6 +115,8 @@
 	   several clients that really want to IDLE forever and there's not
 	   much harm in letting them do so. */
 	timeout_reset(ctx->client->to_idle);
+	/* recalculate time for the next keepalive timeout */
+	idle_add_keepalive_timeout(ctx);
 }
 
 static void idle_sync_now(struct mailbox *box, struct cmd_idle_context *ctx)
@@ -133,6 +138,27 @@
 	}
 }
 
+static void idle_add_keepalive_timeout(struct cmd_idle_context *ctx)
+{
+	const char *value;
+	unsigned int interval;
+
+	value = getenv("IMAP_IDLE_NOTIFY_INTERVAL");
+	interval = value != NULL ?
+		(unsigned int)strtoul(value, NULL, 10) :
+		DEFAULT_IMAP_IDLE_NOTIFY_INTERVAL;
+	if (interval == 0)
+		return;
+
+	interval -= (time(NULL) +
+		     crc32_str(ctx->client->user->username)) % interval;
+
+	if (ctx->keepalive_to != NULL)
+		timeout_remove(&ctx->keepalive_to);
+	ctx->keepalive_to = timeout_add(interval * 1000,
+					keepalive_timeout, ctx);
+}
+
 static bool cmd_idle_continue(struct client_command_context *cmd)
 {
 	struct client *client = cmd->client;
@@ -170,7 +196,7 @@
 	}
 	if (client->output->offset != orig_offset &&
 	    ctx->keepalive_to != NULL)
-		timeout_reset(ctx->keepalive_to);
+		idle_add_keepalive_timeout(ctx);
 
 	if (ctx->sync_pending) {
 		/* more changes occurred while we were sending changes to
@@ -210,14 +236,7 @@
 	ctx = p_new(cmd->pool, struct cmd_idle_context, 1);
 	ctx->cmd = cmd;
 	ctx->client = client;
-
-	str = getenv("IMAP_IDLE_NOTIFY_INTERVAL");
-	interval = str != NULL ?
-		(unsigned int)strtoul(str, NULL, 10) :
-		DEFAULT_IMAP_IDLE_NOTIFY_INTERVAL;
-	ctx->keepalive_to = interval == 0 ? NULL :
-		timeout_add(interval * 1000,
-			    keepalive_timeout, ctx);
+	idle_add_keepalive_timeout(ctx);
 
 	str = getenv("MAILBOX_IDLE_CHECK_INTERVAL");
 	interval = str == NULL ? 0 : (unsigned int)strtoul(str, NULL, 10);