Blob Blame History Raw
From 1a27cfa8e337b7e3298ba230059e766cdbc1123d Mon Sep 17 00:00:00 2001
From: Timo Sirainen <timo.sirainen@open-xchange.com>
Date: Mon, 24 Aug 2020 19:10:43 +0300
Subject: [PATCH] imap: imap_client_hibernate() - Return reason string on
 failure

This helps writing a unit test for it.
---
 src/imap/cmd-idle.c              |  3 ++-
 src/imap/imap-client-hibernate.c | 10 +++++++++-
 src/imap/imap-client.h           |  5 +++--
 3 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/src/imap/cmd-idle.c b/src/imap/cmd-idle.c
index 8a05582d03..2b31dc714e 100644
--- a/src/imap/cmd-idle.c
+++ b/src/imap/cmd-idle.c
@@ -175,11 +175,12 @@ static void idle_add_keepalive_timeout(struct cmd_idle_context *ctx)
 static void idle_hibernate_timeout(struct cmd_idle_context *ctx)
 {
 	struct client *client = ctx->client;
+	const char *reason;
 
 	i_assert(ctx->sync_ctx == NULL);
 	i_assert(!ctx->sync_pending);
 
-	if (imap_client_hibernate(&client)) {
+	if (imap_client_hibernate(&client, &reason)) {
 		/* client may be destroyed now */
 	} else {
 		/* failed - don't bother retrying */
diff --git a/src/imap/imap-client-hibernate.c b/src/imap/imap-client-hibernate.c
index d3451b1bf6..0709e4a244 100644
--- a/src/imap/imap-client-hibernate.c
+++ b/src/imap/imap-client-hibernate.c
@@ -203,19 +203,23 @@ imap_hibernate_process_send(struct client *client, const buffer_t *state,
 	return 0;
 }
 
-bool imap_client_hibernate(struct client **_client)
+bool imap_client_hibernate(struct client **_client, const char **reason_r)
 {
 	struct client *client = *_client;
 	buffer_t *state;
 	const char *error;
 	int ret, fd_notify = -1, fd_hibernate = -1;
 
+	*reason_r = NULL;
+
 	if (client->fd_in != client->fd_out) {
 		/* we won't try to hibernate stdio clients */
+		*reason_r = "stdio clients can't be hibernated";
 		return FALSE;
 	}
 	if (o_stream_get_buffer_used_size(client->output) > 0) {
 		/* wait until we've sent the pending output to client */
+		*reason_r = "output pending to client";
 		return FALSE;
 	}
 
@@ -233,11 +237,13 @@ bool imap_client_hibernate(struct client **_client)
 			"Couldn't export state: %s (mailbox=%s)", error,
 			client->mailbox == NULL ? "" :
 			mailbox_get_vname(client->mailbox));
+		*reason_r = error;
 	} else if (ret == 0) {
 		e_debug(client->event, "Couldn't hibernate imap client: "
 			"Couldn't export state: %s (mailbox=%s)", error,
 			client->mailbox == NULL ? "" :
 			mailbox_get_vname(client->mailbox));
+		*reason_r = error;
 	}
 	if (ret > 0 && client->mailbox != NULL) {
 		fd_notify = mailbox_watch_extract_notify_fd(client->mailbox,
@@ -248,6 +254,7 @@ bool imap_client_hibernate(struct client **_client)
 			e_debug(client->event, "Couldn't hibernate imap client: "
 				"Couldn't extract notifications fd: %s",
 				error);
+			*reason_r = error;
 			ret = -1;
 		}
 	}
@@ -257,5 +264,6 @@ bool imap_client_hibernate(struct client **_client)
 			e_error(client->event,
 				"Couldn't hibernate imap client: %s", error);
+			*reason_r = error;
 			ret = -1;
 		}
 	}
diff --git a/src/imap/imap-client.h b/src/imap/imap-client.h
index f2ffe0d7c9..4e591d5c7c 100644
--- a/src/imap/imap-client.h
+++ b/src/imap/imap-client.h
@@ -323,8 +323,9 @@ enum mailbox_feature client_enabled_mailbox_features(struct client *client);
 const char *const *client_enabled_features(struct client *client);
 
 /* Send client processing to imap-idle process. If successful, returns TRUE
-   and destroys the client. */
-bool imap_client_hibernate(struct client **client);
+   and destroys the client. If hibernation failed, the exact reason is
+   returned (mainly for unit tests). */
+bool imap_client_hibernate(struct client **client, const char **reason_r);
 
 struct imap_search_update *
 client_search_update_lookup(struct client *client, const char *tag,