Blob Blame History Raw
diff -up evolution-data-server-3.8.5/camel/camel-imapx-conn-manager.c.imapx-conn-manager-ext evolution-data-server-3.8.5/camel/camel-imapx-conn-manager.c
--- evolution-data-server-3.8.5/camel/camel-imapx-conn-manager.c.imapx-conn-manager-ext	2013-07-23 13:57:46.000000000 +0200
+++ evolution-data-server-3.8.5/camel/camel-imapx-conn-manager.c	2014-05-13 14:17:43.115983665 +0200
@@ -47,6 +47,7 @@ struct _CamelIMAPXConnManagerPrivate {
 	GList *connections;
 	GWeakRef store;
 	GRWLock rw_lock;
+	guint limit_max_connections;
 };
 
 struct _ConnectionInfo {
@@ -54,6 +55,7 @@ struct _ConnectionInfo {
 	CamelIMAPXServer *is;
 	GHashTable *folder_names;
 	gchar *selected_folder;
+	GError *shutdown_error;
 	volatile gint ref_count;
 };
 
@@ -68,7 +70,9 @@ G_DEFINE_TYPE (
 	CAMEL_TYPE_OBJECT)
 
 static void
-imapx_conn_shutdown (CamelIMAPXServer *is, CamelIMAPXConnManager *con_man);
+imapx_conn_shutdown (CamelIMAPXServer *is,
+		     const GError *error,
+		     CamelIMAPXConnManager *con_man);
 
 static void
 imapx_conn_update_select (CamelIMAPXServer *is,
@@ -91,6 +95,7 @@ connection_info_new (CamelIMAPXServer *i
 	g_mutex_init (&cinfo->lock);
 	cinfo->is = g_object_ref (is);
 	cinfo->folder_names = folder_names;
+	cinfo->shutdown_error = NULL;
 	cinfo->ref_count = 1;
 
 	return cinfo;
@@ -114,11 +119,15 @@ connection_info_unref (ConnectionInfo *c
 	g_return_if_fail (cinfo->ref_count > 0);
 
 	if (g_atomic_int_dec_and_test (&cinfo->ref_count)) {
-		camel_imapx_server_connect (cinfo->is, NULL, NULL);
+		camel_imapx_server_shutdown (cinfo->is, cinfo->shutdown_error);
+		g_signal_handlers_disconnect_matched (cinfo->is, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, imapx_conn_shutdown, NULL);
+		g_signal_handlers_disconnect_matched (cinfo->is, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, imapx_conn_update_select, NULL);
+
 		g_mutex_clear (&cinfo->lock);
 		g_object_unref (cinfo->is);
 		g_hash_table_destroy (cinfo->folder_names);
 		g_free (cinfo->selected_folder);
+		g_clear_error (&cinfo->shutdown_error);
 
 		g_slice_free (ConnectionInfo, cinfo);
 	}
@@ -132,6 +141,7 @@ connection_info_cancel_and_unref (Connec
 
 	g_signal_handlers_disconnect_matched (cinfo->is, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, imapx_conn_shutdown, NULL);
 	g_signal_handlers_disconnect_matched (cinfo->is, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, imapx_conn_update_select, NULL);
+	camel_imapx_server_shutdown (cinfo->is, cinfo->shutdown_error);
 	g_cancellable_cancel (cinfo->is->cancellable);
 	connection_info_unref (cinfo);
 }
@@ -145,8 +155,9 @@ connection_info_is_available (Connection
 
 	g_mutex_lock (&cinfo->lock);
 
-	/* Available means it's not tracking any folder names. */
-	available = (g_hash_table_size (cinfo->folder_names) == 0);
+	/* Available means it's not tracking any folder names or no jobs are running. */
+	available = (g_hash_table_size (cinfo->folder_names) == 0) ||
+		    camel_imapx_server_get_command_count (cinfo->is) == 0;
 
 	g_mutex_unlock (&cinfo->lock);
 
@@ -234,6 +245,23 @@ connection_info_set_selected_folder (Con
 	g_mutex_unlock (&cinfo->lock);
 }
 
+static void
+connection_info_set_shutdown_error (ConnectionInfo *cinfo,
+                                    const GError *shutdown_error)
+{
+	g_return_if_fail (cinfo != NULL);
+
+	g_mutex_lock (&cinfo->lock);
+
+	if (cinfo->shutdown_error != shutdown_error) {
+		g_clear_error (&cinfo->shutdown_error);
+		if (shutdown_error)
+			cinfo->shutdown_error = g_error_copy (shutdown_error);
+	}
+
+	g_mutex_unlock (&cinfo->lock);
+}
+
 static GList *
 imapx_conn_manager_list_info (CamelIMAPXConnManager *con_man)
 {
@@ -416,11 +444,9 @@ camel_imapx_conn_manager_init (CamelIMAP
 	g_rw_lock_init (&con_man->priv->rw_lock);
 }
 
-/* Static functions go here */
-
-/* TODO destroy unused connections in a time-out loop */
 static void
 imapx_conn_shutdown (CamelIMAPXServer *is,
+		     const GError *error,
                      CamelIMAPXConnManager *con_man)
 {
 	ConnectionInfo *cinfo;
@@ -432,6 +458,14 @@ imapx_conn_shutdown (CamelIMAPXServer *i
 		imapx_conn_manager_remove_info (con_man, cinfo);
 		connection_info_unref (cinfo);
 	}
+
+	/* If one connection ends with this error, then it means all
+	   other opened connections also may end with the same error,
+	   thus better to kill them all from the list of connections.
+	*/
+	if (g_error_matches (error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
+		camel_imapx_conn_manager_close_connections (con_man, error);
+	}
 }
 
 static void
@@ -451,14 +485,10 @@ imapx_conn_update_select (CamelIMAPXServ
 	old_selected_folder = connection_info_dup_selected_folder (cinfo);
 
 	if (old_selected_folder != NULL) {
-		IMAPXJobQueueInfo *jinfo;
-
-		jinfo = camel_imapx_server_get_job_queue_info (is);
-		if (!g_hash_table_lookup (jinfo->folders, old_selected_folder)) {
+		if (!camel_imapx_server_folder_name_in_jobs (is, old_selected_folder)) {
 			connection_info_remove_folder_name (cinfo, old_selected_folder);
 			c (is->tagprefix, "Removed folder %s from connection folder list - select changed \n", old_selected_folder);
 		}
-		camel_imapx_destroy_job_queue_info (jinfo);
 
 		g_free (old_selected_folder);
 	}
@@ -471,14 +501,15 @@ imapx_conn_update_select (CamelIMAPXServ
 /* This should find a connection if the slots are full, returns NULL if there are slots available for a new connection for a folder */
 static CamelIMAPXServer *
 imapx_find_connection_unlocked (CamelIMAPXConnManager *con_man,
-                                const gchar *folder_name)
+                                const gchar *folder_name,
+				gboolean for_expensive_job)
 {
 	CamelStore *store;
 	CamelSettings *settings;
 	CamelIMAPXServer *is = NULL;
 	ConnectionInfo *cinfo = NULL;
 	GList *list, *link;
-	guint concurrent_connections;
+	guint concurrent_connections, opened_connections, expensive_connections = 0;
 	guint min_jobs = G_MAXUINT;
 
 	/* Caller must be holding CON_WRITE_LOCK. */
@@ -492,24 +523,85 @@ imapx_find_connection_unlocked (CamelIMA
 		camel_imapx_settings_get_concurrent_connections (
 		CAMEL_IMAPX_SETTINGS (settings));
 
+	if (con_man->priv->limit_max_connections > 0 &&
+	    con_man->priv->limit_max_connections < concurrent_connections)
+		concurrent_connections = con_man->priv->limit_max_connections;
+
 	g_object_unref (settings);
 
 	/* XXX Have a dedicated connection for INBOX ? */
 
+	opened_connections = g_list_length (con_man->priv->connections);
 	list = con_man->priv->connections;
 
 	/* If a folder was not given, find the least-busy connection. */
-	if (folder_name == NULL)
+	if (folder_name == NULL) {
 		goto least_busy;
+	}
 
 	/* First try to find a connection already handling this folder. */
 	for (link = list; link != NULL; link = g_list_next (link)) {
 		ConnectionInfo *candidate = link->data;
 
-		if (connection_info_has_folder_name (candidate, folder_name)) {
+		if (camel_imapx_server_has_expensive_command (candidate->is))
+			expensive_connections++;
+
+		if (connection_info_has_folder_name (candidate, folder_name) &&
+		    (opened_connections >= concurrent_connections || for_expensive_job || !camel_imapx_server_has_expensive_command (candidate->is))) {
+			if (cinfo) {
+				/* group expensive jobs into one connection */
+				if (for_expensive_job && camel_imapx_server_has_expensive_command (cinfo->is))
+					continue;
+
+				if (!for_expensive_job && camel_imapx_server_get_command_count (cinfo->is) < camel_imapx_server_get_command_count (candidate->is))
+					continue;
+
+				connection_info_unref (cinfo);
+			}
+
 			cinfo = connection_info_ref (candidate);
+			if (for_expensive_job && camel_imapx_server_has_expensive_command (cinfo->is))
+				goto exit;
+		}
+	}
+
+ least_busy:
+	if (for_expensive_job) {
+		/* allow only half connections being with expensive operations */
+		if (expensive_connections > 0 &&
+		    expensive_connections < concurrent_connections / 2 &&
+		    opened_connections < concurrent_connections)
 			goto exit;
+
+		/* cinfo here doesn't have any expensive command, thus ignore it */
+		if (cinfo) {
+			connection_info_unref (cinfo);
+			cinfo = NULL;
 		}
+
+		/* Pick the connection with the least number of jobs in progress among those with expensive jobs. */
+		for (link = list; link != NULL; link = g_list_next (link)) {
+			ConnectionInfo *candidate = link->data;
+			guint jobs;
+
+			if (!camel_imapx_server_has_expensive_command (candidate->is))
+				continue;
+
+			jobs = camel_imapx_server_get_command_count (candidate->is);
+
+			if (cinfo == NULL) {
+				cinfo = connection_info_ref (candidate);
+				min_jobs = jobs;
+
+			} else if (jobs < min_jobs) {
+				connection_info_unref (cinfo);
+				cinfo = connection_info_ref (candidate);
+				min_jobs = jobs;
+			}
+		}
+
+		if (cinfo)
+			goto exit;
 	}
 
 	/* Next try to find a connection not handling any folders. */
@@ -517,44 +609,59 @@ imapx_find_connection_unlocked (CamelIMA
 		ConnectionInfo *candidate = link->data;
 
 		if (connection_info_is_available (candidate)) {
+			if (cinfo)
+				connection_info_unref (cinfo);
 			cinfo = connection_info_ref (candidate);
 			goto exit;
 		}
 	}
 
-least_busy:
+	/* open a new connection, if there is a room for it */
+	if (opened_connections < concurrent_connections && (!for_expensive_job || opened_connections < concurrent_connections / 2)) {
+		if (cinfo && camel_imapx_server_get_command_count (cinfo->is) != 0) {
+			connection_info_unref (cinfo);
+			cinfo = NULL;
+		}
+		goto exit;
+	} else {
+		if (cinfo)
+			min_jobs = camel_imapx_server_get_command_count (cinfo->is);
+	}
+
 	/* Pick the connection with the least number of jobs in progress. */
 	for (link = list; link != NULL; link = g_list_next (link)) {
 		ConnectionInfo *candidate = link->data;
-		IMAPXJobQueueInfo *jinfo = NULL;
-
-		jinfo = camel_imapx_server_get_job_queue_info (candidate->is);
+		gint n_commands = camel_imapx_server_get_command_count (candidate->is);
 
 		if (cinfo == NULL) {
 			cinfo = connection_info_ref (candidate);
-			min_jobs = jinfo->queue_len;
+			min_jobs = n_commands;
 
-		} else if (jinfo->queue_len < min_jobs) {
+		} else if (n_commands < min_jobs) {
 			connection_info_unref (cinfo);
 			cinfo = connection_info_ref (candidate);
-			min_jobs = jinfo->queue_len;
+			min_jobs = n_commands;
 		}
-
-		camel_imapx_destroy_job_queue_info (jinfo);
 	}
 
 exit:
 	if (cinfo != NULL && folder_name != NULL)
 		connection_info_insert_folder_name (cinfo, folder_name);
 
+	if (camel_debug_flag (conman)) {
+		printf ("%s: for-expensive:%d will return:%p cmd-count:%d has-expensive:%d found:%d; connections opened:%d max:%d\n", G_STRFUNC, for_expensive_job, cinfo, cinfo ? camel_imapx_server_get_command_count (cinfo->is) : -2, cinfo ? camel_imapx_server_has_expensive_command (cinfo->is) : -2, expensive_connections, g_list_length (list), concurrent_connections);
+		for (link = list; link != NULL; link = g_list_next (link)) {
+			ConnectionInfo *candidate = link->data;
+
+			printf ("   cmds:%d has-expensive:%d avail:%d cinfo:%p server:%p\n", camel_imapx_server_get_command_count (candidate->is), camel_imapx_server_has_expensive_command (candidate->is), connection_info_is_available (candidate), candidate, candidate->is);
+		}
+	}
+
 	if (cinfo != NULL) {
 		is = g_object_ref (cinfo->is);
 		connection_info_unref (cinfo);
 	}
 
-	if (camel_debug_flag (conman))
-		g_assert (!(concurrent_connections == g_list_length (con_man->priv->connections) && is == NULL));
-
 	g_object_unref (store);
 
 	return is;
@@ -601,9 +708,11 @@ imapx_create_new_connection_unlocked (Ca
 	 *     authenticate at once, so this should be thread-safe.
 	 */
 	imapx_store->authenticating_server = g_object_ref (is);
+	camel_imapx_store_set_authenticating_concurrent_connection (imapx_store, con_man->priv->connections != NULL);
 	success = camel_imapx_server_connect (is, cancellable, error);
 	g_object_unref (imapx_store->authenticating_server);
 	imapx_store->authenticating_server = NULL;
+	camel_imapx_store_set_authenticating_concurrent_connection (imapx_store, FALSE);
 
 	if (!success) {
 		g_clear_object (&is);
@@ -626,7 +735,7 @@ imapx_create_new_connection_unlocked (Ca
 	con_man->priv->connections = g_list_prepend (
 		con_man->priv->connections, cinfo);
 
-	c (is->tagprefix, "Created new connection for %s and total connections %d \n", folder_name, g_list_length (con_man->priv->connections));
+	c (is->tagprefix, "Created new connection %p (server:%p) for %s; total connections %d\n", cinfo, cinfo->is, folder_name, g_list_length (con_man->priv->connections));
 
 exit:
 	g_object_unref (store);
@@ -656,6 +765,7 @@ camel_imapx_conn_manager_ref_store (Came
 CamelIMAPXServer *
 camel_imapx_conn_manager_get_connection (CamelIMAPXConnManager *con_man,
                                          const gchar *folder_name,
+					 gboolean for_expensive_job,
                                          GCancellable *cancellable,
                                          GError **error)
 {
@@ -669,10 +779,36 @@ camel_imapx_conn_manager_get_connection
 
 	/* Check if we got cancelled while waiting for the lock. */
 	if (!g_cancellable_set_error_if_cancelled (cancellable, error)) {
-		is = imapx_find_connection_unlocked (con_man, folder_name);
-		if (is == NULL)
-			is = imapx_create_new_connection_unlocked (
-				con_man, folder_name, cancellable, error);
+		is = imapx_find_connection_unlocked (con_man, folder_name, for_expensive_job);
+		if (is == NULL) {
+			GError *local_error = NULL;
+
+			is = imapx_create_new_connection_unlocked (con_man, folder_name, cancellable, &local_error);
+
+			if (!is) {
+				gboolean limit_connections =
+					g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR,
+					CAMEL_IMAPX_SERVER_ERROR_CONCURRENT_CONNECT_FAILED) &&
+					con_man->priv->connections;
+
+				c ('*', "Failed to open a new connection, while having %d opened, with error: %s; will limit connections: %s\n",
+					g_list_length (con_man->priv->connections),
+					local_error ? local_error->message : "Unknown error",
+					limit_connections ? "yes" : "no");
+
+				if (limit_connections) {
+					/* limit to one-less than current connection count - be nice to the server */
+					con_man->priv->limit_max_connections = g_list_length (con_man->priv->connections) - 1;
+					if (!con_man->priv->limit_max_connections)
+						con_man->priv->limit_max_connections = 1;
+
+					g_clear_error (&local_error);
+					is = imapx_find_connection_unlocked (con_man, folder_name, for_expensive_job);
+				} else if (local_error) {
+					g_propagate_error (error, local_error);
+				}
+			}
+		}
 	}
 
 	CON_WRITE_UNLOCK (con_man);
@@ -706,7 +842,6 @@ camel_imapx_conn_manager_update_con_info
                                           const gchar *folder_name)
 {
 	ConnectionInfo *cinfo;
-	IMAPXJobQueueInfo *jinfo;
 
 	g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man));
 
@@ -716,28 +851,35 @@ camel_imapx_conn_manager_update_con_info
 	if (cinfo == NULL)
 		return;
 
-	jinfo = camel_imapx_server_get_job_queue_info (cinfo->is);
-	if (!g_hash_table_lookup (jinfo->folders, folder_name)) {
+	if (camel_imapx_server_folder_name_in_jobs (is, folder_name)) {
 		connection_info_remove_folder_name (cinfo, folder_name);
 		c (is->tagprefix, "Removed folder %s from connection folder list - op done \n", folder_name);
 	}
-	camel_imapx_destroy_job_queue_info (jinfo);
 
 	connection_info_unref (cinfo);
 }
 
 void
-camel_imapx_conn_manager_close_connections (CamelIMAPXConnManager *con_man)
+camel_imapx_conn_manager_close_connections (CamelIMAPXConnManager *con_man,
+					    const GError *error)
 {
+	GList *iter, *connections;
+
 	g_return_if_fail (CAMEL_IS_IMAPX_CONN_MANAGER (con_man));
 
 	CON_WRITE_LOCK (con_man);
 
-	g_list_free_full (
-		con_man->priv->connections,
-		(GDestroyNotify) connection_info_cancel_and_unref);
+	c('*', "Closing all %d connections, with propagated error: %s\n", g_list_length (con_man->priv->connections), error ? error->message : "none");
+
+	connections = con_man->priv->connections;
 	con_man->priv->connections = NULL;
 
 	CON_WRITE_UNLOCK (con_man);
+
+	for (iter = connections; iter; iter = g_list_next (iter)) {
+		connection_info_set_shutdown_error (iter->data, error);
+	}
+
+	g_list_free_full (connections, (GDestroyNotify) connection_info_cancel_and_unref);
 }
 
diff -up evolution-data-server-3.8.5/camel/camel-imapx-conn-manager.h.imapx-conn-manager-ext evolution-data-server-3.8.5/camel/camel-imapx-conn-manager.h
--- evolution-data-server-3.8.5/camel/camel-imapx-conn-manager.h.imapx-conn-manager-ext	2013-07-23 13:57:56.000000000 +0200
+++ evolution-data-server-3.8.5/camel/camel-imapx-conn-manager.h	2014-05-13 14:17:43.116983665 +0200
@@ -71,10 +71,12 @@ CamelIMAPXServer *
 		camel_imapx_conn_manager_get_connection
 						(CamelIMAPXConnManager *con_man,
 						 const gchar *folder_name,
+						 gboolean for_expensive_job,
 						 GCancellable *cancellable,
 						 GError **error);
 void		camel_imapx_conn_manager_close_connections
-						(CamelIMAPXConnManager *con_man);
+						(CamelIMAPXConnManager *con_man,
+						 const GError *error);
 GList *		camel_imapx_conn_manager_get_connections
 						(CamelIMAPXConnManager *con_man);
 void		camel_imapx_conn_manager_update_con_info
diff -up evolution-data-server-3.8.5/camel/camel-imapx-folder.c.imapx-conn-manager-ext evolution-data-server-3.8.5/camel/camel-imapx-folder.c
--- evolution-data-server-3.8.5/camel/camel-imapx-folder.c.imapx-conn-manager-ext	2013-07-23 14:01:51.000000000 +0200
+++ evolution-data-server-3.8.5/camel/camel-imapx-folder.c	2014-05-13 14:17:43.116983665 +0200
@@ -303,47 +303,27 @@ imapx_search_by_uids (CamelFolder *folde
 {
 	CamelIMAPXFolder *ifolder;
 	CamelIMAPXSearch *isearch;
-	CamelIMAPXServer *server = NULL;
-	CamelStore *parent_store;
 	GPtrArray *matches;
-	const gchar *folder_name;
-	gboolean online;
 
 	if (uids->len == 0)
 		return g_ptr_array_new ();
 
 	ifolder = CAMEL_IMAPX_FOLDER (folder);
-	folder_name = camel_folder_get_full_name (folder);
-	parent_store = camel_folder_get_parent_store (folder);
-
-	online = camel_offline_store_get_online (
-		CAMEL_OFFLINE_STORE (parent_store));
-
-	if (online) {
-		/* do not panic when the server cannot be reached for whatever reason,
-		 * show offline data at least */
-		server = camel_imapx_store_get_server (
-			CAMEL_IMAPX_STORE (parent_store),
-			folder_name, cancellable, NULL);
-	}
 
 	g_mutex_lock (&ifolder->search_lock);
 
 	isearch = CAMEL_IMAPX_SEARCH (ifolder->search);
-	camel_imapx_search_set_server (isearch, server);
 
 	camel_folder_search_set_folder (ifolder->search, folder);
+	camel_imapx_search_set_cancellable_and_error (isearch, cancellable, error);
 
 	matches = camel_folder_search_search (
 		ifolder->search, expression, uids, cancellable, error);
 
-	camel_imapx_search_set_server (isearch, NULL);
+	camel_imapx_search_set_cancellable_and_error (isearch, NULL, NULL);
 
 	g_mutex_unlock (&ifolder->search_lock);
 
-	if (server != NULL)
-		g_object_unref (server);
-
 	return matches;
 }
 
@@ -355,44 +335,24 @@ imapx_count_by_expression (CamelFolder *
 {
 	CamelIMAPXFolder *ifolder;
 	CamelIMAPXSearch *isearch;
-	CamelIMAPXServer *server = NULL;
-	CamelStore *parent_store;
-	const gchar *folder_name;
-	gboolean online;
 	guint32 matches;
 
 	ifolder = CAMEL_IMAPX_FOLDER (folder);
-	folder_name = camel_folder_get_full_name (folder);
-	parent_store = camel_folder_get_parent_store (folder);
-
-	online = camel_offline_store_get_online (
-		CAMEL_OFFLINE_STORE (parent_store));
-
-	if (online) {
-		/* do not panic when the server cannot be reached for whatever reason,
-		 * show offline data at least */
-		server = camel_imapx_store_get_server (
-			CAMEL_IMAPX_STORE (parent_store),
-			folder_name, cancellable, NULL);
-	}
 
 	g_mutex_lock (&ifolder->search_lock);
 
 	isearch = CAMEL_IMAPX_SEARCH (ifolder->search);
-	camel_imapx_search_set_server (isearch, server);
 
 	camel_folder_search_set_folder (ifolder->search, folder);
+	camel_imapx_search_set_cancellable_and_error (isearch, cancellable, error);
 
 	matches = camel_folder_search_count (
 		ifolder->search, expression, cancellable, error);
 
-	camel_imapx_search_set_server (isearch, NULL);
+	camel_imapx_search_set_cancellable_and_error (isearch, NULL, NULL);
 
 	g_mutex_unlock (&ifolder->search_lock);
 
-	if (server != NULL)
-		g_object_unref (server);
-
 	return matches;
 }
 
@@ -404,44 +364,24 @@ imapx_search_by_expression (CamelFolder
 {
 	CamelIMAPXFolder *ifolder;
 	CamelIMAPXSearch *isearch;
-	CamelIMAPXServer *server = NULL;
-	CamelStore *parent_store;
 	GPtrArray *matches;
-	const gchar *folder_name;
-	gboolean online;
 
 	ifolder = CAMEL_IMAPX_FOLDER (folder);
-	folder_name = camel_folder_get_full_name (folder);
-	parent_store = camel_folder_get_parent_store (folder);
-
-	online = camel_offline_store_get_online (
-		CAMEL_OFFLINE_STORE (parent_store));
-
-	if (online) {
-		/* do not panic when the server cannot be reached for whatever reason,
-		 * show offline data at least */
-		server = camel_imapx_store_get_server (
-			CAMEL_IMAPX_STORE (parent_store),
-			folder_name, cancellable, NULL);
-	}
 
 	g_mutex_lock (&ifolder->search_lock);
 
 	isearch = CAMEL_IMAPX_SEARCH (ifolder->search);
-	camel_imapx_search_set_server (isearch, server);
 
 	camel_folder_search_set_folder (ifolder->search, folder);
+	camel_imapx_search_set_cancellable_and_error (isearch, cancellable, error);
 
 	matches = camel_folder_search_search (
 		ifolder->search, expression, NULL, cancellable, error);
 
-	camel_imapx_search_set_server (isearch, NULL);
+	camel_imapx_search_set_cancellable_and_error (isearch, NULL, NULL);
 
 	g_mutex_unlock (&ifolder->search_lock);
 
-	if (server != NULL)
-		g_object_unref (server);
-
 	return matches;
 }
 
@@ -466,8 +406,11 @@ imapx_append_message_sync (CamelFolder *
 	CamelStore *parent_store;
 	CamelIMAPXStore *istore;
 	CamelIMAPXServer *server;
+	const gchar *folder_name;
+	GError *local_error = NULL;
 	gboolean success = FALSE;
 
+	folder_name = camel_folder_get_full_name (folder);
 	parent_store = camel_folder_get_parent_store (folder);
 	istore = CAMEL_IMAPX_STORE (parent_store);
 
@@ -482,11 +425,27 @@ imapx_append_message_sync (CamelFolder *
 	if (appended_uid)
 		*appended_uid = NULL;
 
-	server = camel_imapx_store_get_server (istore, NULL, cancellable, error);
+	server = camel_imapx_store_get_server (istore, folder_name, FALSE, cancellable, error);
 	if (server) {
 		success = camel_imapx_server_append_message (
-			server, folder, message, info, appended_uid, cancellable, error);
+			server, folder, message, info, appended_uid, cancellable, &local_error);
+		camel_imapx_store_op_done (istore, server, folder_name);
 		g_object_unref (server);
+
+		while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
+			g_clear_error (&local_error);
+
+			server = camel_imapx_store_get_server (istore, folder_name, FALSE, cancellable, &local_error);
+			if (server) {
+				success = camel_imapx_server_append_message (
+					server, folder, message, info, appended_uid, cancellable, &local_error);
+				camel_imapx_store_op_done (istore, server, folder_name);
+				g_object_unref (server);
+			}
+		}
+
+		if (local_error)
+			g_propagate_error (error, local_error);
 	}
 
 	return success;
@@ -501,6 +460,7 @@ imapx_expunge_sync (CamelFolder *folder,
 	CamelIMAPXStore *istore;
 	CamelIMAPXServer *server;
 	const gchar *folder_name;
+	GError *local_error = NULL;
 	gboolean success = FALSE;
 
 	folder_name = camel_folder_get_full_name (folder);
@@ -515,13 +475,25 @@ imapx_expunge_sync (CamelFolder *folder,
 		return FALSE;
 	}
 
-	server = camel_imapx_store_get_server (
-		istore, folder_name, cancellable, error);
+	server = camel_imapx_store_get_server (istore, folder_name, FALSE, cancellable, error);
 	if (server != NULL) {
-		success = camel_imapx_server_expunge (
-			server, folder, cancellable, error);
+		success = camel_imapx_server_expunge (server, folder, cancellable, &local_error);
 		camel_imapx_store_op_done (istore, server, folder_name);
 		g_object_unref (server);
+
+		while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
+			g_clear_error (&local_error);
+
+			server = camel_imapx_store_get_server (istore, folder_name, FALSE, cancellable, &local_error);
+			if (server != NULL) {
+				success = camel_imapx_server_expunge (server, folder, cancellable, &local_error);
+				camel_imapx_store_op_done (istore, server, folder_name);
+				g_object_unref (server);
+			}
+		}
+
+		if (local_error)
+			g_propagate_error (error, local_error);
 	}
 
 	return success;
@@ -539,6 +511,7 @@ imapx_fetch_messages_sync (CamelFolder *
 	CamelIMAPXStore *istore;
 	CamelIMAPXServer *server;
 	const gchar *folder_name;
+	GError *local_error = NULL;
 	gboolean success = FALSE;
 
 	folder_name = camel_folder_get_full_name (folder);
@@ -557,19 +530,66 @@ imapx_fetch_messages_sync (CamelFolder *
 	if (!camel_service_connect_sync (service, cancellable, error))
 		return FALSE;
 
-	server = camel_imapx_store_get_server (
-		istore, folder_name, cancellable, error);
+	server = camel_imapx_store_get_server (istore, folder_name, TRUE, cancellable, error);
 	if (server != NULL) {
-		success = camel_imapx_server_fetch_messages (
-			server, folder, type, limit, cancellable, error);
+		success = camel_imapx_server_fetch_messages (server, folder, type, limit, cancellable, &local_error);
 		camel_imapx_store_op_done (istore, server, folder_name);
 		g_object_unref (server);
+
+		while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
+			g_clear_error (&local_error);
+
+			server = camel_imapx_store_get_server (istore, folder_name, TRUE, cancellable, &local_error);
+			if (server != NULL) {
+				success = camel_imapx_server_fetch_messages (server, folder, type, limit, cancellable, &local_error);
+				camel_imapx_store_op_done (istore, server, folder_name);
+				g_object_unref (server);
+			}
+		}
+
+		if (local_error)
+			g_propagate_error (error, local_error);
+
 	}
 
 	return success;
 }
 
 static CamelMimeMessage *
+imapx_get_message_cached (CamelFolder *folder,
+			  const gchar *message_uid,
+			  GCancellable *cancellable)
+{
+	CamelIMAPXFolder *imapx_folder;
+	CamelMimeMessage *msg = NULL;
+	CamelStream *stream = NULL;
+
+	g_return_val_if_fail (CAMEL_IS_IMAPX_FOLDER (folder), NULL);
+	g_return_val_if_fail (message_uid != NULL, NULL);
+
+	imapx_folder = CAMEL_IMAPX_FOLDER (folder);
+
+	stream = camel_data_cache_get (imapx_folder->cache, "cur", message_uid, NULL);
+	if (stream != NULL) {
+		gboolean success;
+
+		msg = camel_mime_message_new ();
+
+		g_mutex_lock (&imapx_folder->stream_lock);
+		success = camel_data_wrapper_construct_from_stream_sync (
+			CAMEL_DATA_WRAPPER (msg), stream, cancellable, NULL);
+		if (!success) {
+			g_object_unref (msg);
+			msg = NULL;
+		}
+		g_mutex_unlock (&imapx_folder->stream_lock);
+		g_object_unref (stream);
+	}
+
+	return msg;
+}
+
+static CamelMimeMessage *
 imapx_get_message_sync (CamelFolder *folder,
                         const gchar *uid,
                         GCancellable *cancellable,
@@ -583,6 +603,7 @@ imapx_get_message_sync (CamelFolder *fol
 	CamelIMAPXServer *server;
 	const gchar *folder_name;
 	const gchar *path = NULL;
+	GError *local_error = NULL;
 	gboolean offline_message = FALSE;
 
 	folder_name = camel_folder_get_full_name (folder);
@@ -615,14 +636,27 @@ imapx_get_message_sync (CamelFolder *fol
 		}
 
 		server = camel_imapx_store_get_server (
-			istore, folder_name, cancellable, error);
+			istore, folder_name, FALSE, cancellable, error);
 		if (server == NULL)
 			return NULL;
 
-		stream = camel_imapx_server_get_message (
-			server, folder, uid, cancellable, error);
+		stream = camel_imapx_server_get_message (server, folder, uid, cancellable, &local_error);
 		camel_imapx_store_op_done (istore, server, folder_name);
 		g_object_unref (server);
+
+		while (!stream && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
+			g_clear_error (&local_error);
+
+			server = camel_imapx_store_get_server (istore, folder_name, FALSE, cancellable, &local_error);
+			if (server) {
+				stream = camel_imapx_server_get_message (server, folder, uid, cancellable, &local_error);
+				camel_imapx_store_op_done (istore, server, folder_name);
+				g_object_unref (server);
+			}
+		}
+
+		if (local_error)
+			g_propagate_error (error, local_error);
 	}
 
 	if (stream != NULL) {
@@ -675,6 +709,7 @@ imapx_get_quota_info_sync (CamelFolder *
 	CamelFolderQuotaInfo *quota_info = NULL;
 	const gchar *folder_name;
 	gchar **quota_root_names;
+	GError *local_error = NULL;
 	gboolean success = FALSE;
 
 	folder_name = camel_folder_get_full_name (folder);
@@ -682,14 +717,29 @@ imapx_get_quota_info_sync (CamelFolder *
 
 	server = camel_imapx_store_get_server (
 		CAMEL_IMAPX_STORE (parent_store),
-		folder_name, cancellable, error);
+		folder_name, FALSE, cancellable, error);
 
 	if (server != NULL) {
-		success = camel_imapx_server_update_quota_info (
-			server, folder_name, cancellable, error);
+		success = camel_imapx_server_update_quota_info (server, folder_name, cancellable, &local_error);
+		camel_imapx_store_op_done (CAMEL_IMAPX_STORE (parent_store), server, folder_name);
 		g_object_unref (server);
+
+		while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
+			g_clear_error (&local_error);
+
+			server = camel_imapx_store_get_server (CAMEL_IMAPX_STORE (parent_store), folder_name, FALSE, cancellable, &local_error);
+			if (server) {
+				success = camel_imapx_server_update_quota_info (server, folder_name, cancellable, &local_error);
+				camel_imapx_store_op_done (CAMEL_IMAPX_STORE (parent_store), server, folder_name);
+				g_object_unref (server);
+			}
+		}
+
+		if (local_error)
+			g_propagate_error (error, local_error);
 	}
 
+
 	if (!success)
 		return NULL;
 
@@ -734,6 +784,7 @@ imapx_refresh_info_sync (CamelFolder *fo
 	CamelIMAPXStore *istore;
 	CamelIMAPXServer *server;
 	const gchar *folder_name;
+	GError *local_error = NULL;
 	gboolean success = FALSE;
 
 	folder_name = camel_folder_get_full_name (folder);
@@ -752,13 +803,25 @@ imapx_refresh_info_sync (CamelFolder *fo
 	if (!camel_service_connect_sync (service, cancellable, error))
 		return FALSE;
 
-	server = camel_imapx_store_get_server (
-		istore, folder_name, cancellable, error);
+	server = camel_imapx_store_get_server (istore, folder_name, TRUE, cancellable, error);
 	if (server != NULL) {
-		success = camel_imapx_server_refresh_info (
-			server, folder, cancellable, error);
+		success = camel_imapx_server_refresh_info (server, folder, cancellable, &local_error);
 		camel_imapx_store_op_done (istore, server, folder_name);
 		g_object_unref (server);
+
+		while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
+			g_clear_error (&local_error);
+
+			server = camel_imapx_store_get_server (istore, folder_name, TRUE, cancellable, &local_error);
+			if (server != NULL) {
+				success = camel_imapx_server_refresh_info (server, folder, cancellable, &local_error);
+				camel_imapx_store_op_done (istore, server, folder_name);
+				g_object_unref (server);
+			}
+		}
+
+		if (local_error)
+			g_propagate_error (error, local_error);
 	}
 
 	return success;
@@ -920,6 +983,7 @@ imapx_synchronize_sync (CamelFolder *fol
 	CamelIMAPXStore *istore;
 	CamelIMAPXServer *server;
 	const gchar *folder_name;
+	GError *local_error = NULL;
 	gboolean success = FALSE;
 
 	folder_name = camel_folder_get_full_name (folder);
@@ -934,13 +998,25 @@ imapx_synchronize_sync (CamelFolder *fol
 		return FALSE;
 	}
 
+	/* while it can be expensive job, do not treat it as such, to avoid a blockage
+	   by really expensive jobs */
 	server = camel_imapx_store_get_server (
-		istore, folder_name, cancellable, error);
+		istore, folder_name, FALSE, cancellable, error);
 	if (server != NULL) {
 		gboolean need_to_expunge;
 
-		success = camel_imapx_server_sync_changes (
-			server, folder, cancellable, error);
+		success = camel_imapx_server_sync_changes (server, folder, cancellable, &local_error);
+		while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
+			camel_imapx_store_op_done (istore, server, folder_name);
+
+			g_clear_error (&local_error);
+			g_clear_object (&server);
+
+			server = camel_imapx_store_get_server (istore, folder_name, FALSE, cancellable, &local_error);
+			if (server) {
+				success = camel_imapx_server_sync_changes (server, folder, cancellable, &local_error);
+			}
+		}
 
 		if (success) {
 			success = imapx_move_to_real_junk (
@@ -959,12 +1035,29 @@ imapx_synchronize_sync (CamelFolder *fol
 		/* Sync twice - make sure deleted flags are written out,
 		 * then sync again incase expunge changed anything */
 
-		if (success && expunge)
-			success = camel_imapx_server_expunge (
-				server, folder, cancellable, error);
+		if (success && expunge) {
+			success = camel_imapx_server_expunge (server, folder, cancellable, &local_error);
 
-		camel_imapx_store_op_done (istore, server, folder_name);
-		g_object_unref (server);
+			while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
+				camel_imapx_store_op_done (istore, server, folder_name);
+
+				g_clear_error (&local_error);
+				g_clear_object (&server);
+
+				server = camel_imapx_store_get_server (istore, folder_name, FALSE, cancellable, &local_error);
+				if (server) {
+					success = camel_imapx_server_expunge (server, folder, cancellable, &local_error);
+				}
+			}
+		}
+
+		if (local_error)
+			g_propagate_error (error, local_error);
+
+		if (server) {
+			camel_imapx_store_op_done (istore, server, folder_name);
+			g_object_unref (server);
+		}
 	}
 
 	return success;
@@ -980,6 +1073,7 @@ imapx_synchronize_message_sync (CamelFol
 	CamelIMAPXStore *istore;
 	CamelIMAPXServer *server;
 	const gchar *folder_name;
+	GError *local_error = NULL;
 	gboolean success = FALSE;
 
 	folder_name = camel_folder_get_full_name (folder);
@@ -995,14 +1089,27 @@ imapx_synchronize_message_sync (CamelFol
 	}
 
 	server = camel_imapx_store_get_server (
-		istore, folder_name, cancellable, error);
+		istore, folder_name, FALSE, cancellable, error);
 	if (server != NULL) {
-		success = camel_imapx_server_sync_message (
-			server, folder, uid, cancellable, error);
+		success = camel_imapx_server_sync_message (server, folder, uid, cancellable, &local_error);
 		camel_imapx_store_op_done (istore, server, folder_name);
 		g_object_unref (server);
+
+		while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
+			g_clear_error (&local_error);
+
+			server = camel_imapx_store_get_server (istore, folder_name, FALSE, cancellable, &local_error);
+			if (server != NULL) {
+				success = camel_imapx_server_sync_message (server, folder, uid, cancellable, &local_error);
+				camel_imapx_store_op_done (istore, server, folder_name);
+				g_object_unref (server);
+			}
+		}
 	}
 
+	if (local_error)
+		g_propagate_error (error, local_error);
+
 	return success;
 }
 
@@ -1019,6 +1126,7 @@ imapx_transfer_messages_to_sync (CamelFo
 	CamelIMAPXStore *istore;
 	CamelIMAPXServer *server;
 	const gchar *folder_name;
+	GError *local_error = NULL;
 	gboolean success = FALSE;
 
 	folder_name = camel_folder_get_full_name (source);
@@ -1034,15 +1142,31 @@ imapx_transfer_messages_to_sync (CamelFo
 	}
 
 	server = camel_imapx_store_get_server (
-		istore, folder_name, cancellable, error);
+		istore, folder_name, FALSE, cancellable, error);
 	if (server != NULL) {
 		success = camel_imapx_server_copy_message (
 			server, source, dest, uids,
-			delete_originals, cancellable, error);
+			delete_originals, cancellable, &local_error);
 		camel_imapx_store_op_done (istore, server, folder_name);
 		g_object_unref (server);
+
+		while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
+			g_clear_error (&local_error);
+
+			server = camel_imapx_store_get_server (istore, folder_name, FALSE, cancellable, &local_error);
+			if (server != NULL) {
+				success = camel_imapx_server_copy_message (
+					server, source, dest, uids,
+					delete_originals, cancellable, &local_error);
+				camel_imapx_store_op_done (istore, server, folder_name);
+				g_object_unref (server);
+			}
+		}
 	}
 
+	if (local_error)
+		g_propagate_error (error, local_error);
+
 	/* update destination folder only if not frozen, to not update
 	 * for each single message transfer during filtering
 	 */
@@ -1102,6 +1226,7 @@ camel_imapx_folder_class_init (CamelIMAP
 	folder_class->append_message_sync = imapx_append_message_sync;
 	folder_class->expunge_sync = imapx_expunge_sync;
 	folder_class->fetch_messages_sync = imapx_fetch_messages_sync;
+	folder_class->get_message_cached = imapx_get_message_cached;
 	folder_class->get_message_sync = imapx_get_message_sync;
 	folder_class->get_quota_info_sync = imapx_get_quota_info_sync;
 	folder_class->purge_message_cache_sync = imapx_purge_message_cache_sync;
@@ -1238,12 +1363,17 @@ camel_imapx_folder_new (CamelStore *stor
 		return NULL;
 	}
 
+	/* Ensure cache will never expire, otherwise
+	* it causes redownload of messages. */
+	camel_data_cache_set_expire_age (ifolder->cache, -1);
+	camel_data_cache_set_expire_access (ifolder->cache, -1);
+
 	state_file = g_build_filename (folder_dir, "cmeta", NULL);
 	camel_object_set_state_filename (CAMEL_OBJECT (folder), state_file);
 	g_free (state_file);
 	camel_object_state_read (CAMEL_OBJECT (folder));
 
-	ifolder->search = camel_imapx_search_new ();
+	ifolder->search = camel_imapx_search_new (CAMEL_IMAPX_STORE (store));
 	g_mutex_init (&ifolder->search_lock);
 	g_mutex_init (&ifolder->stream_lock);
 	ifolder->ignore_recent = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL);
diff -up evolution-data-server-3.8.5/camel/camel-imapx-search.c.imapx-conn-manager-ext evolution-data-server-3.8.5/camel/camel-imapx-search.c
--- evolution-data-server-3.8.5/camel/camel-imapx-search.c.imapx-conn-manager-ext	2014-05-13 14:17:43.103983666 +0200
+++ evolution-data-server-3.8.5/camel/camel-imapx-search.c	2014-05-13 14:17:43.116983665 +0200
@@ -16,6 +16,7 @@
  *
  */
 
+#include "camel-imapx-store.h"
 #include "camel-imapx-search.h"
 
 #include "camel-offline-store.h"
@@ -26,13 +27,16 @@
 	((obj), CAMEL_TYPE_IMAPX_SEARCH, CamelIMAPXSearchPrivate))
 
 struct _CamelIMAPXSearchPrivate {
-	GWeakRef server;
+	GWeakRef imapx_store;
 	gint *local_data_search; /* not NULL, if testing whether all used headers are all locally available */
+
+	GCancellable *cancellable; /* not referenced */
+	GError **error; /* not referenced */
 };
 
 enum {
 	PROP_0,
-	PROP_SERVER
+	PROP_STORE
 };
 
 G_DEFINE_TYPE (
@@ -47,8 +51,8 @@ imapx_search_set_property (GObject *obje
                            GParamSpec *pspec)
 {
 	switch (property_id) {
-		case PROP_SERVER:
-			camel_imapx_search_set_server (
+		case PROP_STORE:
+			camel_imapx_search_set_store (
 				CAMEL_IMAPX_SEARCH (object),
 				g_value_get_object (value));
 			return;
@@ -64,10 +68,10 @@ imapx_search_get_property (GObject *obje
                            GParamSpec *pspec)
 {
 	switch (property_id) {
-		case PROP_SERVER:
+		case PROP_STORE:
 			g_value_take_object (
 				value,
-				camel_imapx_search_ref_server (
+				camel_imapx_search_ref_store (
 				CAMEL_IMAPX_SEARCH (object)));
 			return;
 	}
@@ -82,7 +86,7 @@ imapx_search_dispose (GObject *object)
 
 	priv = CAMEL_IMAPX_SEARCH_GET_PRIVATE (object);
 
-	g_weak_ref_set (&priv->server, NULL);
+	g_weak_ref_set (&priv->imapx_store, NULL);
 
 	/* Chain up to parent's dispose() method. */
 	G_OBJECT_CLASS (camel_imapx_search_parent_class)->dispose (object);
@@ -136,31 +140,51 @@ imapx_search_result_match_none (CamelSEx
 static CamelSExpResult *
 imapx_search_process_criteria (CamelSExp *sexp,
 			       CamelFolderSearch *search,
-			       CamelIMAPXServer *server,
+			       CamelIMAPXStore *imapx_store,
 			       const GString *criteria,
 			       const gchar *from_function)
 {
 	CamelSExpResult *result;
+	CamelIMAPXSearch *imapx_search = CAMEL_IMAPX_SEARCH (search);
 	GPtrArray *uids = NULL;
-	GError *error = NULL;
+	GError *local_error = NULL;
+	CamelIMAPXServer *imapx_server;
+	const gchar *folder_name;
+
+	/* there should always be one, held by one of the callers of this function */
+	g_warn_if_fail (imapx_store != NULL);
+
+	folder_name = camel_folder_get_full_name (search->folder);
+
+	imapx_server = camel_imapx_store_get_server (imapx_store, folder_name, TRUE, imapx_search->priv->cancellable, &local_error);
+	if (imapx_server) {
+		uids = camel_imapx_server_uid_search (imapx_server, search->folder, criteria->str, imapx_search->priv->cancellable, &local_error);
+		camel_imapx_store_op_done (imapx_store, imapx_server, folder_name);
+
+		while (!uids && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
+			g_clear_error (&local_error);
+			g_clear_object (&imapx_server);
+
+			imapx_server = camel_imapx_store_get_server (imapx_store, folder_name, TRUE, imapx_search->priv->cancellable, &local_error);
+			if (imapx_server) {
+				uids = camel_imapx_server_uid_search (imapx_server, search->folder, criteria->str, imapx_search->priv->cancellable, &local_error);
+				camel_imapx_store_op_done (imapx_store, imapx_server, folder_name);
+			}
+		}
+	}
 
-	uids = camel_imapx_server_uid_search (
-		server, search->folder, criteria->str, NULL, &error);
+	g_clear_object (&imapx_server);
 
 	/* Sanity check. */
 	g_return_val_if_fail (
-		((uids != NULL) && (error == NULL)) ||
-		((uids == NULL) && (error != NULL)), NULL);
+		((uids != NULL) && (local_error == NULL)) ||
+		((uids == NULL) && (local_error != NULL)), NULL);
+
+	if (local_error != NULL) {
+		g_propagate_error (imapx_search->priv->error, local_error);
 
-	/* XXX No allowance for errors in CamelSExp callbacks!
-	 *     Dump the error to the console and make like we
-	 *     got an empty result. */
-	if (error != NULL) {
-		g_warning (
-			"%s: (UID SEARCH %s): %s",
-			from_function, criteria->str, error->message);
+		/* Make like we've got an empty result */
 		uids = g_ptr_array_new ();
-		g_error_free (error);
 	}
 
 	if (search->current != NULL) {
@@ -183,7 +207,7 @@ imapx_search_match_all (CamelSExp *sexp,
 			CamelFolderSearch *search)
 {
 	CamelIMAPXSearch *imapx_search = CAMEL_IMAPX_SEARCH (search);
-	CamelIMAPXServer *server;
+	CamelIMAPXStore *imapx_store;
 	CamelSExpResult *result;
 	GPtrArray *summary;
 	gint local_data_search = 0, *prev_local_data_search, ii;
@@ -191,9 +215,9 @@ imapx_search_match_all (CamelSExp *sexp,
 	if (argc != 1)
 		return imapx_search_result_match_none (sexp, search);
 
-	server = camel_imapx_search_ref_server (CAMEL_IMAPX_SEARCH (search));
-	if (!server || search->current || !search->summary) {
-		g_clear_object (&server);
+	imapx_store = camel_imapx_search_ref_store (CAMEL_IMAPX_SEARCH (search));
+	if (!imapx_store || search->current || !search->summary) {
+		g_clear_object (&imapx_store);
 
 		/* Chain up to parent's method. */
 		return CAMEL_FOLDER_SEARCH_CLASS (camel_imapx_search_parent_class)->
@@ -224,7 +248,7 @@ imapx_search_match_all (CamelSExp *sexp,
 	imapx_search->priv->local_data_search = prev_local_data_search;
 
 	if (local_data_search >= 0) {
-		g_clear_object (&server);
+		g_clear_object (&imapx_store);
 
 		/* Chain up to parent's method. */
 		return CAMEL_FOLDER_SEARCH_CLASS (camel_imapx_search_parent_class)->
@@ -235,7 +259,7 @@ imapx_search_match_all (CamelSExp *sexp,
 	   but here is expected GPtrArray of matched UIDs */
 	result = camel_sexp_term_eval (sexp, argv[0]);
 
-	g_object_unref (server);
+	g_clear_object (&imapx_store);
 
 	g_return_val_if_fail (result != NULL, result);
 	g_return_val_if_fail (result->type == CAMEL_SEXP_RES_ARRAY_PTR, result);
@@ -250,7 +274,7 @@ imapx_search_body_contains (CamelSExp *s
                             CamelFolderSearch *search)
 {
 	CamelIMAPXSearch *imapx_search = CAMEL_IMAPX_SEARCH (search);
-	CamelIMAPXServer *server;
+	CamelIMAPXStore *imapx_store;
 	CamelSExpResult *result;
 	GString *criteria;
 	gint ii, jj;
@@ -269,10 +293,10 @@ imapx_search_body_contains (CamelSExp *s
 	if (argc == 0 || search->summary->len == 0)
 		return imapx_search_result_match_none (sexp, search);
 
-	server = camel_imapx_search_ref_server (CAMEL_IMAPX_SEARCH (search));
+	imapx_store = camel_imapx_search_ref_store (CAMEL_IMAPX_SEARCH (search));
 
-	/* This will be NULL if we're offline.  Search from cache. */
-	if (server == NULL) {
+	/* This will be NULL if we're offline. Search from cache. */
+	if (imapx_store == NULL) {
 		/* Chain up to parent's method. */
 		return CAMEL_FOLDER_SEARCH_CLASS (camel_imapx_search_parent_class)->
 			body_contains (sexp, argc, argv, search);
@@ -320,10 +344,10 @@ imapx_search_body_contains (CamelSExp *s
 		}
 	}
 
-	result = imapx_search_process_criteria (sexp, search, server, criteria, G_STRFUNC);
+	result = imapx_search_process_criteria (sexp, search, imapx_store, criteria, G_STRFUNC);
 
 	g_string_free (criteria, TRUE);
-	g_object_unref (server);
+	g_object_unref (imapx_store);
 
 	return result;
 }
@@ -344,7 +368,7 @@ imapx_search_header_contains (CamelSExp
 			      CamelFolderSearch *search)
 {
 	CamelIMAPXSearch *imapx_search = CAMEL_IMAPX_SEARCH (search);
-	CamelIMAPXServer *server;
+	CamelIMAPXStore *imapx_store;
 	CamelSExpResult *result;
 	const gchar *headername, *command = NULL;
 	GString *criteria;
@@ -373,10 +397,10 @@ imapx_search_header_contains (CamelSExp
 		return imapx_search_result_match_none (sexp, search);
 	}
 
-	server = camel_imapx_search_ref_server (CAMEL_IMAPX_SEARCH (search));
+	imapx_store = camel_imapx_search_ref_store (CAMEL_IMAPX_SEARCH (search));
 
-	/* This will be NULL if we're offline.  Search from cache. */
-	if (server == NULL) {
+	/* This will be NULL if we're offline. Search from cache. */
+	if (imapx_store == NULL) {
 		/* Chain up to parent's method. */
 		return CAMEL_FOLDER_SEARCH_CLASS (camel_imapx_search_parent_class)->
 			header_contains (sexp, argc, argv, search);
@@ -440,10 +464,10 @@ imapx_search_header_contains (CamelSExp
 		}
 	}
 
-	result = imapx_search_process_criteria (sexp, search, server, criteria, G_STRFUNC);
+	result = imapx_search_process_criteria (sexp, search, imapx_store, criteria, G_STRFUNC);
 
 	g_string_free (criteria, TRUE);
-	g_object_unref (server);
+	g_object_unref (imapx_store);
 
 	return result;
 }
@@ -455,7 +479,7 @@ imapx_search_header_exists (CamelSExp *s
 			    CamelFolderSearch *search)
 {
 	CamelIMAPXSearch *imapx_search = CAMEL_IMAPX_SEARCH (search);
-	CamelIMAPXServer *server;
+	CamelIMAPXStore *imapx_store;
 	CamelSExpResult *result;
 	GString *criteria;
 	gint ii;
@@ -490,10 +514,10 @@ imapx_search_header_exists (CamelSExp *s
 		return imapx_search_result_match_none (sexp, search);
 	}
 
-	server = camel_imapx_search_ref_server (CAMEL_IMAPX_SEARCH (search));
+	imapx_store = camel_imapx_search_ref_store (CAMEL_IMAPX_SEARCH (search));
 
-	/* This will be NULL if we're offline.  Search from cache. */
-	if (server == NULL) {
+	/* This will be NULL if we're offline. Search from cache. */
+	if (imapx_store == NULL) {
 		/* Chain up to parent's method. */
 		return CAMEL_FOLDER_SEARCH_CLASS (camel_imapx_search_parent_class)->
 			header_exists (sexp, argc, argv, search);
@@ -525,10 +549,10 @@ imapx_search_header_exists (CamelSExp *s
 		g_string_append_printf (criteria, "HEADER \"%s\" \"\"", headername);
 	}
 
-	result = imapx_search_process_criteria (sexp, search, server, criteria, G_STRFUNC);
+	result = imapx_search_process_criteria (sexp, search, imapx_store, criteria, G_STRFUNC);
 
 	g_string_free (criteria, TRUE);
-	g_object_unref (server);
+	g_object_unref (imapx_store);
 
 	return result;
 }
@@ -554,12 +578,12 @@ camel_imapx_search_class_init (CamelIMAP
 
 	g_object_class_install_property (
 		object_class,
-		PROP_SERVER,
+		PROP_STORE,
 		g_param_spec_object (
-			"server",
-			"Server",
-			"Server proxy for server-side searches",
-			CAMEL_TYPE_IMAPX_SERVER,
+			"store",
+			"IMAPX Store",
+			"IMAPX Store for server-side searches",
+			CAMEL_TYPE_IMAPX_STORE,
 			G_PARAM_READWRITE |
 			G_PARAM_STATIC_STRINGS));
 }
@@ -573,67 +597,105 @@ camel_imapx_search_init (CamelIMAPXSearc
 
 /**
  * camel_imapx_search_new:
+ * imapx_store: a #CamelIMAPXStore to which the search belongs
  *
  * Returns a new #CamelIMAPXSearch instance.
  *
- * The #CamelIMAPXSearch must be given a #CamelIMAPXSearch:server before
- * it can issue server-side search requests.  Otherwise it will fallback
- * to the default #CamelFolderSearch behavior.
- *
  * Returns: a new #CamelIMAPXSearch
  *
  * Since: 3.8
  **/
 CamelFolderSearch *
-camel_imapx_search_new (void)
+camel_imapx_search_new (CamelIMAPXStore *imapx_store)
 {
-	return g_object_new (CAMEL_TYPE_IMAPX_SEARCH, NULL);
+	g_return_val_if_fail (CAMEL_IS_IMAPX_STORE (imapx_store), NULL);
+
+	return g_object_new (
+		CAMEL_TYPE_IMAPX_SEARCH,
+		"store", imapx_store,
+		NULL);
 }
 
 /**
- * camel_imapx_search_ref_server:
+ * camel_imapx_search_ref_store:
  * @search: a #CamelIMAPXSearch
  *
- * Returns a #CamelIMAPXServer to use for server-side searches,
- * or %NULL when the corresponding #CamelIMAPXStore is offline.
+ * Returns a #CamelIMAPXStore to use for server-side searches,
+ * or %NULL when the store is offline.
  *
- * The returned #CamelIMAPXSearch is referenced for thread-safety and
+ * The returned #CamelIMAPXStore is referenced for thread-safety and
  * must be unreferenced with g_object_unref() when finished with it.
  *
- * Returns: a #CamelIMAPXServer, or %NULL
+ * Returns: a #CamelIMAPXStore, or %NULL
  *
  * Since: 3.8
  **/
-CamelIMAPXServer *
-camel_imapx_search_ref_server (CamelIMAPXSearch *search)
+CamelIMAPXStore *
+camel_imapx_search_ref_store (CamelIMAPXSearch *search)
 {
+	CamelIMAPXStore *imapx_store;
+
 	g_return_val_if_fail (CAMEL_IS_IMAPX_SEARCH (search), NULL);
 
-	return g_weak_ref_get (&search->priv->server);
+	imapx_store = g_weak_ref_get (&search->priv->imapx_store);
+
+	if (imapx_store && !camel_offline_store_get_online (CAMEL_OFFLINE_STORE (imapx_store)))
+		g_clear_object (&imapx_store);
+
+	return imapx_store;
 }
 
 /**
- * camel_imapx_search_set_server:
+ * camel_imapx_search_set_store:
  * @search: a #CamelIMAPXSearch
- * @server: a #CamelIMAPXServer, or %NULL
+ * @imapx_server: a #CamelIMAPXStore, or %NULL
  *
- * Sets a #CamelIMAPXServer to use for server-side searches.  Generally
+ * Sets a #CamelIMAPXStore to use for server-side searches. Generally
  * this is set for the duration of a single search when online, and then
  * reset to %NULL.
  *
  * Since: 3.8
  **/
 void
-camel_imapx_search_set_server (CamelIMAPXSearch *search,
-                               CamelIMAPXServer *server)
+camel_imapx_search_set_store (CamelIMAPXSearch *search,
+			      CamelIMAPXStore *imapx_store)
 {
 	g_return_if_fail (CAMEL_IS_IMAPX_SEARCH (search));
 
-	if (server != NULL)
-		g_return_if_fail (CAMEL_IS_IMAPX_SERVER (server));
+	if (imapx_store != NULL)
+		g_return_if_fail (CAMEL_IS_IMAPX_STORE (imapx_store));
 
-	g_weak_ref_set (&search->priv->server, server);
+	g_weak_ref_set (&search->priv->imapx_store, imapx_store);
 
-	g_object_notify (G_OBJECT (search), "server");
+	g_object_notify (G_OBJECT (search), "store");
 }
 
+/**
+ * camel_imapx_search_set_cancellable_and_error:
+ * @search: a #CamelIMAPXSearch
+ * @cancellable: a #GCancellable, or %NULL
+ * @error: a #GError, or %NULL
+ *
+ * Sets @cancellable and @error to use for server-side searches. This way
+ * the search can return accurate errors and be eventually cancelled by
+ * a user.
+ *
+ * Note: The caller is responsible to keep alive both @cancellable and @error
+ * for the whole run of the search and reset them both to NULL after
+ * the search is finished.
+ *
+ * Since: 3.14
+ **/
+void
+camel_imapx_search_set_cancellable_and_error (CamelIMAPXSearch *search,
+					      GCancellable *cancellable,
+					      GError **error)
+{
+	g_return_if_fail (CAMEL_IS_IMAPX_SEARCH (search));
+
+	if (cancellable)
+		g_return_if_fail (G_IS_CANCELLABLE (cancellable));
+
+	search->priv->cancellable = cancellable;
+	search->priv->error = error;
+}
diff -up evolution-data-server-3.8.5/camel/camel-imapx-search.h.imapx-conn-manager-ext evolution-data-server-3.8.5/camel/camel-imapx-search.h
--- evolution-data-server-3.8.5/camel/camel-imapx-search.h.imapx-conn-manager-ext	2013-07-23 13:57:45.000000000 +0200
+++ evolution-data-server-3.8.5/camel/camel-imapx-search.h	2014-05-13 14:17:43.116983665 +0200
@@ -24,7 +24,7 @@
 #define CAMEL_IMAPX_SEARCH_H
 
 #include <camel/camel-folder-search.h>
-#include <camel/camel-imapx-server.h>
+#include <camel/camel-imapx-store.h>
 
 /* Standard GObject macros */
 #define CAMEL_TYPE_IMAPX_SEARCH \
@@ -47,6 +47,9 @@
 
 G_BEGIN_DECLS
 
+/* Avoid a circular reference. */
+struct _CamelIMAPXStore;
+
 typedef struct _CamelIMAPXSearch CamelIMAPXSearch;
 typedef struct _CamelIMAPXSearchClass CamelIMAPXSearchClass;
 typedef struct _CamelIMAPXSearchPrivate CamelIMAPXSearchPrivate;
@@ -70,11 +73,15 @@ struct _CamelIMAPXSearchClass {
 
 GType		camel_imapx_search_get_type	(void) G_GNUC_CONST;
 CamelFolderSearch *
-		camel_imapx_search_new		(void);
-CamelIMAPXServer *
-		camel_imapx_search_ref_server	(CamelIMAPXSearch *search);
-void		camel_imapx_search_set_server	(CamelIMAPXSearch *search,
-						 CamelIMAPXServer *server);
+		camel_imapx_search_new		(struct _CamelIMAPXStore *imapx_store);
+struct _CamelIMAPXStore *
+		camel_imapx_search_ref_store	(CamelIMAPXSearch *search);
+void		camel_imapx_search_set_store	(CamelIMAPXSearch *search,
+						 struct _CamelIMAPXStore *imapx_store);
+void		camel_imapx_search_set_cancellable_and_error
+						(CamelIMAPXSearch *search,
+						 GCancellable *cancellable,
+						 GError **error);
 
 G_END_DECLS
 
diff -up evolution-data-server-3.8.5/camel/camel-imapx-server.c.imapx-conn-manager-ext evolution-data-server-3.8.5/camel/camel-imapx-server.c
--- evolution-data-server-3.8.5/camel/camel-imapx-server.c.imapx-conn-manager-ext	2014-05-13 14:17:43.110983665 +0200
+++ evolution-data-server-3.8.5/camel/camel-imapx-server.c	2014-05-13 14:17:43.118983665 +0200
@@ -73,6 +73,8 @@
 
 #define MAX_COMMAND_LEN 1000
 
+G_DEFINE_QUARK (camel-imapx-server-error-quark, camel_imapx_server_error)
+
 extern gint camel_application_is_exiting;
 
 /* Job-specific structs */
@@ -343,6 +345,14 @@ struct _CamelIMAPXServerPrivate {
 
 	GHashTable *known_alerts;
 	GMutex known_alerts_lock;
+
+	GMutex jobs_prop_lock;
+	GHashTable *jobs_prop_folder_paths;
+	gint jobs_prop_command_count; /* without IDLE command */
+	gint jobs_prop_expensive_command_count;
+
+	GMutex shutdown_error_lock;
+	GError *shutdown_error;
 };
 
 enum {
@@ -377,7 +387,6 @@ static gboolean	imapx_continuation		(Cam
 						 gboolean litplus,
 						 GCancellable *cancellable,
 						 GError **error);
-static gboolean	imapx_disconnect		(CamelIMAPXServer *is);
 static gboolean	imapx_is_command_queue_empty	(CamelIMAPXServer *is);
 static gint	imapx_uid_cmp			(gconstpointer ap,
 						 gconstpointer bp,
@@ -560,6 +569,159 @@ replace_untagged_descriptor (GHashTable
 }
 
 static void
+imapx_server_set_shutdown_error (CamelIMAPXServer *imapx_server,
+				 const GError *error)
+{
+	g_mutex_lock (&imapx_server->priv->shutdown_error_lock);
+
+	if (error != imapx_server->priv->shutdown_error) {
+		g_clear_error (&imapx_server->priv->shutdown_error);
+		if (error)
+			imapx_server->priv->shutdown_error = g_error_copy (error);
+	}
+
+	g_mutex_unlock (&imapx_server->priv->shutdown_error_lock);
+}
+
+static GError *
+imapx_server_dup_shutdown_error (CamelIMAPXServer *imapx_server)
+{
+	GError *error = NULL;
+
+	g_mutex_lock (&imapx_server->priv->shutdown_error_lock);
+
+	if (imapx_server->priv->shutdown_error)
+		error = g_error_copy (imapx_server->priv->shutdown_error);
+
+	g_mutex_unlock (&imapx_server->priv->shutdown_error_lock);
+
+	return error;
+}
+
+static void
+imapx_server_command_added (CamelIMAPXServer *imapx_server,
+			    CamelIMAPXCommand *command)
+{
+	CamelIMAPXJob *job;
+
+	g_return_if_fail (command != NULL);
+
+	g_mutex_lock (&imapx_server->priv->jobs_prop_lock);
+
+	job = camel_imapx_command_get_job (command);
+
+	if (job) {
+		/* without IDLE commands */
+		if (!(job->type & IMAPX_JOB_IDLE))
+			imapx_server->priv->jobs_prop_command_count++;
+
+		if ((job->type & (IMAPX_JOB_FETCH_NEW_MESSAGES | IMAPX_JOB_REFRESH_INFO)) != 0)
+			imapx_server->priv->jobs_prop_expensive_command_count++;
+	}
+
+	g_mutex_unlock (&imapx_server->priv->jobs_prop_lock);
+}
+
+static void
+imapx_server_command_removed (CamelIMAPXServer *imapx_server,
+			      CamelIMAPXCommand *command)
+{
+	CamelIMAPXJob *job;
+
+	g_return_if_fail (command != NULL);
+
+	g_mutex_lock (&imapx_server->priv->jobs_prop_lock);
+
+	job = camel_imapx_command_get_job (command);
+
+	if (job) {
+		/* without IDLE commands */
+		if (!(job->type & IMAPX_JOB_IDLE)) {
+			imapx_server->priv->jobs_prop_command_count--;
+			g_warn_if_fail (imapx_server->priv->jobs_prop_command_count >= 0);
+		}
+
+		if ((job->type & (IMAPX_JOB_FETCH_NEW_MESSAGES | IMAPX_JOB_REFRESH_INFO)) != 0) {
+			imapx_server->priv->jobs_prop_expensive_command_count--;
+			g_warn_if_fail (imapx_server->priv->jobs_prop_expensive_command_count >= 0);
+		}
+	}
+
+	g_mutex_unlock (&imapx_server->priv->jobs_prop_lock);
+}
+
+static void
+imapx_server_add_job_mailbox (CamelIMAPXServer *imapx_server,
+			      const gchar *folder_path)
+{
+	gint n_stored;
+
+	g_return_if_fail (folder_path != NULL);
+
+	g_mutex_lock (&imapx_server->priv->jobs_prop_lock);
+
+	n_stored = GPOINTER_TO_INT (g_hash_table_lookup (imapx_server->priv->jobs_prop_folder_paths, folder_path));
+	g_hash_table_insert (imapx_server->priv->jobs_prop_folder_paths, g_strdup (folder_path), GINT_TO_POINTER (n_stored + 1));
+
+	g_mutex_unlock (&imapx_server->priv->jobs_prop_lock);
+}
+
+static void
+imapx_server_remove_job_mailbox (CamelIMAPXServer *imapx_server,
+				 const gchar *folder_path)
+{
+	gint n_stored;
+
+	g_return_if_fail (folder_path != NULL);
+
+	g_mutex_lock (&imapx_server->priv->jobs_prop_lock);
+
+	n_stored = GPOINTER_TO_INT (g_hash_table_lookup (imapx_server->priv->jobs_prop_folder_paths, folder_path));
+	g_warn_if_fail (n_stored >= 1);
+
+	n_stored--;
+	if (n_stored > 0) {
+		g_hash_table_insert (imapx_server->priv->jobs_prop_folder_paths, g_strdup (folder_path), GINT_TO_POINTER (n_stored));
+	} else {
+		g_hash_table_remove (imapx_server->priv->jobs_prop_folder_paths, folder_path);
+	}
+
+	g_mutex_unlock (&imapx_server->priv->jobs_prop_lock);
+}
+
+static void
+imapx_server_job_added (CamelIMAPXServer *imapx_server,
+			CamelIMAPXJob *job)
+{
+	CamelFolder *folder;
+
+	g_return_if_fail (job != NULL);
+
+	folder = camel_imapx_job_ref_folder (job);
+
+	if (folder != NULL) {
+		imapx_server_add_job_mailbox (imapx_server, camel_folder_get_full_name (folder));
+		g_object_unref (folder);
+	}
+}
+
+static void
+imapx_server_job_removed (CamelIMAPXServer *imapx_server,
+			  CamelIMAPXJob *job)
+{
+	CamelFolder *folder;
+
+	g_return_if_fail (job != NULL);
+
+	folder = camel_imapx_job_ref_folder (job);
+
+	if (folder != NULL) {
+		imapx_server_remove_job_mailbox (imapx_server, camel_folder_get_full_name (folder));
+		g_object_unref (folder);
+	}
+}
+
+static void
 add_initial_untagged_descriptor (GHashTable *untagged_handlers,
                                  guint untagged_id)
 {
@@ -582,8 +744,8 @@ static GHashTable *
 create_initial_untagged_handler_table (void)
 {
 	GHashTable *uh = g_hash_table_new_full (
-		g_str_hash,
-		g_str_equal,
+		camel_strcase_hash,
+		camel_strcase_equal,
 		g_free,
 		NULL);
 	guint32 ii = 0;
@@ -833,12 +995,14 @@ imapx_command_start (CamelIMAPXServer *i
 {
 	CamelIMAPXStream *stream = NULL;
 	CamelIMAPXCommandPart *cp;
+	CamelIMAPXJob *job;
 	gboolean cp_continuation;
 	gboolean cp_literal_plus;
 	GList *head;
 	gboolean success = FALSE;
 	gchar *string;
 	gint retval;
+	GError *local_error = NULL;
 
 	camel_imapx_command_close (ic);
 
@@ -857,6 +1021,14 @@ imapx_command_start (CamelIMAPXServer *i
 		is->literal = ic;
 
 	camel_imapx_command_queue_push_tail (is->active, ic);
+	imapx_server_command_added (is, ic);
+
+	job = camel_imapx_command_get_job (ic);
+	if (job && g_cancellable_set_error_if_cancelled (camel_imapx_job_get_cancellable (job), &local_error)) {
+		camel_imapx_job_set_error (job, local_error);
+		g_clear_error (&local_error);
+		goto err;
+	}
 
 	stream = camel_imapx_server_ref_stream (is);
 
@@ -898,6 +1070,7 @@ imapx_command_start (CamelIMAPXServer *i
 
 err:
 	camel_imapx_command_queue_remove (is->active, ic);
+	imapx_server_command_removed (is, ic);
 
 	/* HACK: Since we're failing, make sure the command has a status
 	 *       structure and the result code indicates failure, so the
@@ -1016,6 +1189,7 @@ imapx_command_start_next (CamelIMAPXServ
 
 			ic = camel_imapx_command_ref (link->data);
 			camel_imapx_command_queue_delete_link (is->queue, link);
+			imapx_server_command_removed (is, ic);
 
 			success = imapx_command_start (
 				is, ic, cancellable, error);
@@ -1150,6 +1324,7 @@ imapx_command_start_next (CamelIMAPXServ
 
 			ic = camel_imapx_command_ref (link->data);
 			camel_imapx_command_queue_delete_link (is->queue, link);
+			imapx_server_command_removed (is, ic);
 
 			success = imapx_command_start (
 				is, ic, cancellable, error);
@@ -1223,6 +1398,7 @@ imapx_command_start_next (CamelIMAPXServ
 
 			ic = camel_imapx_command_ref (link->data);
 			camel_imapx_command_queue_delete_link (is->queue, link);
+			imapx_server_command_removed (is, ic);
 
 			success = imapx_command_start (
 				is, ic, cancellable, error);
@@ -1279,7 +1455,7 @@ imapx_command_queue (CamelIMAPXServer *i
 	if (is->state == IMAPX_SHUTDOWN) {
 		c (is->tagprefix, "refuse to queue job on disconnected server\n");
 		g_set_error (
-			error, CAMEL_IMAPX_ERROR, 1,
+			error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT,
 			"%s", _("Server disconnected"));
 
 		QUEUE_UNLOCK (is);
@@ -1294,6 +1470,7 @@ imapx_command_queue (CamelIMAPXServer *i
 	}
 
 	camel_imapx_command_queue_insert_sorted (is->queue, ic);
+	imapx_server_command_added (is, ic);
 
 	success = imapx_command_start_next (is, cancellable, error);
 
@@ -1376,38 +1553,34 @@ imapx_match_active_job (CamelIMAPXServer
 	return match;
 }
 
+/* Do *not* call this when the queue_lock is held, it can cause
+   deadlock when searching between multiple servers */
 static CamelIMAPXJob *
-imapx_is_job_in_queue (CamelIMAPXServer *is,
-                       CamelFolder *folder,
-                       guint32 type,
-                       const gchar *uid)
+imapx_server_ref_job (CamelIMAPXServer *imapx_server,
+		      CamelFolder *folder,
+		      guint32 job_type,
+		      const gchar *uid)
 {
-	GList *head, *link;
-	CamelIMAPXJob *job = NULL;
-	gboolean found = FALSE;
-
-	QUEUE_LOCK (is);
+	CamelIMAPXStore *imapx_store;
+	CamelIMAPXJob *job;
 
-	head = g_queue_peek_head_link (&is->jobs);
+	g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (imapx_server), NULL);
 
-	for (link = head; link != NULL; link = g_list_next (link)) {
-		job = (CamelIMAPXJob *) link->data;
+	/* first try its own queue */
+	job = camel_imapx_server_ref_job (imapx_server, folder, job_type, uid);
+	if (job)
+		return job;
 
-		if (!job || !(job->type & type))
-			continue;
+	/* then try queue for all the opened servers */
+	imapx_store = camel_imapx_server_ref_store (imapx_server);
+	if (!imapx_store)
+		return NULL;
 
-		if (camel_imapx_job_matches (job, folder, uid)) {
-			found = TRUE;
-			break;
-		}
-	}
+	job = camel_imapx_store_ref_job (imapx_store, folder, job_type, uid);
 
-	QUEUE_UNLOCK (is);
+	g_object_unref (imapx_store);
 
-	if (found)
-		return job;
-	else
-		return NULL;
+	return job;
 }
 
 static void
@@ -1867,8 +2040,8 @@ imapx_untagged_fetch (CamelIMAPXServer *
 					is->changes = camel_folder_change_info_new ();
 
 				camel_folder_change_info_change_uid (is->changes, uid);
-				g_free (uid);
 			}
+			g_free (uid);
 
 			if (imapx_idle_supported (is) && changed && imapx_in_idle (is)) {
 				camel_folder_summary_save_to_db (
@@ -2313,9 +2486,6 @@ imapx_untagged_bye (CamelIMAPXServer *is
                     GCancellable *cancellable,
                     GError **error)
 {
-	CamelIMAPXStore *imapx_store;
-	CamelService *service;
-	CamelServiceConnectionStatus status;
 	guchar *token = NULL;
 
 	g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
@@ -2325,7 +2495,7 @@ imapx_untagged_bye (CamelIMAPXServer *is
 	if (camel_imapx_stream_text (stream, &token, cancellable, NULL)) {
 		c (is->tagprefix, "BYE: %s\n", token);
 		g_set_error (
-			error, CAMEL_IMAPX_ERROR, 1,
+			error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT,
 			"IMAP server said BYE: %s", token);
 	}
 
@@ -2333,19 +2503,6 @@ imapx_untagged_bye (CamelIMAPXServer *is
 
 	is->state = IMAPX_SHUTDOWN;
 
-	imapx_store = camel_imapx_server_ref_store (is);
-	service = CAMEL_SERVICE (imapx_store);
-	status = camel_service_get_connection_status (service);
-
-	/* Do not disconnect the service if we're still connecting.
-	 * camel_service_disconnect_sync() will cancel the connect
-	 * operation and the server message will get replaced with
-	 * a generic "Operation was cancelled" message. */
-	if (status == CAMEL_SERVICE_CONNECTED)
-		camel_service_disconnect_sync (service, FALSE, NULL, NULL);
-
-	g_object_unref (imapx_store);
-
 	return FALSE;
 }
 
@@ -2399,10 +2556,16 @@ imapx_untagged_ok_no_bad (CamelIMAPXServ
 			select_folder = g_weak_ref_get (&is->select_folder);
 			select_pending = g_weak_ref_get (&is->select_pending);
 
-			if (select_folder == NULL)
+			if (select_folder)
+				imapx_server_remove_job_mailbox (is, camel_folder_get_full_name (select_folder));
+
+			if (select_folder == NULL) {
 				g_weak_ref_set (
 					&is->select_folder,
 					select_pending);
+				if (select_pending)
+					imapx_server_add_job_mailbox (is, camel_folder_get_full_name (select_pending));
+			}
 
 			g_clear_object (&select_folder);
 			g_clear_object (&select_pending);
@@ -2849,6 +3012,7 @@ imapx_completion (CamelIMAPXServer *is,
 
 	camel_imapx_command_ref (ic);
 	camel_imapx_command_queue_remove (is->active, ic);
+	imapx_server_command_removed (is, ic);
 	camel_imapx_command_queue_push_tail (is->done, ic);
 	camel_imapx_command_unref (ic);
 
@@ -3058,10 +3222,18 @@ imapx_register_job (CamelIMAPXServer *is
 	if (is->state >= IMAPX_INITIALISED) {
 		QUEUE_LOCK (is);
 		g_queue_push_head (&is->jobs, camel_imapx_job_ref (job));
+		imapx_server_job_added (is, job);
 		QUEUE_UNLOCK (is);
 
+	} else if (is->state <= IMAPX_SHUTDOWN) {
+		e (is->tagprefix, "Server is shutdown/disconnected, try reconnect.");
+		g_set_error (error,
+			CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT,
+			_("Not authenticated"));
+		return FALSE;
+
 	} else {
-		e (is->tagprefix, "NO connection yet, maybe user cancelled jobs earlier ?");
+		e (is->tagprefix, "Not connected yet, maybe user cancelled jobs earlier?");
 		g_set_error (
 			error, CAMEL_SERVICE_ERROR,
 			CAMEL_SERVICE_ERROR_NOT_CONNECTED,
@@ -3080,8 +3252,10 @@ imapx_unregister_job (CamelIMAPXServer *
 		camel_imapx_job_done (job);
 
 	QUEUE_LOCK (is);
-	if (g_queue_remove (&is->jobs, job))
+	if (g_queue_remove (&is->jobs, job)) {
+		imapx_server_job_removed (is, job);
 		camel_imapx_job_unref (job);
+	}
 	QUEUE_UNLOCK (is);
 }
 
@@ -3152,6 +3326,7 @@ imapx_command_idle_done (CamelIMAPXServe
 	IDLE_UNLOCK (idle);
 
 	imapx_unregister_job (is, job);
+
 	camel_imapx_command_unref (ic);
 
 	return success;
@@ -3347,8 +3522,11 @@ imapx_idle_thread (gpointer data)
 			break;
 	}
 
+	IDLE_LOCK (is->idle);
 	g_clear_error (&local_error);
 	is->idle->idle_thread = NULL;
+	IDLE_UNLOCK (is->idle);
+
 	return NULL;
 }
 
@@ -3521,6 +3699,11 @@ imapx_command_select_done (CamelIMAPXSer
 		c (is->tagprefix, "Select failed\n");
 
 		g_mutex_lock (&is->select_lock);
+		folder = g_weak_ref_get (&is->select_folder);
+		if (folder) {
+			imapx_server_remove_job_mailbox (is, camel_folder_get_full_name (folder));
+			g_object_unref (folder);
+		}
 		folder = g_weak_ref_get (&is->select_pending);
 		g_weak_ref_set (&is->select_folder, NULL);
 		g_weak_ref_set (&is->select_pending, NULL);
@@ -3548,7 +3731,9 @@ imapx_command_select_done (CamelIMAPXSer
 
 		while ((link = g_queue_pop_head (&trash)) != NULL) {
 			CamelIMAPXCommand *cw = link->data;
+			camel_imapx_command_ref (cw);
 			camel_imapx_command_queue_delete_link (is->queue, link);
+			imapx_server_command_removed (is, cw);
 			g_queue_push_tail (&failed, cw);
 		}
 
@@ -3563,6 +3748,7 @@ imapx_command_select_done (CamelIMAPXSer
 
 			if (!CAMEL_IS_IMAPX_JOB (job)) {
 				g_warn_if_reached ();
+				camel_imapx_command_unref (cw);
 				continue;
 			}
 
@@ -3572,6 +3758,7 @@ imapx_command_select_done (CamelIMAPXSer
 				cw->status = imapx_copy_status (ic->status);
 
 			cw->complete (is, cw, NULL, NULL);
+			camel_imapx_command_unref (cw);
 		}
 
 		g_propagate_error (error, local_error);
@@ -3601,22 +3788,16 @@ imapx_command_select_done (CamelIMAPXSer
 			/* We don't want to fetch new messages if the command we selected this
 			 * folder for is *already* fetching all messages (i.e. scan_changes).
 			 * Bug #667725. */
-			CamelIMAPXJob *job = imapx_is_job_in_queue (
+			CamelIMAPXJob *job = imapx_server_ref_job (
 				is, folder, IMAPX_JOB_REFRESH_INFO, NULL);
 			if (job) {
-				RefreshInfoData *data = camel_imapx_job_get_data (job);
-
-				if (data->scan_changes) {
-					c (is->tagprefix, "Will not fetch_new_messages when already in scan_changes\n");
-					goto no_fetch_new;
-				}
+				camel_imapx_job_unref (job);
+				c (
+					is->tagprefix,
+					"Will not fetch_new_messages when already refreshing information\n");
+			} else {
+				imapx_server_fetch_new_messages (is, folder, TRUE, TRUE, NULL, NULL);
 			}
-			imapx_server_fetch_new_messages (is, folder, TRUE, TRUE, NULL, NULL);
-			/* We don't do this right now because we want the new messages to
-			 * update the unseen count. */
-			//ifolder->uidnext_on_server = is->uidnext;
-		no_fetch_new:
-			;
 		}
 		ifolder->uidvalidity_on_server = is->uidvalidity;
 		selected_folder = camel_folder_get_full_name (folder);
@@ -3638,6 +3819,9 @@ imapx_command_select_done (CamelIMAPXSer
 
 	camel_imapx_command_unref (ic);
 
+	if (selected_folder)
+		imapx_server_add_job_mailbox (is, selected_folder);
+
 	g_signal_emit (is, signals[SELECT_CHANGED], 0, selected_folder);
 
 	return success;
@@ -4132,7 +4316,7 @@ camel_imapx_server_authenticate (CamelIM
 
 	g_return_val_if_fail (
 		CAMEL_IS_IMAPX_SERVER (is),
-		CAMEL_AUTHENTICATION_REJECTED);
+		CAMEL_AUTHENTICATION_ERROR);
 
 	store = camel_imapx_server_ref_store (is);
 
@@ -4202,8 +4386,27 @@ camel_imapx_server_authenticate (CamelIM
 		result = CAMEL_AUTHENTICATION_ERROR;
 	else if (ic->status->result == IMAPX_OK)
 		result = CAMEL_AUTHENTICATION_ACCEPTED;
-	else
-		result = CAMEL_AUTHENTICATION_REJECTED;
+	else if (ic->status->result == IMAPX_NO) {
+		if (camel_imapx_store_get_authenticating_concurrent_connection (store)) {
+			/* At least one connection succeeded, probably max connection limit
+			   set on the server had been reached, thus use special error code
+			   for it, to instruct the connection manager to decrease the limit
+			   and use already created connection. */
+			g_set_error_literal (
+				error, CAMEL_IMAPX_SERVER_ERROR,
+				CAMEL_IMAPX_SERVER_ERROR_CONCURRENT_CONNECT_FAILED,
+				ic->status->text ? ic->status->text : _("Unknown error"));
+			result = CAMEL_AUTHENTICATION_ERROR;
+		} else {
+			result = CAMEL_AUTHENTICATION_REJECTED;
+		}
+	} else {
+		g_set_error_literal (
+			error, CAMEL_SERVICE_ERROR,
+			CAMEL_SERVICE_ERROR_CANT_AUTHENTICATE,
+			ic->status->text ? ic->status->text : _("Unknown error"));
+		result = CAMEL_AUTHENTICATION_ERROR;
+	}
 
 	/* Forget old capabilities after login. */
 	if (result == CAMEL_AUTHENTICATION_ACCEPTED) {
@@ -4348,7 +4551,7 @@ imapx_reconnect (CamelIMAPXServer *is,
 
 exception:
 
-	imapx_disconnect (is);
+	camel_imapx_server_disconnect (is);
 
 	if (is->cinfo) {
 		imapx_free_capability (is->cinfo);
@@ -4457,6 +4660,13 @@ imapx_command_fetch_message_done (CamelI
 			_("Failed to close the tmp stream"));
 	}
 
+	if (success && g_cancellable_set_error_if_cancelled (cancellable, error)) {
+		success = FALSE;
+		g_prefix_error (
+			error, "%s: ",
+			_("Error fetching message"));
+	}
+
 	if (success) {
 		gchar *cur_filename;
 		gchar *tmp_filename;
@@ -5488,7 +5698,6 @@ imapx_job_fetch_new_messages_start (Came
 		_("Fetching summary information for new messages in '%s'"),
 		camel_folder_get_display_name (folder));
 
-	//printf ("Fetch order: %d/%d\n", fetch_order, CAMEL_SORT_DESCENDING);
 	if (diff > uidset_size || fetch_order == CAMEL_SORT_DESCENDING) {
 		ic = camel_imapx_command_new (
 			is, "FETCH", folder,
@@ -6837,7 +7046,7 @@ imapx_job_sync_changes_matches (CamelIMA
 /* we cancel all the commands and their jobs, so associated jobs will be notified */
 static void
 cancel_all_jobs (CamelIMAPXServer *is,
-                 GError *error)
+                 const GError *error)
 {
 	CamelIMAPXCommandQueue *queue;
 	GList *head, *link;
@@ -6847,11 +7056,21 @@ cancel_all_jobs (CamelIMAPXServer *is,
 
 	queue = camel_imapx_command_queue_new ();
 
+	imapx_server_set_shutdown_error (is, error);
+
 	QUEUE_LOCK (is);
 
 	camel_imapx_command_queue_transfer (is->queue, queue);
 	camel_imapx_command_queue_transfer (is->active, queue);
 
+	head = camel_imapx_command_queue_peek_head_link (queue);
+	for (link = head; link != NULL; link = g_list_next (link)) {
+		CamelIMAPXCommand *ic = link->data;
+
+		if (ic)
+			imapx_server_command_removed (is, ic);
+	}
+
 	QUEUE_UNLOCK (is);
 
 	head = camel_imapx_command_queue_peek_head_link (queue);
@@ -6871,7 +7090,14 @@ cancel_all_jobs (CamelIMAPXServer *is,
 		if (!CAMEL_IS_IMAPX_JOB (job))
 			continue;
 
-		camel_imapx_job_cancel (job);
+		if (error) {
+			/* Insert an error into the CamelIMAPXCommand to be
+			 * propagated when the completion callback function
+			 * calls camel_imapx_command_set_error_if_failed(). */
+			camel_imapx_job_set_error (job, error);
+		} else {
+			camel_imapx_job_cancel (job);
+		}
 
 		/* Send a NULL GError since we already cancelled
 		 * the job and we're not interested in individual
@@ -6916,6 +7142,7 @@ imapx_parser_thread (gpointer d)
 	GCancellable *cancellable;
 	gboolean have_stream;
 	GError *local_error = NULL;
+	GError *shutdown_error;
 
 	QUEUE_LOCK (is);
 	/* Do not use CamelOperation here, because it can be cancelled at
@@ -6991,8 +7218,28 @@ imapx_parser_thread (gpointer d)
 		}
 
 		/* Jump out of the loop if an error occurred. */
-		if (local_error != NULL)
+		if (local_error != NULL) {
+			camel_imapx_debug (io, is->tagprefix, "Data read failed with error '%s'\n", local_error->message);
+
+			/* Sadly, G_IO_ERROR_FAILED is also used for 'Connection reset by peer' error */
+			if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_FAILED)) {
+				local_error->domain = CAMEL_IMAPX_SERVER_ERROR;
+				local_error->code = CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT;
+			}
+
+			imapx_server_set_shutdown_error (is, local_error);
+
+			/* Call the signal early, certain thread interleaving can cause the closed connection
+			   being reused on the following reconnect attempt. There is also re-setting
+			   the shutdown_error above, because the signal handler in connection manager
+			   also calls camel_imapx_server_shutdown(), but without the error, while we want
+			   to have there propagated the "try reconnect" error instead. As there is no
+			   guarantee that it'll be called, then we also quit the parser's mainloop and
+			   call the imapx_abort_all_commands() below - just in case. */
+			g_signal_emit (is, signals[SHUTDOWN], 0, local_error);
+
 			break;
+		}
 
 		stream = camel_imapx_server_ref_stream (is);
 		if (stream != NULL) {
@@ -7020,7 +7267,12 @@ imapx_parser_thread (gpointer d)
 	QUEUE_UNLOCK (is);
 
 	is->parser_quit = FALSE;
-	g_signal_emit (is, signals[SHUTDOWN], 0);
+
+	shutdown_error = imapx_server_dup_shutdown_error (is);
+
+	g_signal_emit (is, signals[SHUTDOWN], 0, shutdown_error);
+
+	g_clear_error (&shutdown_error);
 
 	g_object_unref (is);
 
@@ -7103,7 +7355,7 @@ imapx_server_dispose (GObject *object)
 	if (server->cinfo && imapx_idle_supported (server))
 		imapx_exit_idle (server);
 
-	imapx_disconnect (server);
+	camel_imapx_server_disconnect (server);
 
 	g_weak_ref_set (&server->priv->store, NULL);
 
@@ -7141,6 +7393,12 @@ imapx_server_finalize (GObject *object)
 	g_hash_table_destroy (is->priv->known_alerts);
 	g_mutex_clear (&is->priv->known_alerts_lock);
 
+	g_mutex_clear (&is->priv->jobs_prop_lock);
+	g_hash_table_destroy (is->priv->jobs_prop_folder_paths);
+
+	g_mutex_clear (&is->priv->shutdown_error_lock);
+	g_clear_error (&is->priv->shutdown_error);
+
 	/* Chain up to parent's finalize() method. */
 	G_OBJECT_CLASS (camel_imapx_server_parent_class)->finalize (object);
 }
@@ -7216,6 +7474,7 @@ camel_imapx_server_class_init (CamelIMAP
 	/**
 	 * CamelIMAPXServer::shutdown
 	 * @server: the #CamelIMAPXServer which emitted the signal
+	 * @error: a #GError, which caused the shutdown; can be %NULL
 	 **/
 	signals[SHUTDOWN] = g_signal_new (
 		"shutdown",
@@ -7223,8 +7482,8 @@ camel_imapx_server_class_init (CamelIMAP
 		G_SIGNAL_RUN_FIRST,
 		G_STRUCT_OFFSET (CamelIMAPXServerClass, shutdown),
 		NULL, NULL,
-		g_cclosure_marshal_VOID__VOID,
-		G_TYPE_NONE, 0);
+		g_cclosure_marshal_VOID__BOXED,
+		G_TYPE_NONE, 1, G_TYPE_ERROR);
 
 	class->tagprefix = 'A';
 }
@@ -7239,6 +7498,12 @@ camel_imapx_server_init (CamelIMAPXServe
 	g_mutex_init (&is->priv->stream_lock);
 	g_mutex_init (&is->priv->search_results_lock);
 	g_mutex_init (&is->priv->known_alerts_lock);
+	g_mutex_init (&is->priv->jobs_prop_lock);
+	g_mutex_init (&is->priv->shutdown_error_lock);
+
+	is->priv->jobs_prop_folder_paths = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+	is->priv->jobs_prop_command_count = 0;
+	is->priv->jobs_prop_expensive_command_count = 0;
 
 	is->queue = camel_imapx_command_queue_new ();
 	is->active = camel_imapx_command_queue_new ();
@@ -7259,6 +7524,8 @@ camel_imapx_server_init (CamelIMAPXServe
 	is->changes = camel_folder_change_info_new ();
 	is->parser_quit = FALSE;
 
+	is->priv->shutdown_error = NULL;
+
 	is->priv->known_alerts = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
 }
 
@@ -7312,11 +7579,23 @@ camel_imapx_server_ref_stream (CamelIMAP
 	return stream;
 }
 
-static gboolean
-imapx_disconnect (CamelIMAPXServer *is)
+gboolean
+camel_imapx_server_disconnect (CamelIMAPXServer *is)
 {
 	gboolean ret = TRUE;
 
+	/*QUEUE_LOCK (is);
+	is->state = IMAPX_SHUTDOWN;
+
+	is->parser_quit = TRUE;
+
+	if (is->cancellable != NULL) {
+		g_cancellable_cancel (is->cancellable);
+		g_object_unref (is->cancellable);
+		is->cancellable = NULL;
+	}
+	QUEUE_UNLOCK (is);*/
+
 	g_mutex_lock (&is->priv->stream_lock);
 
 	if (is->priv->stream != NULL) {
@@ -7387,18 +7666,15 @@ imapx_server_get_message (CamelIMAPXServ
 	gboolean registered;
 	gboolean success;
 
-	QUEUE_LOCK (is);
-
-	if ((job = imapx_is_job_in_queue (is, folder, IMAPX_JOB_GET_MESSAGE, uid))) {
+	if ((job = imapx_server_ref_job (is, folder, IMAPX_JOB_GET_MESSAGE, uid))) {
 		/* Promote the existing GET_MESSAGE
 		 * job's priority if ours is higher. */
 		if (pri > job->pri)
 			job->pri = pri;
 
-		QUEUE_UNLOCK (is);
-
 		/* Wait for the job to finish. */
 		camel_imapx_job_wait (job);
+		camel_imapx_job_unref (job);
 
 		/* Disregard errors here.  If we failed to retreive the
 		 * message from cache (implying the job we were waiting
@@ -7407,10 +7683,10 @@ imapx_server_get_message (CamelIMAPXServ
 			ifolder->cache, "cur", uid, NULL);
 		if (stream != NULL)
 			return stream;
-
-		QUEUE_LOCK (is);
 	}
 
+	QUEUE_LOCK (is);
+
 	mi = camel_folder_summary_get (folder->summary, uid);
 	if (!mi) {
 		g_set_error (
@@ -7700,15 +7976,17 @@ camel_imapx_server_refresh_info (CamelIM
 
 	full_name = camel_folder_get_full_name (folder);
 
-	QUEUE_LOCK (is);
-
 	/* Both RefreshInfo and Fetch messages can't operate simultaneously */
-	if (imapx_is_job_in_queue (is, folder, IMAPX_JOB_REFRESH_INFO, NULL) ||
-		imapx_is_job_in_queue (is, folder, IMAPX_JOB_FETCH_MESSAGES, NULL)) {
-		QUEUE_UNLOCK (is);
+	job = imapx_server_ref_job (is, folder, IMAPX_JOB_REFRESH_INFO, NULL);
+	if (!job)
+		job = imapx_server_ref_job (is, folder, IMAPX_JOB_FETCH_MESSAGES, NULL);
+	if (job) {
+		camel_imapx_job_unref (job);
 		return TRUE;
 	}
 
+	QUEUE_LOCK (is);
+
 	data = g_slice_new0 (RefreshInfoData);
 	data->changes = camel_folder_change_info_new ();
 
@@ -7963,13 +8241,11 @@ imapx_server_sync_changes (CamelIMAPXSer
 
 	/* TODO above code should go into changes_start */
 
-	QUEUE_LOCK (is);
-
-	if ((job = imapx_is_job_in_queue (is, folder, IMAPX_JOB_SYNC_CHANGES, NULL))) {
+	if ((job = imapx_server_ref_job (is, folder, IMAPX_JOB_SYNC_CHANGES, NULL))) {
 		if (pri > job->pri)
 			job->pri = pri;
 
-		QUEUE_UNLOCK (is);
+		camel_imapx_job_unref (job);
 
 		imapx_sync_free_user (on_user);
 		imapx_sync_free_user (off_user);
@@ -7977,6 +8253,8 @@ imapx_server_sync_changes (CamelIMAPXSer
 		return TRUE;
 	}
 
+	QUEUE_LOCK (is);
+
 	data = g_slice_new0 (SyncChangesData);
 	data->folder = g_object_ref (folder);
 	data->changed_uids = changed_uids;  /* takes ownership */
@@ -8036,13 +8314,15 @@ camel_imapx_server_expunge (CamelIMAPXSe
 	gboolean success;
 
 	/* Do we really care to wait for this one to finish? */
-	QUEUE_LOCK (is);
 
-	if (imapx_is_job_in_queue (is, folder, IMAPX_JOB_EXPUNGE, NULL)) {
-		QUEUE_UNLOCK (is);
+	job = imapx_server_ref_job (is, folder, IMAPX_JOB_EXPUNGE, NULL);
+	if (job) {
+		camel_imapx_job_unref (job);
 		return TRUE;
 	}
 
+	QUEUE_LOCK (is);
+
 	job = camel_imapx_job_new (cancellable);
 	job->type = IMAPX_JOB_EXPUNGE;
 	job->start = imapx_job_expunge_start;
@@ -8270,15 +8550,17 @@ camel_imapx_server_fetch_messages (Camel
 	firstuid = strtoull (uid, NULL, 10);
 	g_free (uid);
 
-	QUEUE_LOCK (is);
-
 	/* Both RefreshInfo and Fetch messages can't operate simultaneously */
-	if (imapx_is_job_in_queue (is, folder, IMAPX_JOB_REFRESH_INFO, NULL) ||
-		imapx_is_job_in_queue (is, folder, IMAPX_JOB_FETCH_MESSAGES, NULL)) {
-		QUEUE_UNLOCK (is);
+	job = imapx_server_ref_job (is, folder, IMAPX_JOB_REFRESH_INFO, NULL);
+	if (!job)
+		job = imapx_server_ref_job (is, folder, IMAPX_JOB_FETCH_MESSAGES, NULL);
+	if (job) {
+		camel_imapx_job_unref (job);
 		return TRUE;
 	}
 
+	QUEUE_LOCK (is);
+
 	data = g_slice_new0 (RefreshInfoData);
 	data->changes = camel_folder_change_info_new ();
 	data->fetch_msg_limit = limit;
@@ -8450,55 +8732,54 @@ camel_imapx_server_uid_search (CamelIMAP
 	return results;
 }
 
-IMAPXJobQueueInfo *
-camel_imapx_server_get_job_queue_info (CamelIMAPXServer *is)
+gboolean
+camel_imapx_server_folder_name_in_jobs (CamelIMAPXServer *imapx_server,
+					const gchar *folder_path)
 {
-	IMAPXJobQueueInfo *jinfo = g_new0 (IMAPXJobQueueInfo, 1);
-	CamelFolder *select_folder;
-	CamelIMAPXJob *job = NULL;
-	GList *head, *link;
+	gboolean res;
 
-	QUEUE_LOCK (is);
+	g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (imapx_server), FALSE);
+	g_return_val_if_fail (folder_path != NULL, FALSE);
 
-	jinfo->queue_len = g_queue_get_length (&is->jobs);
-	jinfo->folders = g_hash_table_new_full (
-		(GHashFunc) g_str_hash,
-		(GEqualFunc) g_str_equal,
-		(GDestroyNotify) g_free,
-		(GDestroyNotify) NULL);
+	g_mutex_lock (&imapx_server->priv->jobs_prop_lock);
 
-	head = g_queue_peek_head_link (&is->jobs);
+	res = GPOINTER_TO_INT (g_hash_table_lookup (imapx_server->priv->jobs_prop_folder_paths, folder_path)) > 0;
 
-	for (link = head; link != NULL; link = g_list_next (link)) {
-		CamelFolder *folder;
+	g_mutex_unlock (&imapx_server->priv->jobs_prop_lock);
 
-		job = (CamelIMAPXJob *) link->data;
-		folder = camel_imapx_job_ref_folder (job);
+	return res;
+}
 
-		if (folder != NULL) {
-			gchar *folder_name;
+gboolean
+camel_imapx_server_has_expensive_command (CamelIMAPXServer *imapx_server)
+{
+	gboolean res;
 
-			folder_name = camel_folder_dup_full_name (folder);
-			g_hash_table_add (jinfo->folders, folder_name);
+	g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (imapx_server), FALSE);
 
-			g_object_unref (folder);
-		}
-	}
+	g_mutex_lock (&imapx_server->priv->jobs_prop_lock);
 
-	select_folder = g_weak_ref_get (&is->select_folder);
+	res = imapx_server->priv->jobs_prop_expensive_command_count > 0;
 
-	if (select_folder != NULL) {
-		gchar *folder_name;
+	g_mutex_unlock (&imapx_server->priv->jobs_prop_lock);
 
-		folder_name = camel_folder_dup_full_name (select_folder);
-		g_hash_table_add (jinfo->folders, folder_name);
+	return res;
+}
 
-		g_object_unref (select_folder);
-	}
+gint
+camel_imapx_server_get_command_count (CamelIMAPXServer *imapx_server)
+{
+	guint32 res;
 
-	QUEUE_UNLOCK (is);
+	g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (imapx_server), -1);
+
+	g_mutex_lock (&imapx_server->priv->jobs_prop_lock);
 
-	return jinfo;
+	res = imapx_server->priv->jobs_prop_command_count;
+
+	g_mutex_unlock (&imapx_server->priv->jobs_prop_lock);
+
+	return res;
 }
 
 /**
@@ -8575,3 +8856,108 @@ camel_imapx_server_command_run (CamelIMA
 
 	return ok;
 }
+
+/**
+ * camel_imapx_server_is_job_in_queue:
+ * @imapx_server: a #CamelIMAPXServer instance
+ * @folder: a folder to search job for
+ * @job_type: a job type specifier to search for
+ * @uid: optional message UID for which the job might be searched
+ *
+ * Searches queue of jobs for the particular job. The returned job
+ * is referenced for thread safety, unref it with camel_imapx_job_unref().
+ *
+ * Returns: %NULL, if such job could not be found, or a referenced job.
+ **/
+CamelIMAPXJob *
+camel_imapx_server_ref_job (CamelIMAPXServer *imapx_server,
+			    CamelFolder *folder,
+			    guint32 job_type,
+			    const gchar *uid)
+{
+	GList *head, *link;
+	CamelIMAPXJob *job = NULL;
+	gboolean found = FALSE;
+
+	g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (imapx_server), NULL);
+
+	QUEUE_LOCK (imapx_server);
+
+	head = g_queue_peek_head_link (&imapx_server->jobs);
+
+	for (link = head; link != NULL; link = g_list_next (link)) {
+		job = (CamelIMAPXJob *) link->data;
+
+		if (!job || !(job->type & job_type))
+			continue;
+
+		if (camel_imapx_job_matches (job, folder, uid)) {
+			found = TRUE;
+			camel_imapx_job_ref (job);
+			break;
+		}
+	}
+
+	QUEUE_UNLOCK (imapx_server);
+
+	return found ? job : NULL;
+}
+
+/**
+ * camel_imapx_server_shutdown:
+ * @is: a #CamelIMAPXServer
+ * @error: a #GError with which cancel any pending jobs
+ *
+ * Signals the server to shut down command processing. A #CamelIMAPXStore
+ * should call this immediately before unreferencing its server instance.
+ * Note, the server instance may linger a short time after this function
+ * returns as its own worker threads finish.
+ *
+ * Since: 3.12
+ **/
+void
+camel_imapx_server_shutdown (CamelIMAPXServer *is,
+			     const GError *error)
+{
+	GCancellable *cancellable;
+	GError *shutdown_error_copy = NULL;
+
+	g_return_if_fail (CAMEL_IS_IMAPX_SERVER (is));
+
+	QUEUE_LOCK (is);
+
+	is->parser_quit = TRUE;
+	is->state = IMAPX_SHUTDOWN;
+
+	if (is->cancellable)
+		cancellable = g_object_ref (is->cancellable);
+	else
+		cancellable = NULL;
+
+	QUEUE_UNLOCK (is);
+
+	if (!error) {
+		shutdown_error_copy = imapx_server_dup_shutdown_error (is);
+		error = shutdown_error_copy;
+	}
+
+	if (error) {
+		cancel_all_jobs (is, error);
+	} else {
+		GError *local_error = NULL;
+
+		g_set_error (
+			&local_error, CAMEL_SERVICE_ERROR,
+			CAMEL_SERVICE_ERROR_UNAVAILABLE,
+			"Shutting down");
+
+		cancel_all_jobs (is, local_error);
+
+		g_clear_error (&local_error);
+	}
+
+	if (cancellable)
+		g_cancellable_cancel (cancellable);
+	g_clear_object (&cancellable);
+	g_clear_error (&shutdown_error_copy);
+}
diff -up evolution-data-server-3.8.5/camel/camel-imapx-server.h.imapx-conn-manager-ext evolution-data-server-3.8.5/camel/camel-imapx-server.h
--- evolution-data-server-3.8.5/camel/camel-imapx-server.h.imapx-conn-manager-ext	2013-07-23 13:57:54.000000000 +0200
+++ evolution-data-server-3.8.5/camel/camel-imapx-server.h	2014-05-13 14:17:43.118983665 +0200
@@ -53,18 +53,27 @@
 #define IMAPX_MODE_READ (1 << 0)
 #define IMAPX_MODE_WRITE (1 << 1)
 
+#define CAMEL_IMAPX_SERVER_ERROR (camel_imapx_server_error_quark ())
+
 G_BEGIN_DECLS
 
+typedef enum {
+	CAMEL_IMAPX_SERVER_ERROR_CONCURRENT_CONNECT_FAILED,
+	CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT
+} CamelIMAPXServerError;
+
+GQuark		camel_imapx_server_error_quark		(void) G_GNUC_CONST;
+
 /* Avoid a circular reference. */
 struct _CamelIMAPXStore;
 struct _CamelIMAPXSettings;
+struct _CamelIMAPXJob;
 
 typedef struct _CamelIMAPXServer CamelIMAPXServer;
 typedef struct _CamelIMAPXServerClass CamelIMAPXServerClass;
 typedef struct _CamelIMAPXServerPrivate CamelIMAPXServerPrivate;
 
 typedef struct _CamelIMAPXIdle CamelIMAPXIdle;
-struct _IMAPXJobQueueInfo;
 
 /* untagged response handling */
 typedef gboolean
@@ -167,7 +176,8 @@ struct _CamelIMAPXServerClass {
 	/* Signals */
 	void	(*select_changed)	(CamelIMAPXServer *is,
 					 const gchar *selected_folder);
-	void	(*shutdown)		(CamelIMAPXServer *is);
+	void	(*shutdown)		(CamelIMAPXServer *is,
+					 const GError *error);
 
 	gchar tagprefix;
 };
@@ -184,6 +194,9 @@ CamelIMAPXStream *
 gboolean	camel_imapx_server_connect	(CamelIMAPXServer *is,
 						 GCancellable *cancellable,
 						 GError **error);
+gboolean	camel_imapx_server_disconnect	(CamelIMAPXServer *is);
+void		camel_imapx_server_shutdown	(CamelIMAPXServer *is,
+						 const GError *error);
 gboolean	imapx_connect_to_server		(CamelIMAPXServer *is,
 						 GCancellable *cancellable,
 						 GError **error);
@@ -278,9 +291,13 @@ GPtrArray *	camel_imapx_server_uid_searc
 						 const gchar *criteria,
 						 GCancellable *cancellable,
 						 GError **error);
-struct _IMAPXJobQueueInfo *
-		camel_imapx_server_get_job_queue_info
-						(CamelIMAPXServer *is);
+gboolean	camel_imapx_server_folder_name_in_jobs
+						(CamelIMAPXServer *imapx_server,
+						 const gchar *folder_path);
+gboolean	camel_imapx_server_has_expensive_command
+						(CamelIMAPXServer *imapx_server);
+gint		camel_imapx_server_get_command_count
+						(CamelIMAPXServer *imapx_server);
 const CamelIMAPXUntaggedRespHandlerDesc *
 		camel_imapx_server_register_untagged_handler
 						(CamelIMAPXServer *is,
@@ -290,6 +307,11 @@ gboolean	camel_imapx_server_command_run
 						 CamelIMAPXCommand *ic,
 						 GCancellable *cancellable,
 						 GError **error);
+struct _CamelIMAPXJob *
+		camel_imapx_server_ref_job	(CamelIMAPXServer *imapx_server,
+						 CamelFolder *folder,
+						 guint32 job_type,
+						 const gchar *uid);
 
 G_END_DECLS
 
diff -up evolution-data-server-3.8.5/camel/camel-imapx-settings.c.imapx-conn-manager-ext evolution-data-server-3.8.5/camel/camel-imapx-settings.c
--- evolution-data-server-3.8.5/camel/camel-imapx-settings.c.imapx-conn-manager-ext	2013-07-23 13:57:50.000000000 +0200
+++ evolution-data-server-3.8.5/camel/camel-imapx-settings.c	2014-05-13 14:17:43.118983665 +0200
@@ -516,7 +516,7 @@ camel_imapx_settings_class_init (CamelIM
 			"Number of concurrent IMAP connections to use",
 			MIN_CONCURRENT_CONNECTIONS,
 			MAX_CONCURRENT_CONNECTIONS,
-			5,
+			3,
 			G_PARAM_READWRITE |
 			G_PARAM_CONSTRUCT |
 			G_PARAM_STATIC_STRINGS));
diff -up evolution-data-server-3.8.5/camel/camel-imapx-store.c.imapx-conn-manager-ext evolution-data-server-3.8.5/camel/camel-imapx-store.c
--- evolution-data-server-3.8.5/camel/camel-imapx-store.c.imapx-conn-manager-ext	2014-05-13 14:17:43.114983665 +0200
+++ evolution-data-server-3.8.5/camel/camel-imapx-store.c	2014-05-13 14:17:43.119983665 +0200
@@ -40,6 +40,7 @@
 #include <glib/gi18n-lib.h>
 
 #include "camel-imapx-folder.h"
+#include "camel-imapx-job.h"
 #include "camel-imapx-server.h"
 #include "camel-imapx-settings.h"
 #include "camel-imapx-store.h"
@@ -59,6 +60,7 @@
 struct _CamelIMAPXStorePrivate {
 	GHashTable *quota_info;
 	GMutex quota_info_lock;
+	gboolean is_concurrent_connection;
 };
 
 enum {
@@ -260,11 +262,12 @@ imapx_get_name (CamelService *service,
 CamelIMAPXServer *
 camel_imapx_store_get_server (CamelIMAPXStore *istore,
                               const gchar *folder_name,
+			      gboolean for_expensive_job,
                               GCancellable *cancellable,
                               GError **error)
 {
 	return camel_imapx_conn_manager_get_connection (
-		istore->con_man, folder_name, cancellable, error);
+		istore->con_man, folder_name, for_expensive_job, cancellable, error);
 }
 
 void
@@ -286,7 +289,7 @@ imapx_connect_sync (CamelService *servic
 	CamelIMAPXStore *istore = (CamelIMAPXStore *) service;
 	CamelIMAPXServer *server;
 
-	server = camel_imapx_store_get_server (istore, NULL, cancellable, error);
+	server = camel_imapx_store_get_server (istore, NULL, FALSE, cancellable, error);
 	if (server) {
 		g_object_unref (server);
 		return TRUE;
@@ -309,7 +312,7 @@ imapx_disconnect_sync (CamelService *ser
 	res = service_class->disconnect_sync (service, clean, cancellable, error);
 
 	if (istore->con_man != NULL)
-		camel_imapx_conn_manager_close_connections (istore->con_man);
+		camel_imapx_conn_manager_close_connections (istore->con_man, NULL);
 
 	return res;
 }
@@ -333,7 +336,7 @@ imapx_authenticate_sync (CamelService *s
 
 	g_return_val_if_fail (
 		CAMEL_IS_IMAPX_SERVER (server),
-		CAMEL_AUTHENTICATION_REJECTED);
+		CAMEL_AUTHENTICATION_ERROR);
 
 	return camel_imapx_server_authenticate (
 		server, mechanism, cancellable, error);
@@ -657,22 +660,35 @@ imapx_subscribe_folder (CamelStore *stor
 {
 	CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
 	CamelIMAPXServer *server;
+	GError *local_error = NULL;
 	gboolean success;
 
 	if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
 		return TRUE;
 
-	server = camel_imapx_store_get_server (istore, NULL, cancellable, error);
+	server = camel_imapx_store_get_server (istore, NULL, FALSE, cancellable, error);
 	if (!server)
 		return FALSE;
 
 	if (folder_name && *folder_name == '/')
 		folder_name++;
 
-	success = camel_imapx_server_manage_subscription (
-		server, folder_name, TRUE, cancellable, error);
+	success = camel_imapx_server_manage_subscription (server, folder_name, TRUE, cancellable, &local_error);
 	g_object_unref (server);
 
+	while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
+		g_clear_error (&local_error);
+
+		server = camel_imapx_store_get_server (istore, NULL, FALSE, cancellable, &local_error);
+		if (server) {
+			success = camel_imapx_server_manage_subscription (server, folder_name, TRUE, cancellable, &local_error);
+			g_object_unref (server);
+		}
+	}
+
+	if (local_error)
+		g_propagate_error (error, local_error);
+
 	if (success)
 		imapx_mark_folder_subscribed (istore, folder_name, emit_signal);
 
@@ -688,22 +704,35 @@ imapx_unsubscribe_folder (CamelStore *st
 {
 	CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
 	CamelIMAPXServer *server;
+	GError *local_error = NULL;
 	gboolean success;
 
 	if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store)))
 		return TRUE;
 
-	server = camel_imapx_store_get_server (istore, NULL, cancellable, error);
+	server = camel_imapx_store_get_server (istore, NULL, FALSE, cancellable, error);
 	if (!server)
 		return FALSE;
 
 	if (folder_name && *folder_name == '/')
 		folder_name++;
 
-	success = camel_imapx_server_manage_subscription (
-		server, folder_name, FALSE, cancellable, error);
+	success = camel_imapx_server_manage_subscription (server, folder_name, FALSE, cancellable, &local_error);
 	g_object_unref (server);
 
+	while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
+		g_clear_error (&local_error);
+
+		server = camel_imapx_store_get_server (istore, NULL, FALSE, cancellable, &local_error);
+		if (server) {
+			success = camel_imapx_server_manage_subscription (server, folder_name, FALSE, cancellable, &local_error);
+			g_object_unref (server);
+		}
+	}
+
+	if (local_error)
+		g_propagate_error (error, local_error);
+
 	if (success)
 		imapx_unmark_folder_subscribed (istore, folder_name, emit_signal);
 
@@ -1012,9 +1041,23 @@ fetch_folders_for_pattern (CamelIMAPXSto
 	GPtrArray *folders;
 	GError *local_error = NULL;
 
+	g_object_ref (server);
+
 	folders = camel_imapx_server_list (
 		server, pattern, flags, ext, cancellable, &local_error);
-	if (folders == NULL || local_error) {
+
+	while (!folders && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
+		g_clear_error (&local_error);
+		g_clear_object (&server);
+
+		server = camel_imapx_store_get_server (istore, NULL, FALSE, cancellable, &local_error);
+		if (server)
+			folders = camel_imapx_server_list (server, pattern, flags, ext, cancellable, &local_error);
+	}
+
+	if (folders == NULL || local_error || !server) {
+		g_clear_object (&server);
+
 		if (local_error)
 			g_propagate_error (error, local_error);
 		return FALSE;
@@ -1022,6 +1065,8 @@ fetch_folders_for_pattern (CamelIMAPXSto
 
 	add_folders_to_summary (istore, server, folders, table, (flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED));
 
+	g_clear_object (&server);
+
 	g_ptr_array_foreach (folders, free_list, folders);
 	g_ptr_array_free (folders, TRUE);
 
@@ -1057,7 +1102,7 @@ fetch_folders_for_namespaces (CamelIMAPX
 	GHashTable *folders = NULL;
 	GList *namespaces = NULL, *l;
 
-	server = camel_imapx_store_get_server (istore, NULL, cancellable, error);
+	server = camel_imapx_store_get_server (istore, NULL, FALSE, cancellable, error);
 	if (!server)
 		return NULL;
 
@@ -1581,6 +1626,7 @@ imapx_store_create_folder_sync (CamelSto
 	gchar *real_name, *full_name, *parent_real;
 	CamelFolderInfo *fi = NULL;
 	gchar dir_sep = 0;
+	GError *local_error = NULL;
 	gboolean success;
 
 	if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store))) {
@@ -1591,7 +1637,7 @@ imapx_store_create_folder_sync (CamelSto
 		return NULL;
 	}
 
-	server = camel_imapx_store_get_server (istore, NULL, cancellable, error);
+	server = camel_imapx_store_get_server (istore, NULL, FALSE, cancellable, error);
 	if (!server)
 		return NULL;
 
@@ -1642,10 +1688,22 @@ imapx_store_create_folder_sync (CamelSto
 	full_name = imapx_concat (istore, parent_real, real_name);
 	g_free (real_name);
 
-	success = camel_imapx_server_create_folder (
-		server, full_name, cancellable, error);
+	success = camel_imapx_server_create_folder (server, full_name, cancellable, &local_error);
 	g_object_unref (server);
 
+	while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
+		g_clear_error (&local_error);
+
+		server = camel_imapx_store_get_server (istore, NULL, FALSE, cancellable, &local_error);
+		if (server) {
+			success = camel_imapx_server_create_folder (server, full_name, cancellable, &local_error);
+			g_object_unref (server);
+		}
+	}
+
+	if (local_error)
+		g_propagate_error (error, local_error);
+
 	if (success) {
 		CamelIMAPXStoreInfo *si;
 
@@ -1670,6 +1728,7 @@ imapx_store_delete_folder_sync (CamelSto
 {
 	CamelIMAPXStore *istore = (CamelIMAPXStore *) store;
 	CamelIMAPXServer *server;
+	GError *local_error = NULL;
 	gboolean success;
 
 	if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store))) {
@@ -1681,14 +1740,28 @@ imapx_store_delete_folder_sync (CamelSto
 	}
 	/* Use INBOX connection as the implementation would try to select inbox to ensure
 	 * we are not selected on the folder being deleted */
-	server = camel_imapx_store_get_server (istore, "INBOX", cancellable, error);
+	server = camel_imapx_store_get_server (istore, "INBOX", FALSE, cancellable, error);
 	if (!server)
 		return FALSE;
 
-	success = camel_imapx_server_delete_folder (
-		server, folder_name, cancellable, error);
+	success = camel_imapx_server_delete_folder (server, folder_name, cancellable, &local_error);
+	camel_imapx_store_op_done (istore, server, "INBOX");
 	g_object_unref (server);
 
+	while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
+		g_clear_error (&local_error);
+
+		server = camel_imapx_store_get_server (istore, "INBOX", FALSE, cancellable, &local_error);
+		if (server) {
+			success = camel_imapx_server_delete_folder (server, folder_name, cancellable, &local_error);
+			camel_imapx_store_op_done (istore, server, "INBOX");
+			g_object_unref (server);
+		}
+	}
+
+	if (local_error)
+		g_propagate_error (error, local_error);
+
 	if (success)
 		imapx_delete_folder_from_cache (istore, folder_name);
 
@@ -1734,11 +1807,28 @@ imapx_store_rename_folder_sync (CamelSto
 
 	/* Use INBOX connection as the implementation would try to select inbox to ensure
 	 * we are not selected on the folder being renamed */
-	server = camel_imapx_store_get_server (istore, "INBOX", cancellable, error);
+	server = camel_imapx_store_get_server (istore, "INBOX", FALSE, cancellable, error);
 	if (server) {
-		success = camel_imapx_server_rename_folder (
-			server, old, new, cancellable, error);
+		GError *local_error = NULL;
+
+		success = camel_imapx_server_rename_folder (server, old, new, cancellable, &local_error);
+		camel_imapx_store_op_done (istore, server, "INBOX");
 		g_object_unref (server);
+
+		while (!success && g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
+			g_clear_error (&local_error);
+
+			server = camel_imapx_store_get_server (istore, "INBOX", FALSE, cancellable, &local_error);
+			if (server) {
+				success = camel_imapx_server_rename_folder (server, old, new, cancellable, &local_error);
+				camel_imapx_store_op_done (istore, server, "INBOX");
+				g_object_unref (server);
+			}
+		}
+
+		if (local_error)
+			g_propagate_error (error, local_error);
+
 	}
 
 	if (!success) {
@@ -1787,9 +1877,18 @@ imapx_store_noop_sync (CamelStore *store
 
 	for (link = list; link != NULL; link = g_list_next (link)) {
 		CamelIMAPXServer *server = CAMEL_IMAPX_SERVER (link->data);
+		GError *local_error = NULL;
 
 		/* we just return last noops value, technically not correct though */
-		success = camel_imapx_server_noop (server, NULL, cancellable, error);
+		success = camel_imapx_server_noop (server, NULL, cancellable, &local_error);
+
+		if (g_error_matches (local_error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT)) {
+			g_clear_error (&local_error);
+			break;
+		} else if (local_error) {
+			g_propagate_error (error, local_error);
+		}
+
 		if (!success)
 			break;
 	}
@@ -2081,3 +2180,49 @@ camel_imapx_store_set_quota_info (CamelI
 	g_mutex_unlock (&store->priv->quota_info_lock);
 }
 
+void
+camel_imapx_store_set_authenticating_concurrent_connection (CamelIMAPXStore *store,
+							    gboolean is_concurrent_connection)
+{
+	g_return_if_fail (CAMEL_IS_IMAPX_STORE (store));
+
+	store->priv->is_concurrent_connection = is_concurrent_connection;
+}
+
+gboolean
+camel_imapx_store_get_authenticating_concurrent_connection (CamelIMAPXStore *store)
+{
+	g_return_val_if_fail (CAMEL_IS_IMAPX_STORE (store), FALSE);
+
+	return store->priv->is_concurrent_connection;
+}
+
+/* Tries to find matching job among all active connections.
+   See camel_imapx_server_ref_job() for more information on parameters
+   and return values.
+*/
+CamelIMAPXJob *
+camel_imapx_store_ref_job (CamelIMAPXStore *imapx_store,
+			   CamelFolder *folder,
+			   guint32 job_type,
+			   const gchar *uid)
+{
+	GList *servers, *siter;
+	CamelIMAPXJob *job = NULL;
+
+	g_return_val_if_fail (CAMEL_IS_IMAPX_STORE (imapx_store), NULL);
+
+	servers = camel_imapx_conn_manager_get_connections (imapx_store->con_man);
+
+	for (siter = servers; siter; siter = g_list_next (siter)) {
+		CamelIMAPXServer *imapx_server = siter->data;
+
+		job = camel_imapx_server_ref_job (imapx_server, folder, job_type, uid);
+		if (job)
+			break;
+	}
+
+	g_list_free_full (servers, g_object_unref);
+
+	return job;
+}
diff -up evolution-data-server-3.8.5/camel/camel-imapx-store.h.imapx-conn-manager-ext evolution-data-server-3.8.5/camel/camel-imapx-store.h
--- evolution-data-server-3.8.5/camel/camel-imapx-store.h.imapx-conn-manager-ext	2013-07-23 13:57:56.000000000 +0200
+++ evolution-data-server-3.8.5/camel/camel-imapx-store.h	2014-05-13 14:17:43.119983665 +0200
@@ -55,6 +55,9 @@
 
 G_BEGIN_DECLS
 
+/* Avoid a circular reference. */
+struct _CamelIMAPXJob;
+
 typedef struct _CamelIMAPXStore CamelIMAPXStore;
 typedef struct _CamelIMAPXStoreClass CamelIMAPXStoreClass;
 typedef struct _CamelIMAPXStorePrivate CamelIMAPXStorePrivate;
@@ -93,6 +96,7 @@ GType		camel_imapx_store_get_type	(void)
 CamelIMAPXServer *
 		camel_imapx_store_get_server	(CamelIMAPXStore *store,
 						 const gchar *folder_name,
+						 gboolean for_expensive_job,
 						 GCancellable *cancellable,
 						 GError **error);
 void		camel_imapx_store_op_done	(CamelIMAPXStore *istore,
@@ -106,6 +110,16 @@ void		camel_imapx_store_set_quota_info
 						(CamelIMAPXStore *store,
 						 const gchar *quota_root_name,
 						 const CamelFolderQuotaInfo *info);
+void		camel_imapx_store_set_authenticating_concurrent_connection
+						(CamelIMAPXStore *store,
+						 gboolean is_concurrent_connection);
+gboolean	camel_imapx_store_get_authenticating_concurrent_connection
+						(CamelIMAPXStore *store);
+struct _CamelIMAPXJob *
+		camel_imapx_store_ref_job	(CamelIMAPXStore *imapx_store,
+						 CamelFolder *folder,
+						 guint32 job_type,
+						 const gchar *uid);
 
 G_END_DECLS
 
diff -up evolution-data-server-3.8.5/camel/camel-imapx-stream.c.imapx-conn-manager-ext evolution-data-server-3.8.5/camel/camel-imapx-stream.c
--- evolution-data-server-3.8.5/camel/camel-imapx-stream.c.imapx-conn-manager-ext	2013-07-23 13:57:55.000000000 +0200
+++ evolution-data-server-3.8.5/camel/camel-imapx-stream.c	2014-05-13 14:17:43.119983665 +0200
@@ -34,6 +34,7 @@
 #include <camel/camel-stream-mem.h>
 
 #include "camel-imapx-utils.h"
+#include "camel-imapx-server.h"
 #include "camel-imapx-stream.h"
 
 #define CAMEL_IMAPX_STREAM_GET_PRIVATE(obj) \
@@ -92,10 +93,14 @@ imapx_stream_fill (CamelIMAPXStream *is,
 			 * that to be an error. But we do -- we should only be here
 			 * if we *know* there are data to receive. So set the error
 			 * accordingly */
-			if (!left)
+			if (!left) {
+				io (is->tagprefix, "Failed to read any bytes into buffer of size %d (from buffer size %d, last read:'%.20s')\n", (gint) (is->priv->bufsize - (is->priv->end - is->priv->buf)), is->priv->bufsize, (const gchar *) is->priv->buf);
+
 				g_set_error (
-					error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
+					error, CAMEL_IMAPX_SERVER_ERROR, CAMEL_IMAPX_SERVER_ERROR_TRY_RECONNECT,
 					_("Source stream returned no data"));
+			}
+
 			return -1;
 		}
 	}
diff -up evolution-data-server-3.8.5/camel/camel-imapx-utils.c.imapx-conn-manager-ext evolution-data-server-3.8.5/camel/camel-imapx-utils.c
--- evolution-data-server-3.8.5/camel/camel-imapx-utils.c.imapx-conn-manager-ext	2014-05-13 14:17:43.110983665 +0200
+++ evolution-data-server-3.8.5/camel/camel-imapx-utils.c	2014-05-13 14:17:43.119983665 +0200
@@ -430,8 +430,8 @@ create_initial_capabilities_table (void)
 	 *      to free hash table
 	 */
 	capa_htable = g_hash_table_new_full (
-		g_str_hash,
-		g_str_equal,
+		camel_strcase_hash,
+		camel_strcase_equal,
 		g_free,
 		NULL);
 
@@ -456,7 +456,7 @@ imapx_parse_capability (CamelIMAPXStream
 	GError *local_error = NULL;
 
 	cinfo = g_malloc0 (sizeof (*cinfo));
-	cinfo->auth_types = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL);
+	cinfo->auth_types = g_hash_table_new_full (camel_strcase_hash, camel_strcase_equal, (GDestroyNotify) g_free, NULL);
 
 	/* FIXME: handle auth types */
 	while ((tok = camel_imapx_stream_token (stream, &token, &len, cancellable, &local_error)) != '\n' &&
@@ -2607,10 +2607,3 @@ imapx_get_temp_uid (void)
 
 	return res;
 }
-
-void
-camel_imapx_destroy_job_queue_info (IMAPXJobQueueInfo *jinfo)
-{
-	g_hash_table_destroy (jinfo->folders);
-	g_free (jinfo);
-}
diff -up evolution-data-server-3.8.5/camel/camel-imapx-utils.h.imapx-conn-manager-ext evolution-data-server-3.8.5/camel/camel-imapx-utils.h
--- evolution-data-server-3.8.5/camel/camel-imapx-utils.h.imapx-conn-manager-ext	2013-07-23 13:57:45.000000000 +0200
+++ evolution-data-server-3.8.5/camel/camel-imapx-utils.h	2014-05-13 14:17:43.119983665 +0200
@@ -365,17 +365,6 @@ gboolean	camel_imapx_parse_quotaroot	(st
 						 GError **error);
 
 /* ********************************************************************** */
-typedef struct _IMAPXJobQueueInfo {
-	guint queue_len;
-
-	/* list of folders for which jobs are in the queue */
-	GHashTable *folders;
-} IMAPXJobQueueInfo;
-
-void		camel_imapx_destroy_job_queue_info
-						(IMAPXJobQueueInfo *jinfo);
-
-/* ********************************************************************** */
 
 extern guchar imapx_specials[256];
 
diff -up evolution-data-server-3.8.5/camel/camel-service.c.imapx-conn-manager-ext evolution-data-server-3.8.5/camel/camel-service.c
--- evolution-data-server-3.8.5/camel/camel-service.c.imapx-conn-manager-ext	2013-07-23 14:01:51.000000000 +0200
+++ evolution-data-server-3.8.5/camel/camel-service.c	2014-05-13 14:17:43.120983665 +0200
@@ -934,7 +934,7 @@ service_authenticate_finish (CamelServic
 	g_return_val_if_fail (
 		g_simple_async_result_is_valid (
 		result, G_OBJECT (service), service_authenticate),
-		CAMEL_AUTHENTICATION_REJECTED);
+		CAMEL_AUTHENTICATION_ERROR);
 
 	simple = G_SIMPLE_ASYNC_RESULT (result);
 	async_context = g_simple_async_result_get_op_res_gpointer (simple);
@@ -2007,12 +2007,12 @@ camel_service_authenticate_sync (CamelSe
 
 	g_return_val_if_fail (
 		CAMEL_IS_SERVICE (service),
-		CAMEL_AUTHENTICATION_REJECTED);
+		CAMEL_AUTHENTICATION_ERROR);
 
 	class = CAMEL_SERVICE_GET_CLASS (service);
 	g_return_val_if_fail (
 		class->authenticate_sync != NULL,
-		CAMEL_AUTHENTICATION_REJECTED);
+		CAMEL_AUTHENTICATION_ERROR);
 
 	result = class->authenticate_sync (
 		service, mechanism, cancellable, error);
@@ -2096,15 +2096,15 @@ camel_service_authenticate_finish (Camel
 
 	g_return_val_if_fail (
 		CAMEL_IS_SERVICE (service),
-		CAMEL_AUTHENTICATION_REJECTED);
+		CAMEL_AUTHENTICATION_ERROR);
 	g_return_val_if_fail (
 		G_IS_ASYNC_RESULT (result),
-		CAMEL_AUTHENTICATION_REJECTED);
+		CAMEL_AUTHENTICATION_ERROR);
 
 	class = CAMEL_SERVICE_GET_CLASS (service);
 	g_return_val_if_fail (
 		class->authenticate_finish,
-		CAMEL_AUTHENTICATION_REJECTED);
+		CAMEL_AUTHENTICATION_ERROR);
 
 	return class->authenticate_finish (service, result, error);
 }