Patch: rework IMAP IDLE locks behavior



	Hi,

	I'm attaching a complete rework of the lock behavior of Tinymail
(camel) imap IDLE implementation.

	The problem we want to fix is:
	* Sometimes IDLE thread causes deathlocks (connect lock, idle lock,
g_thread_join, etc). This happens easily when there are disconnects, or
when we switch fast among folders.

	The main ideas with this implementation:
	* Provided a count of reasons to stop idle because of connect lock.
	* If a caller has taken connect lock, then it should do the send done
stuff itself.
	* Idle thread has the connect lock always when it's in the body of the
loop.
	* In any point, if we want to  take the connect lock, then we should
stop idle. No partial idle can be alive when we want to connect.
	* Camel queue enables/disables the possibility to start idle. That's
for avoiding running IDLE / SEND DONE in the middle of queued
operations.

	With these changes, the behavior is good, and I didn't get any new
hang. I tested this both from Modest and Tinymail Demo UI, for 4 days,
and still didn't get hangs.

	Anyway, as the patch is really complex and long, I would ask for
careful review). It's one of the most annoying bugs we have in Tinymail
and it may be a solution for this :).

Changelog... the description of the patch in this mail would be a good
explanation ;). I could also add a deep explanation of the way this is
working in docs directory, for developers reference.

-- 
José Dapena Paz <jdapena igalia com>
Igalia
Index: libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-store.c
===================================================================
--- libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-store.c	(revisión: 3792)
+++ libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-store.c	(copia de trabajo)
@@ -110,6 +110,7 @@
 static gboolean imap_connect_offline (CamelService *service, CamelException *ex);
 static gboolean imap_disconnect_online (CamelService *service, gboolean clean, CamelException *ex);
 static gboolean imap_disconnect_offline (CamelService *service, gboolean clean, CamelException *ex);
+static void imap_can_idle (CamelService *service, gboolean can_idle);
 static void imap_noop (CamelStore *store, CamelException *ex);
 static CamelFolder *imap_get_junk(CamelStore *store, CamelException *ex);
 static CamelFolder *imap_get_trash(CamelStore *store, CamelException *ex);
@@ -262,10 +263,14 @@
 }
 
 void
-camel_imap_store_stop_idle (CamelImapStore *store)
+_camel_imap_store_stop_idle (CamelImapStore *store)
 {
+	/* We avoid to stop or start the idle thread from the msg gmsgstore */
+	if (store->current_folder && CAMEL_IS_IMAP_FOLDER (store->current_folder) && 
+	    (CamelService *) store->current_folder->parent_store != (CamelService *) store)
+		return;
 	if (store->current_folder && CAMEL_IS_IMAP_FOLDER (store->current_folder))
-		camel_imap_folder_stop_idle (store->current_folder);
+		camel_imap_folder_stop_idle_in_connect_lock (store->current_folder);
 	else {
 		g_static_rec_mutex_lock (store->idle_lock);
 		g_static_rec_mutex_lock (store->idle_prefix_lock);
@@ -305,13 +310,172 @@
 
 
 void
-camel_imap_store_start_idle (CamelImapStore *store)
+_camel_imap_store_start_idle (CamelImapStore *store)
 {
+	/* We avoid to stop or start the idle thread from the msg gmsgstore */
+	if (store->current_folder && CAMEL_IS_IMAP_FOLDER (store->current_folder) && store->current_folder->parent_store != store)
+		return;
 	if (store->current_folder && CAMEL_IS_IMAP_FOLDER (store->current_folder))
 		camel_imap_folder_start_idle (store->current_folder);
 }
 
+void
+_camel_imap_store_stop_idle_connect_lock (CamelImapStore *store)
+{
+#ifdef IDLE_DEBUG
+	gint depth;
+#endif
+	/* This operation should behave as atomic. This should open
+	 * an area where imap operations requested by user are executed,
+	 * and block idle loop meanwhile.
+	 *
+	 * The operation does three things:
+	 *   - Stops the idle thread
+	 *   - Increases the idle wait reasons
+	 *   - Locks the connect
+	 */
+
+	if (store->idle_thread != NULL && g_thread_self () == store->idle_thread) {
+		idle_debug ("Called from idle thread\n");
+		return;
+	}
+
+	idle_debug ("Waiting for idle wait reasons lock\n");
+	g_static_rec_mutex_lock (store->idle_wait_reasons_lock);
+	idle_debug ("Idle wait reasons lock depth: %d\n", store->idle_wait_reasons_lock->depth);
+
+	store->idle_wait_reasons++;
+	idle_debug ("Idle wait reasons %d -> %d\n", store->idle_wait_reasons - 1, store->idle_wait_reasons);
+		
+	CAMEL_SERVICE_REC_LOCK (store, connect_lock);
+	if (store->capabilities & IMAP_CAPABILITY_IDLE) {
+		if (!store->already_in_stop_idle) {
+			store->already_in_stop_idle = TRUE;
+			camel_imap_store_stop_idle (store);
+			store->already_in_stop_idle = FALSE;
+		}
+	}
+#ifdef IDLE_DEBUG
+	depth = store->idle_wait_reasons_lock->depth;
+#endif
+	g_static_rec_mutex_unlock (store->idle_wait_reasons_lock);
+	idle_debug ("Idle wait reasons lock depth (%d->%d)\n", depth, depth - 1);
+		
+}
+	
 static void
+decrease_wait_reasons (CamelImapStore *store)
+{
+	g_assert (store->idle_wait_reasons > 0);
+	store->idle_wait_reasons--;
+	idle_debug ("Idle wait reasons %d -> %d\n", store->idle_wait_reasons + 1, store->idle_wait_reasons);
+	CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+}
+
+void
+_camel_imap_store_connect_unlock_start_idle (CamelImapStore *store)
+{
+#ifdef IDLE_DEBUG
+	gint depth;
+#endif
+	/* This operation should behave as atomic. This should close a
+	 * camel_imap_store_stop_idle_connect_lock, so they should be
+	 * paired.
+	 *
+	 * The operation does three things:
+	 *   - Decrease the count for reasons to make idle stop (the number of
+	 *     connect lock recursions that should force idle to wait)
+	 *   - Unlock connect
+	 *   - If the reasons count is 0, then start idle.
+	 */
+
+	if (store->idle_thread != NULL && g_thread_self () == store->idle_thread) {
+		idle_debug ("Called from idle thread\n");
+		return;
+	}
+
+	idle_debug ("Waiting for idle wait reasons lock\n");
+	g_static_rec_mutex_lock (store->idle_wait_reasons_lock);
+	idle_debug ("Idle wait reasons lock depth: %d\n", store->idle_wait_reasons_lock->depth);
+
+	decrease_wait_reasons (store);
+	if (store->idle_wait_reasons == 0 && (store->capabilities & IMAP_CAPABILITY_IDLE))
+		camel_imap_store_start_idle (store);
+#ifdef IDLE_DEBUG
+	depth = store->idle_wait_reasons_lock->depth;
+#endif
+	g_static_rec_mutex_unlock (store->idle_wait_reasons_lock);
+	idle_debug ("Idle wait reasons lock depth (%d->%d)\n", depth, depth - 1);
+	
+}
+
+void
+_camel_imap_store_start_idle_if_unlocked (CamelImapStore *store)
+{
+#ifdef IDLE_DEBUG
+	gint depth;
+#endif
+
+	/* This is for starting idle when we finish operations and we have no reasons to
+	 * keep blocking idle */
+
+	if (store->idle_thread != NULL && g_thread_self () == store->idle_thread) {
+		idle_debug ("Called from idle thread\n");
+		return;
+	}
+
+	idle_debug ("Waiting for idle wait reasons lock\n");
+	g_static_rec_mutex_lock (store->idle_wait_reasons_lock);
+	idle_debug ("Idle wait reasons lock depth: %d\n", store->idle_wait_reasons_lock->depth);
+
+	if (store->idle_wait_reasons == 0 && (store->capabilities & IMAP_CAPABILITY_IDLE))
+		camel_imap_store_start_idle (store);
+#ifdef IDLE_DEBUG
+	depth = store->idle_wait_reasons_lock->depth;
+#endif
+	g_static_rec_mutex_unlock (store->idle_wait_reasons_lock);
+	idle_debug ("Idle wait reasons lock depth (%d)\n", depth);
+	
+}
+
+void
+_camel_imap_store_connect_unlock_no_start_idle (CamelImapStore *store)
+{
+#ifdef IDLE_DEBUG
+	gint depth;
+#endif
+	/* Just very similar to connect_unlock_start_idle. The main
+	 * difference is this function does not start idle if the lock
+	 * count is 0. Why is this required? A pair of connect_lock_stop_idle
+	 * and this one should be added wrapping imap code that can go deeper
+	 * in the wait reasons, if there's a connect lock we cannot control outside.
+	 *
+	 * Example: camel_service_online does a lock on connect. We do imap operations
+	 * inside. We then may deathlock because our imap operations finish starting
+	 * idle. We'll wait with the connect_lock until idle is ready, but idle won't
+	 * be ready as it needs the connect lock to be ready.
+	 */
+
+	if (store->idle_thread != NULL && g_thread_self () == store->idle_thread) {
+		idle_debug ("Called from idle thread\n");
+		return;
+	}
+	       
+	idle_debug ("Waiting for idle wait reasons lock\n");
+	g_static_rec_mutex_lock (store->idle_wait_reasons_lock);
+	idle_debug ("Idle wait reasons lock depth: %d\n", store->idle_wait_reasons_lock->depth);
+
+	decrease_wait_reasons (store);
+
+#ifdef IDLE_DEBUG	
+	depth = store->idle_wait_reasons_lock->depth;
+#endif
+	g_static_rec_mutex_unlock (store->idle_wait_reasons_lock);
+	idle_debug ("Idle wait reasons lock depth (%d->%d)\n", depth, depth - 1);
+}
+
+
+static void
 imap_restore (CamelStore *store)
 {
 	CamelImapStore *imap_store = (CamelImapStore *) store;
@@ -325,7 +489,6 @@
 			camel_imap_response_free (imap_store, response2);
 		}
 		camel_exception_clear (&nex);
-		camel_imap_store_start_idle (imap_store);
 	}
 
 	return;
@@ -352,6 +515,7 @@
 	camel_service_class->construct = construct;
 	camel_service_class->query_auth_types = query_auth_types;
 	camel_service_class->get_name = imap_get_name;
+	camel_service_class->can_idle = imap_can_idle;
 
 	camel_store_class->get_local_size = imapstore_get_local_size;
 	camel_store_class->delete_cache = imap_delete_cache;
@@ -399,7 +563,9 @@
 
 	let_idle_die (imap_store, TRUE);
 
+	CAMEL_SERVICE_REC_LOCK (imap_store, connect_lock);
 	camel_imap_store_stop_idle (imap_store);
+	CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
 
 	if (imap_store->current_folder) {
 		camel_object_unhook_event (imap_store->current_folder, "finalize",
@@ -458,6 +624,9 @@
 	g_free (imap_store->sum_lock);
 	imap_store->sum_lock = NULL;
 
+	g_free (imap_store->idle_wait_reasons_lock);
+	imap_store->idle_wait_reasons_lock = NULL;
+
 }
 
 static void
@@ -482,6 +651,11 @@
 	imap_store->sum_lock = g_new0 (GStaticRecMutex, 1);
 	g_static_rec_mutex_init (imap_store->sum_lock);
 
+	imap_store->idle_wait_reasons_lock = g_new0 (GStaticRecMutex, 1);
+	g_static_rec_mutex_init (imap_store->idle_wait_reasons_lock);
+	imap_store->idle_wait_reasons = 0;
+	imap_store->already_in_stop_idle = FALSE;
+
 	imap_store->dontdistridlehack = FALSE;
 
 	imap_store->idle_sleep_set = FALSE;
@@ -490,6 +664,7 @@
 
 	imap_store->in_idle = FALSE;
 	imap_store->idle_cont = FALSE;
+	imap_store->idle_send_done_happened = FALSE;
 
 	g_static_rec_mutex_lock (imap_store->idle_t_lock);
 	imap_store->idle_thread = NULL;
@@ -497,6 +672,8 @@
 
 	imap_store->idle_prefix = NULL;
 
+	imap_store->idle_blocked = TRUE;
+
 	imap_store->istream = NULL;
 	imap_store->ostream = NULL;
 	imap_store->has_login = FALSE;
@@ -796,6 +973,17 @@
 }
 
 static void
+imap_can_idle (CamelService *service, gboolean can_idle)
+{
+	CamelImapStore *store = (CamelImapStore *) service;
+
+	store->idle_blocked = !can_idle;
+	idle_debug ("Idle blocked: %s\n", store->idle_blocked?"yes":"no");
+	if (!store->idle_blocked)
+		camel_imap_store_start_idle_if_unlocked (store);
+}
+
+static void
 imap_set_server_level (CamelImapStore *store)
 {
 	if (store->capabilities & IMAP_CAPABILITY_IMAP4REV1) {
@@ -1482,11 +1670,11 @@
 	if (!camel_disco_store_check_online (CAMEL_DISCO_STORE (store), ex))
 		return NULL;
 
-	CAMEL_SERVICE_REC_LOCK (store, connect_lock);
+	camel_imap_store_stop_idle_connect_lock (store);
 	connected = store->istream != NULL && store->connected;
 	if (!connected)
 		connected = connect_to_server_wrapper (service, ex);
-	CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+	camel_imap_store_connect_unlock_start_idle (store);
 
 	if (!connected)
 		return NULL;
@@ -1995,12 +2183,12 @@
 
 	let_idle_die (store, TRUE);
 
-	CAMEL_SERVICE_REC_LOCK (store, connect_lock);
+	camel_imap_store_stop_idle_connect_lock (store);
 
 	if (!connect_to_server_wrapper (service, ex) || !imap_auth_loop (service, ex, &auth))
 	{
 		/* CAMEL_DISCO_STORE (store)->status = CAMEL_DISCO_STORE_OFFLINE; */
-		CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+		camel_imap_store_connect_unlock_no_start_idle (store);
 		/* camel_service_disconnect (service, TRUE, NULL); */
 		store->going_online = FALSE;
 		store->not_recon = FALSE;
@@ -2140,7 +2328,7 @@
 
 	g_static_rec_mutex_unlock (store->sum_lock);
 
-	CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+	camel_imap_store_connect_unlock_no_start_idle (store);
 
 	if (camel_exception_is_set (ex))
 		camel_service_disconnect (service, TRUE, NULL);
@@ -2164,7 +2352,9 @@
 	imap_debug ("imap_connect_offline\n");
 
 	let_idle_die (store, TRUE);
+	CAMEL_SERVICE_REC_LOCK (service, connect_lock);
 	camel_imap_store_stop_idle (store);
+	CAMEL_SERVICE_REC_UNLOCK (service, connect_lock);
 
 	if (!disco_store->diary)
 		return FALSE;
@@ -2182,7 +2372,9 @@
 	imap_debug ("imap_disconnect_offline\n");
 
 	let_idle_die (store, TRUE);
+	CAMEL_SERVICE_REC_LOCK (service, connect_lock);
 	camel_imap_store_stop_idle (store);
+	CAMEL_SERVICE_REC_UNLOCK (service, connect_lock);
 
 	if (store->istream) {
 		camel_stream_close(store->istream);
@@ -2232,6 +2424,8 @@
 	if (clean)
 		let_idle_die (store, TRUE);
 
+	camel_imap_store_stop_idle_connect_lock (store);
+
 	if (store->connected && clean) {
 		response = camel_imap_command (store, NULL, NULL, "LOGOUT");
 		camel_imap_response_free (store, response);
@@ -2239,6 +2433,7 @@
 
 	imap_disconnect_offline (service, clean, ex);
 
+	camel_imap_store_connect_unlock_no_start_idle (store);
 	return TRUE;
 }
 
@@ -2269,7 +2464,7 @@
 	CamelImapResponse *response;
 	CamelFolder *current_folder;
 
-	CAMEL_SERVICE_REC_LOCK (imap_store, connect_lock);
+	camel_imap_store_stop_idle_connect_lock (imap_store);
 
 	if (!camel_disco_store_check_online((CamelDiscoStore *)store, ex))
 		goto done;
@@ -2284,7 +2479,7 @@
 			camel_imap_response_free (imap_store, response);
 	}
 done:
-	CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
+	camel_imap_store_connect_unlock_start_idle (imap_store);
 }
 
 static CamelFolder *
@@ -2651,7 +2846,7 @@
 	if (!camel_disco_store_check_online (CAMEL_DISCO_STORE (imap_store), &ex))
 		return;
 
-	CAMEL_SERVICE_REC_LOCK (imap_store, connect_lock);
+	camel_imap_store_stop_idle_connect_lock (imap_store);
 
 	/*
 	 *  Example: C: A042 STATUS blurdybloop (UIDNEXT MESSAGES)
@@ -2680,8 +2875,7 @@
 	}
 	imap_status_item_free (items);
 
-	CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
-	camel_imap_store_start_idle (imap_store);
+	camel_imap_store_connect_unlock_start_idle (imap_store);
 
 	return;
 }
@@ -2701,10 +2895,10 @@
 		return new_folder;
 	camel_exception_clear(ex);
 
-	CAMEL_SERVICE_REC_LOCK(imap_store, connect_lock);
+	camel_imap_store_stop_idle_connect_lock (imap_store);
 
 	if (!camel_disco_store_check_online((CamelDiscoStore *)imap_store, ex)) {
-		CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
+		camel_imap_store_connect_unlock_start_idle (imap_store);
 		return NULL;
 	}
 
@@ -2724,16 +2918,14 @@
 		const char *c;
 
 		if (camel_exception_get_id(ex) == CAMEL_EXCEPTION_USER_CANCEL) {
-			CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
-			camel_imap_store_start_idle (imap_store);
+			camel_imap_store_connect_unlock_start_idle (imap_store);
 			return NULL;
 		}
 
 		camel_exception_clear (ex);
 
 		if (!(flags & CAMEL_STORE_FOLDER_CREATE)) {
-			CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
-			camel_imap_store_start_idle (imap_store);
+			camel_imap_store_connect_unlock_start_idle (imap_store);
 			camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER,
 					      _("No such folder %s"), folder_name);
 			return NULL;
@@ -2745,11 +2937,10 @@
 			c++;
 
 		if (*c != '\0') {
-			CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
 			camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_CREATE,
 					      _("The folder name \"%s\" is invalid because it contains the character \"%c\""),
 					      folder_name, *c);
-			camel_imap_store_start_idle (imap_store);
+			camel_imap_store_connect_unlock_start_idle (imap_store);
 			return NULL;
 		}
 
@@ -2770,8 +2961,7 @@
 				g_free (parent_name);
 				g_free (parent_real);
 
-				CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
-				camel_imap_store_start_idle (imap_store);
+				camel_imap_store_connect_unlock_start_idle (imap_store);
 
 				return NULL;
 			}
@@ -2817,8 +3007,7 @@
 							     _("The parent folder is not allowed to contain subfolders"));
 					g_free (parent_name);
 					g_free (parent_real);
-					CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
-					camel_imap_store_start_idle (imap_store);
+					camel_imap_store_connect_unlock_start_idle (imap_store);
 					return NULL;
 				}
 
@@ -2828,8 +3017,7 @@
 				if (camel_exception_is_set (&lex)) {
 					g_free (parent_name);
 					g_free (parent_real);
-					CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
-					camel_imap_store_start_idle (imap_store);
+					camel_imap_store_connect_unlock_start_idle (imap_store);
 					camel_exception_xfer (ex, &lex);
 					return NULL;
 				}
@@ -2843,8 +3031,7 @@
 				if (!response) {
 					g_free (parent_name);
 					g_free (parent_real);
-					CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
-					camel_imap_store_start_idle (imap_store);
+					camel_imap_store_connect_unlock_start_idle (imap_store);
 					return NULL;
 				} else
 					camel_imap_response_free (imap_store, response);
@@ -2866,8 +3053,7 @@
 		}
 		g_free(folder_real);
 		if (!response) {
-			CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
-			camel_imap_store_start_idle (imap_store);
+			camel_imap_store_connect_unlock_start_idle (imap_store);
 
 			return NULL;
 		}
@@ -2877,8 +3063,7 @@
 				      folder_name);
 
 		camel_imap_response_free_without_processing (imap_store, response);
-		CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
-		camel_imap_store_start_idle (imap_store);
+		camel_imap_store_connect_unlock_start_idle (imap_store);
 
 		return NULL;
 	}
@@ -2910,8 +3095,7 @@
 	}
 	camel_imap_response_free_without_processing (imap_store, response);
 
-	CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
-	camel_imap_store_start_idle (imap_store);
+	camel_imap_store_connect_unlock_start_idle (imap_store);
 
 	return new_folder;
 }
@@ -2953,14 +3137,13 @@
 	CamelImapResponse *response;
 	CamelFolder *old_in_case;
 
-	CAMEL_SERVICE_REC_LOCK (imap_store, connect_lock);
+	camel_imap_store_stop_idle_connect_lock (imap_store);
 
 	old_in_case = imap_store->current_folder;
 
 	if (!camel_disco_store_check_online((CamelDiscoStore *)imap_store, ex))
 		goto fail;
 
-	camel_imap_store_stop_idle (imap_store);
 	/* make sure this folder isn't currently SELECTed */
 	response = camel_imap_command (imap_store, NULL, ex, "SELECT INBOX");
 	if (!response)
@@ -2991,10 +3174,8 @@
 		imap_forget_folder (imap_store, folder_name, ex);
 	}
 fail:
-	CAMEL_SERVICE_REC_UNLOCK(imap_store, connect_lock);
+	camel_imap_store_connect_unlock_start_idle (imap_store);
 
-	camel_imap_store_start_idle (imap_store);
-
 }
 
 static void
@@ -3171,7 +3352,7 @@
 	char *tpath, *lslash;
 	CamelFolder *old_in_case = NULL;
 
-	CAMEL_SERVICE_REC_LOCK (imap_store, connect_lock);
+	camel_imap_store_stop_idle_connect_lock (imap_store);
 
 	old_in_case = imap_store->current_folder;
 
@@ -3263,10 +3444,9 @@
 	g_free (newpath);
 fail:
 	imap_store->renaming = FALSE;
-	CAMEL_SERVICE_REC_UNLOCK(imap_store, connect_lock);
 	camel_operation_end (NULL);
 
-	camel_imap_store_start_idle (imap_store);
+	camel_imap_store_connect_unlock_start_idle (imap_store);
 
 }
 
@@ -3315,7 +3495,6 @@
 				       parent_real);
 	if (!response) /* whoa, this is bad */ {
 		g_free(parent_real);
-		camel_imap_store_start_idle (imap_store);
 		return NULL;
 	}
 
@@ -3360,7 +3539,6 @@
 			camel_exception_set (ex, CAMEL_EXCEPTION_FOLDER_INVALID_STATE,
 					     _("The parent folder is not allowed to contain subfolders"));
 			g_free(parent_real);
-			camel_imap_store_start_idle (imap_store);
 			return NULL;
 		}
 
@@ -3368,7 +3546,6 @@
 		delete_folder (store, parent_name, &internal_ex);
 		if (camel_exception_is_set (&internal_ex)) {
 			camel_exception_xfer (ex, &internal_ex);
-			camel_imap_store_start_idle (imap_store);
 			return NULL;
 		}
 
@@ -3380,7 +3557,6 @@
 
 		if (!response) {
 			g_free(parent_real);
-			camel_imap_store_start_idle (imap_store);
 			return NULL;
 		} else
 			camel_imap_response_free (imap_store, response);
@@ -3393,7 +3569,6 @@
 	full_name = imap_concat (imap_store, parent_real, real_name);
 	g_free(real_name);
 
-	camel_imap_store_stop_idle (imap_store);
 	response = camel_imap_command (imap_store, NULL, ex, "CREATE %G", full_name);
 
 	if (response) {
@@ -3423,8 +3598,6 @@
 	g_free (full_name);
 	g_free(parent_real);
 
-	camel_imap_store_start_idle (imap_store);
-
 	return root;
 }
 
@@ -3563,8 +3736,6 @@
 
 	for (j = 0; j < loops; j++) {
 
-		camel_imap_store_stop_idle (imap_store);
-
 		if (imap_store->capabilities & IMAP_CAPABILITY_LISTEXT)
 			response = camel_imap_command (imap_store, NULL, ex,
 				"%s \"\" %G", "LIST (SUBSCRIBED)",
@@ -3653,7 +3824,6 @@
 	g_hash_table_foreach(present, get_folders_free, NULL);
 	g_hash_table_destroy(present);
 
-	camel_imap_store_start_idle (imap_store);
 }
 
 
@@ -3726,7 +3896,7 @@
 
 	present = g_hash_table_new(folder_hash, folder_eq);
 
-	camel_imap_store_stop_idle (imap_store);
+	camel_imap_store_stop_idle_connect_lock (imap_store);
 
 	if (imap_store->capabilities & IMAP_CAPABILITY_LISTEXT) {
 
@@ -3889,7 +4059,7 @@
 	g_hash_table_foreach(present, get_folders_free, NULL);
 	g_hash_table_destroy(present);
 
-	camel_imap_store_start_idle (imap_store);
+	camel_imap_store_connect_unlock_start_idle (imap_store);
 }
 
 
@@ -3906,8 +4076,6 @@
 	CamelStoreInfo *si;
 	present = g_hash_table_new(folder_hash, folder_eq);
 
-	camel_imap_store_stop_idle (imap_store);
-
 	response = camel_imap_command (imap_store, NULL, ex,
 		"LSUB \"%s\" %G", namespace->prefix, 
 		(strlen (namespace->prefix) > 0)?"*":"%");
@@ -3957,7 +4125,6 @@
 	g_hash_table_foreach(present, get_folders_free, NULL);
 	g_hash_table_destroy(present);
 
-	camel_imap_store_start_idle (imap_store);
 }
 
 static void
@@ -4000,14 +4167,14 @@
 	if (top == NULL)
 		top = "";
 
+	camel_imap_store_stop_idle_connect_lock (imap_store);
+
 	if (imap_store->going_online || !imap_store->got_online)
 		goto fail;
 
 	if (camel_debug("imap:folder_info"))
 		printf("get folder info online\n");
 
-	CAMEL_SERVICE_REC_LOCK(store, connect_lock);
-
 	if (!camel_disco_store_check_online((CamelDiscoStore *)imap_store, ex))
 		goto fail;
 
@@ -4106,7 +4273,7 @@
 		camel_store_summary_save((CamelStoreSummary *)imap_store->summary, ex);
 	}
 
-	CAMEL_SERVICE_REC_UNLOCK(store, connect_lock);
+	camel_imap_store_connect_unlock_start_idle (imap_store);
 
 	tree = get_folder_info_offline(store, top, flags, ex);
 
@@ -4114,7 +4281,7 @@
 	return tree;
 
 fail:
-	CAMEL_SERVICE_REC_UNLOCK(store, connect_lock);
+	camel_imap_store_connect_unlock_start_idle (imap_store);
 
 	tree = get_folder_info_offline (store, top, flags, ex);
 
@@ -4262,12 +4429,11 @@
 	CamelFolderInfo *fi;
 	CamelStoreInfo *si;
 
-	CAMEL_SERVICE_REC_LOCK(store, connect_lock);
+	camel_imap_store_stop_idle_connect_lock (imap_store);
 
 	if (!camel_disco_store_check_online((CamelDiscoStore *)imap_store, ex))
 		goto done;
 
-	camel_imap_store_stop_idle (imap_store);
 	response = camel_imap_command (imap_store, NULL, ex,
 				       "SUBSCRIBE %F", folder_name);
 	if (!response)
@@ -4301,8 +4467,7 @@
 	camel_object_trigger_event (CAMEL_OBJECT (store), "folder_subscribed", fi);
 	camel_folder_info_free (fi);
 done:
-	camel_imap_store_start_idle (imap_store);
-	CAMEL_SERVICE_REC_UNLOCK(store, connect_lock);
+	camel_imap_store_connect_unlock_start_idle (imap_store);
 }
 
 static void
@@ -4312,12 +4477,11 @@
 	CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
 	CamelImapResponse *response;
 
-	CAMEL_SERVICE_REC_LOCK(store, connect_lock);
+	camel_imap_store_stop_idle_connect_lock (imap_store);
 
 	if (!camel_disco_store_check_online((CamelDiscoStore *)imap_store, ex))
 		goto done;
 
-	camel_imap_store_stop_idle (imap_store);
 	response = camel_imap_command (imap_store, NULL, ex,
 				       "UNSUBSCRIBE %F", folder_name);
 	if (!response)
@@ -4326,10 +4490,8 @@
 
 	imap_folder_effectively_unsubscribed (imap_store, folder_name, ex);
 done:
-	CAMEL_SERVICE_REC_UNLOCK(store, connect_lock);
+	camel_imap_store_connect_unlock_start_idle (imap_store);
 
-	camel_imap_store_start_idle (imap_store);
-
 }
 
 #if 0
@@ -4591,3 +4753,4 @@
 
 	store->last_folder = NULL;
 }
+
Index: libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-store.h
===================================================================
--- libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-store.h	(revisión: 3792)
+++ libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-store.h	(copia de trabajo)
@@ -170,12 +170,18 @@
 
 	GStaticRecMutex *idle_prefix_lock, *idle_lock, *sum_lock, *idle_t_lock;
 	GThread *idle_thread;
-	gboolean idle_cont, in_idle, idle_kill;
+	gboolean idle_cont, in_idle, idle_kill, idle_send_done_happened;
 	guint idle_sleep, getsrv_sleep;
 	gboolean courier_crap, idle_sleep_set;
 	gboolean going_online, got_online, clean_exit;
 	gboolean not_recon, needs_lsub;
 
+	GStaticRecMutex *idle_wait_reasons_lock;
+	guint idle_wait_reasons;
+	gboolean already_in_stop_idle;
+
+	gboolean idle_blocked;
+
 	struct addrinfo *addrinfo;
 };
 
@@ -185,6 +191,7 @@
 } CamelImapStoreClass;
 
 
+
 /* Standard Camel function */
 CamelType camel_imap_store_get_type (void);
 
@@ -197,10 +204,21 @@
 
 gboolean camel_imap_store_restore_stream_buffer (CamelImapStore *store);
 
-void camel_imap_store_stop_idle (CamelImapStore *store);
-void camel_imap_store_start_idle (CamelImapStore *store);
+void _camel_imap_store_stop_idle (CamelImapStore *store);
+void _camel_imap_store_stop_idle_connect_lock (CamelImapStore *store);
+void _camel_imap_store_start_idle (CamelImapStore *store);
+void _camel_imap_store_connect_unlock_start_idle (CamelImapStore *store);
+void _camel_imap_store_start_idle_if_unlocked (CamelImapStore *store);
+void _camel_imap_store_connect_unlock_no_start_idle (CamelImapStore *store);
 void camel_imap_recon (CamelImapStore *store, CamelException *mex, gboolean was_cancel);
 
+#define camel_imap_store_stop_idle_connect_lock(store) {idle_debug ("Thread %d StopIdle-ConnectLock(%x) %s:%d\n", (gint) g_thread_self (), (gint) store, __FUNCTION__, (gint) __LINE__);  _camel_imap_store_stop_idle_connect_lock((store));}
+#define camel_imap_store_connect_unlock_start_idle(store) {idle_debug ("Thread %d ConnectUnlock-StartIdle(%x) %s:%d\n", (gint) g_thread_self (), (gint) store, __FUNCTION__, (gint) __LINE__);  _camel_imap_store_connect_unlock_start_idle((store));}
+#define camel_imap_store_start_idle_if_unlocked(store) {idle_debug ("Thread %d StartIdle-IfUnlocked(%x) %s:%d\n", (gint) g_thread_self (), (gint) store, __FUNCTION__, (gint) __LINE__);  _camel_imap_store_start_idle_if_unlocked((store));}
+#define camel_imap_store_connect_unlock_no_start_idle(store) {idle_debug ("Thread %d ConnectUnlock-NO-StartIdle(%x) %s:%d\n", (gint) g_thread_self (), (gint) store, __FUNCTION__, (gint) __LINE__);  _camel_imap_store_connect_unlock_no_start_idle((store));}
+#define camel_imap_store_stop_idle(store) {idle_debug ("Thread %d StopIdle(%x) %s:%d\n", (gint) g_thread_self (), (gint) store, __FUNCTION__, (gint) __LINE__);  _camel_imap_store_stop_idle((store));}
+#define camel_imap_store_start_idle(store) {idle_debug ("Thread %d StartIdle(%x) %s:%d\n", (gint) g_thread_self (), (gint) store, __FUNCTION__, (gint) __LINE__);  _camel_imap_store_start_idle((store));}
+
 G_END_DECLS
 
 #endif /* CAMEL_IMAP_STORE_H */
Index: libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-search.c
===================================================================
--- libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-search.c	(revisión: 3792)
+++ libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-search.c	(copia de trabajo)
@@ -349,7 +349,6 @@
 	/* We only try search using utf8 if its non us-ascii text? */
 	if ((words->type & CAMEL_SEARCH_WORD_8BIT) &&  (store->capabilities & IMAP_CAPABILITY_utf8_search)) {
 
-		camel_imap_store_stop_idle ((CamelImapStore *) store);
 		response = camel_imap_command (store, folder, NULL,
 					       "UID SEARCH CHARSET UTF-8 %s", search->str);
 		/* We can't actually tell if we got a NO response, so assume always */
@@ -357,7 +356,6 @@
 			store->capabilities &= ~IMAP_CAPABILITY_utf8_search;
 	}
 	if (response == NULL) {
-		camel_imap_store_stop_idle ((CamelImapStore *) store);
 		response = camel_imap_command (store, folder, NULL,
 					       "UID SEARCH %s", search->str);
 	}
Index: libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-folder.c
===================================================================
--- libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-folder.c	(revisión: 3792)
+++ libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-folder.c	(copia de trabajo)
@@ -935,7 +935,7 @@
 	 * us with a NOOP of new messages, so force a reselect which
 	 * should do it.  */
 	CAMEL_FOLDER_REC_LOCK(folder, lock);
-	CAMEL_SERVICE_REC_LOCK (imap_store, connect_lock);
+	camel_imap_store_stop_idle_connect_lock (imap_store);
 
 	if (!camel_disco_store_check_online ((CamelDiscoStore*)imap_store, ex))
 		goto done;
@@ -980,13 +980,11 @@
 		camel_store_summary_info_free((CamelStoreSummary *)((CamelImapStore *)folder->parent_store)->summary, si);
 	}
 done:
-	CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
-	CAMEL_FOLDER_REC_UNLOCK(folder, lock);
-
 	camel_folder_summary_save(folder->summary, ex);
 	camel_store_summary_save((CamelStoreSummary *)((CamelImapStore *)folder->parent_store)->summary, ex);
 
-	camel_imap_folder_start_idle (folder);
+	camel_imap_store_connect_unlock_start_idle (imap_store);
+	CAMEL_FOLDER_REC_UNLOCK(folder, lock);
 
 }
 
@@ -1520,7 +1518,7 @@
 	}
 
 	camel_exception_init (&local_ex);
-	CAMEL_SERVICE_REC_LOCK (store, connect_lock);
+	camel_imap_store_stop_idle_connect_lock (store);
 
 	/* Find a message with changed flags, find all of the other
 	 * messages like it, sync them as a group, mark them as
@@ -1586,25 +1584,21 @@
 		}
 		g_ptr_array_free (matches, TRUE);
 
-		/* We unlock here so that other threads can have a chance to grab the connect_lock */
-		CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
-
 		/* check for an exception */
 		if (camel_exception_is_set (&local_ex)) {
 
+			camel_imap_store_connect_unlock_start_idle (store);
+
 			camel_exception_xfer (ex, &local_ex);
-			camel_imap_folder_start_idle (folder);
 			return;
 		}
 
-		/* Re-lock the connect_lock */
-		CAMEL_SERVICE_REC_LOCK (store, connect_lock);
 	}
 
 	/* Save the summary */
 	imap_sync_offline (folder, ex);
 
-	CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+	camel_imap_store_connect_unlock_start_idle (store);
 	camel_imap_folder_start_idle (folder);
 
 }
@@ -1658,12 +1652,12 @@
 	int uid = 0;
 	char *set;
 
-	CAMEL_SERVICE_REC_LOCK (store, connect_lock);
+	camel_imap_store_stop_idle_connect_lock (store);
 
 	if ((store->capabilities & IMAP_CAPABILITY_UIDPLUS) == 0) {
 		((CamelFolderClass *)CAMEL_OBJECT_GET_CLASS(folder))->sync(folder, 0, ex);
 		if (camel_exception_is_set(ex)) {
-			CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+			camel_imap_store_connect_unlock_start_idle (store);
 			return;
 		}
 	}
@@ -1678,7 +1672,7 @@
 		if (response)
 			camel_imap_response_free (store, response);
 		if (camel_exception_is_set (ex)) {
-			CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+			camel_imap_store_connect_unlock_start_idle (store);
 			g_free (set);
 			return;
 		}
@@ -1705,10 +1699,7 @@
 		g_free (set);
 	}
 
-	CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
-
-	camel_imap_folder_start_idle (folder);
-
+	camel_imap_store_connect_unlock_start_idle (store);
 }
 
 static void
@@ -1733,11 +1724,11 @@
 	 * and any that aren't in our to-expunge list get temporarily
 	 * marked un-deleted. */
 
-	CAMEL_SERVICE_REC_LOCK (store, connect_lock);
+	camel_imap_store_stop_idle_connect_lock (store);
 
 	((CamelFolderClass *)CAMEL_OBJECT_GET_CLASS(folder))->sync(folder, 0, ex);
 	if (camel_exception_is_set(ex)) {
-		CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+		camel_imap_store_connect_unlock_start_idle (store);
 		return;
 	}
 
@@ -1748,7 +1739,7 @@
 	}
 	result = camel_imap_response_extract (store, response, "SEARCH", ex);
 	if (!result) {
-		CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+		camel_imap_store_connect_unlock_start_idle (store);
 		return;
 	}
 
@@ -1808,7 +1799,7 @@
 			if (!response) {
 				g_ptr_array_free (keep_uids, TRUE);
 				g_ptr_array_free (mark_uids, TRUE);
-				CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+				camel_imap_store_connect_unlock_start_idle (store);
 				return;
 			}
 			camel_imap_response_free (store, response);
@@ -1833,6 +1824,7 @@
 			if (!response) {
 				g_ptr_array_free (keep_uids, TRUE);
 				g_ptr_array_free (mark_uids, TRUE);
+				camel_imap_store_connect_unlock_start_idle (store);
 				CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
 				return;
 			}
@@ -1872,10 +1864,8 @@
 	/* now we can free this, now that we're done with keep_uids */
 	g_free (result);
 
-	CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+	camel_imap_store_connect_unlock_start_idle (store);
 
-	camel_imap_folder_start_idle (folder);
-
 }
 
 static gchar *
@@ -2065,14 +2055,12 @@
 	camel_imap_response_free (store, response);
 
 	/* Make sure a "folder_changed" is emitted. */
-	CAMEL_SERVICE_REC_LOCK (store, connect_lock);
+	camel_imap_store_stop_idle_connect_lock (store);
 	if (store->current_folder != folder ||
 	    camel_folder_summary_count (folder->summary) == count)
 		imap_refresh_info (folder, ex);
-	CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+	camel_imap_store_connect_unlock_start_idle (store);
 
-	camel_imap_folder_start_idle (folder);
-
 }
 
 static void
@@ -2127,10 +2115,10 @@
 	 * deadlock in the case where we're simultaneously also trying
 	 * to copy messages in the other direction from another thread.
 	 */
-	CAMEL_SERVICE_REC_LOCK (store, connect_lock);
+	camel_imap_store_stop_idle_connect_lock (store);
 	CAMEL_IMAP_FOLDER_REC_LOCK (source, cache_lock);
 	CAMEL_IMAP_FOLDER_REC_LOCK (dest, cache_lock);
-	CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+	camel_imap_store_connect_unlock_start_idle (store);
 
 	if (transferred_uids) {
 		*transferred_uids = g_ptr_array_new ();
@@ -2834,16 +2822,16 @@
 				char *body, *found_uid;
 				int i;
 
-				CAMEL_SERVICE_REC_LOCK(store, connect_lock);
+				camel_imap_store_stop_idle_connect_lock (store);
 				if (!camel_disco_store_check_online ((CamelDiscoStore*)store, ex)) {
-					CAMEL_SERVICE_REC_UNLOCK(store, connect_lock);
+					camel_imap_store_connect_unlock_start_idle (store);
 					camel_exception_set (ex, CAMEL_EXCEPTION_FOLDER_UID_NOT_AVAILABLE,
 							     _("This message is not currently available"));
 					goto fail;
 				}
 
 				response = camel_imap_command (store, folder, ex, "UID FETCH %s BODY", uid);
-				CAMEL_SERVICE_REC_UNLOCK(store, connect_lock);
+				camel_imap_store_connect_unlock_start_idle (store);
 
 				if (response) {
 					for (i = 0, body = NULL; i < response->untagged->len; i++) {
@@ -3358,7 +3346,6 @@
 
 	if ((cnt < nextn) && more)
 	{
-		int i;
 
 		g_ptr_array_foreach (needheaders, (GFunc)g_free, NULL);
 		g_ptr_array_free (needheaders, TRUE);
@@ -3441,7 +3428,6 @@
 		/* If we still received too few */
 		if (tcnt < (exists - seq))
 		{
-			int i;
 
 			g_ptr_array_foreach (needheaders, (GFunc)g_free, NULL);
 			g_ptr_array_free (needheaders, TRUE);
@@ -3950,6 +3936,109 @@
 	return;
 }
 
+static void
+process_idle_body (CamelImapStore *store, CamelFolder *folder, IdleResponse **idle_response, CamelException *exception)
+{
+	char *resp = NULL;
+
+	while (camel_imap_store_readline_nb (store, &resp, exception) > 0) {
+		if (resp && strlen (resp) > 1 && resp[0] == '*') {
+			if (!*idle_response)
+				*idle_response = idle_response_new (folder);
+			consume_idle_line (store, folder, resp, *idle_response);
+		}
+		
+		if (resp)
+			g_free (resp);
+		resp = NULL;
+	}
+}
+
+static void
+process_idle_untagged_response (CamelImapStore *store, CamelFolder *folder, IdleResponse **idle_response, CamelException *exception)
+{
+	char *resp = NULL;
+	CamelImapResponseType type;
+
+	while ((type = camel_imap_command_response_idle (store, &resp, exception)) == CAMEL_IMAP_RESPONSE_UNTAGGED) {
+		if (resp && strlen (resp) > 1 && resp[0] == '*') {
+			if (!*idle_response)
+				*idle_response = idle_response_new (folder);
+			consume_idle_line (store, folder, resp, *idle_response);
+		}
+		
+		if (resp)
+			g_free (resp);
+		resp = NULL;
+	}
+}
+
+static void
+do_send_done (CamelImapStore *store, CamelFolder *folder, IdleResponse **idle_resp, CamelException *ex)
+{
+	if (store->idle_prefix) {
+		gboolean l = g_static_rec_mutex_trylock (store->idle_lock);
+
+		if (!store->idle_kill) {
+			int nwritten=0;
+			/* We read-away everything that we still
+			 * have. To find where idle_resp is handled,
+			 * read below at the g_thread_join for
+			 * this thread (we are returning it). */
+
+			process_idle_body (store, folder, idle_resp, ex);
+
+			/* We send the DONE to the server */
+			
+			nwritten = camel_stream_printf (store->ostream, "DONE\r\n");
+			idle_debug ("(%d, 8) -> DONE\n", nwritten);
+
+			/* We read away everything the server sends
+			 * until the we see the untagged OK response */
+
+			process_idle_untagged_response (store, folder, idle_resp, ex);
+		}
+
+		if (l)
+			g_static_rec_mutex_unlock (store->idle_lock);
+
+		/* If we are continuing the loop, handle idle_resp
+		 * now (this can invoke fetching new headers). */
+
+		if (store->idle_cont && *idle_resp) {
+			process_idle_response (*idle_resp);
+			idle_response_free (*idle_resp);
+			*idle_resp = NULL;
+		}
+
+	}
+	store->idle_send_done_happened = TRUE;
+}
+
+static gpointer
+send_done_in_stop_idle (CamelImapStore *store, CamelFolder *folder)
+{
+	CamelException ex = CAMEL_EXCEPTION_INITIALISER;
+	IdleResponse *idle_resp = NULL;
+
+	/* This method is used for sending the commands we expect idle thread to do to finish
+	 * idle loop, when the caller thread has the connect lock (and then the idle thread cannot
+	 * do safely these commands */
+
+	if (g_static_rec_mutex_trylock (store->idle_lock)) {
+			/* Step B) (see idle_thread) */
+
+			if (!store->idle_kill) {
+				process_idle_body (store, folder, &idle_resp, &ex);
+			}
+			g_static_rec_mutex_unlock (store->idle_lock);
+	}
+
+	/* Step C) (see idle_thread). We're assuming idle_cont == FALSE, send_done == TRUE*/
+	do_send_done (store, folder, &idle_resp, &ex);
+	return idle_resp;
+}
+
 typedef struct {
 	CamelFolder *folder;
 	GCond *condition;
@@ -3966,7 +4055,6 @@
 	CamelImapStore *store;
 	gboolean tfirst = TRUE, first = TRUE, my_cont, had_cond = FALSE;
 	int cnt = 0;
-	int nwritten=0;
 	gpointer retval = NULL;
 
 	idle_debug ("idle_thread starts\n");
@@ -4029,198 +4117,112 @@
 		idle_debug ("idle_thread starting but immediately stopping\n");
 	}
 
+	store->idle_send_done_happened = FALSE;
 	/* While nothing has stopped us yet ...
 	 * TNY TODO: it would be nicer to use select() here, rather than usleep() */
-
-	while (my_cont && !store->idle_kill)
+	
+	while (my_cont && !store->idle_kill && 
+	       (store->idle_cont || !store->idle_send_done_happened))
 	{
 		CamelException ex = CAMEL_EXCEPTION_INITIALISER;
-		char *resp = NULL;
 		IdleResponse *idle_resp = NULL;
 		gboolean senddone = FALSE;
+		
+		if (CAMEL_SERVICE_REC_TRYLOCK (store, connect_lock)) {
+			/* A) The first time we will start the IDLE by sending IDLE to
+			 * the server and reading away the + continuation (check out the
+			 * idle_real_start function). We don't call this in the other
+			 * loop cycles of this while. */
 
-		/* A) The first time we will start the IDLE by sending IDLE to
-		 * the server and reading away the + continuation (check out the
-		 * idle_real_start function). We don't call this in the other
-		 * loop cycles of this while. */
+			if (store->idle_cont && first) {
+				gboolean l = g_static_rec_mutex_trylock (store->idle_lock);
+				if (!store->idle_kill)
+					idle_real_start (store);
+				if (l)
+					g_static_rec_mutex_unlock (store->idle_lock);
+				first = FALSE;
+			}
 
-		if (store->idle_cont && first) {
-			gboolean l = g_static_rec_mutex_trylock (store->idle_lock);
-			if (!store->idle_kill)
-				idle_real_start (store);
-			if (l)
-				g_static_rec_mutex_unlock (store->idle_lock);
-			first = FALSE;
-		}
-
-		/* And we also send the broadcast to the caller of this thread:
-		 * We're started, and we're fine. It can continue. We don't call
-		 * this in the other loop cycles of this while. */
-
-		if (tfirst) {
-			if (info->condition) {
-				g_mutex_lock (info->mutex);
-				g_cond_broadcast (info->condition);
-				info->had_cond = TRUE; had_cond = TRUE;
-				g_mutex_unlock (info->mutex);
+			/* And we also send the broadcast to the caller of this thread:
+			 * We're started, and we're fine. It can continue. We don't call
+			 * this in the other loop cycles of this while. */
+			
+			if (tfirst) {
+				if (info->condition) {
+					g_mutex_lock (info->mutex);
+					g_cond_broadcast (info->condition);
+					info->had_cond = TRUE; had_cond = TRUE;
+					g_mutex_unlock (info->mutex);
+				}
+				tfirst = FALSE;
 			}
-			tfirst = FALSE;
-		}
 
-		if (g_static_rec_mutex_trylock (store->idle_lock))
-		{
-			/* B) This happens during the IDLE's body (after IDLE is
-			 * started and before DONE is sent). We read away the
-			 * lines in a non-blocking way. As soon as we have a
-			 * full line, that starts with '*', we consume it. */
-
-			if (!store->idle_kill) {
-				while (camel_imap_store_readline_nb (store, &resp, &ex) > 0)
-				{
-					if (resp && strlen (resp) > 1 && resp[0] == '*') {
-						if (!idle_resp)
-							idle_resp = idle_response_new (folder);
-						consume_idle_line (store, folder, resp, idle_resp);
-					}
-
-					if (resp)
-						g_free (resp);
-					resp = NULL;
+			if (g_static_rec_mutex_trylock (store->idle_lock)) {
+				/* B) This happens during the IDLE's body (after IDLE is
+				 * started and before DONE is sent). We read away the
+				 * lines in a non-blocking way. As soon as we have a
+				 * full line, that starts with '*', we consume it. */
+				
+				if (!store->idle_kill) {
+					process_idle_body (store, folder, &idle_resp, &ex);
 				}
+				g_static_rec_mutex_unlock (store->idle_lock);
 			}
-			g_static_rec_mutex_unlock (store->idle_lock);
-		}
+			
+			if (store->idle_cont) {
+				if (idle_resp && !idle_resp->exists_happened) {
+					/* We can process it already: nothing is at this moment
+					 * joining us, nothing is at this moment locking the
+					 * folder_changed handler of TnyCamelFolder */
+					process_idle_response (idle_resp);
+					idle_response_free (idle_resp);
+					idle_resp = NULL;
+					retval = NULL;
+				} else if (idle_resp && idle_resp->exists_happened) {
 
-		if (resp)
-			g_free (resp);
-
-		if (store->idle_cont)
-		{
-			if (idle_resp && !idle_resp->exists_happened) {
-				/* We can process it already: nothing is at this moment
-				 * joining us, nothing is at this moment locking the
-				 * folder_changed handler of TnyCamelFolder */
-				process_idle_response (idle_resp);
-				idle_response_free (idle_resp);
-				idle_resp = NULL;
-				retval = NULL;
-			} else if (idle_resp && idle_resp->exists_happened) {
-
-				/* We can't deal with new EXISTS responses
-				 * without first stopping IDLE (we'll need to
-				 * fetch the new headers) */
-
+					/* We can't deal with new EXISTS responses
+					 * without first stopping IDLE (we'll need to
+					 * fetch the new headers) */
+					
+					senddone = TRUE;
+					retval = idle_resp;
+				}
+			} else {
+				/* If store->idle_cont was FALSE, we're going to handle
+				 * idle_resp differently (look below). */
 				senddone = TRUE;
 				retval = idle_resp;
 			}
-		} else {
-			/* If store->idle_cont was FALSE, we're going to handle
-			 * idle_resp differently (look below). */
-			senddone = TRUE;
-			retval = idle_resp;
-		}
 
-		/* C) So either we timed out (store->idle_sleep as been reached),
-		 * which means that we 'are' going to restart this entire while,
-		 * including resending the IDLE-start, after we're done with
-		 * this if-block of course.
-		 *
-		 * Or another thread called us to stop IDLE, and then we're
-		 * going to exit this while, of course. If it was an idle_kill,
-		 * we're not even going to try doing that in a nice way. In that
-		 * case we'll just exit ASAP (it's let_idle_die in CamelImapStore
-		 * trying to disconnect from the IMAP server). */
+			/* C) So either we timed out (store->idle_sleep as been reached),
+			 * which means that we 'are' going to restart this entire while,
+			 * including resending the IDLE-start, after we're done with
+			 * this if-block of course.
+			 *
+			 * Or another thread called us to stop IDLE, and then we're
+			 * going to exit this while, of course. If it was an idle_kill,
+			 * we're not even going to try doing that in a nice way. In that
+			 * case we'll just exit ASAP (it's let_idle_die in CamelImapStore
+			 * trying to disconnect from the IMAP server). */
 
-		if ((cnt > store->idle_sleep) || senddone)
-		{
-			if (store->idle_prefix)
-			{
-				CamelImapResponseType type;
-				gboolean l = g_static_rec_mutex_trylock (store->idle_lock);
-
-				if (!store->idle_kill)
-				{
-					/* We read-away everything that we still
-					 * have. To find where idle_resp is handled,
-					 * read below at the g_thread_join for
-					 * this thread (we are returning it). */
-
-					resp = NULL;
-					while (camel_imap_store_readline_nb (store, &resp, &ex) > 0)
-					{
-						if (resp && strlen (resp) > 1 && resp[0] == '*') {
-							if (!idle_resp) {
-								idle_resp = idle_response_new (folder);
-								/* We will free this after the join */
-								if (!store->idle_cont)
-									retval = idle_resp;
-							}
-							consume_idle_line (store, folder, resp, idle_resp);
-						}
-
-						if (resp)
-							g_free (resp);
-						resp = NULL;
-					}
-					if (resp)
-						g_free (resp);
-					resp = NULL;
-
-					/* We send the DONE to the server */
-
-					nwritten = camel_stream_printf (store->ostream, "DONE\r\n");
-					idle_debug ("(%d, 8) -> DONE\n", nwritten);
-
-					/* We read away everything the server sends
-					 * until the we see the untagged OK response */
-
-					while ((type = camel_imap_command_response_idle (store, &resp, &ex)) == CAMEL_IMAP_RESPONSE_UNTAGGED)
-					{
-						if (resp && strlen (resp) > 1 && resp[0] == '*') {
-							if (!idle_resp) {
-								idle_resp = idle_response_new (folder);
-								/* We will free this after the join */
-								if (!store->idle_cont)
-									retval = idle_resp;
-							}
-							consume_idle_line (store, folder, resp, idle_resp);
-						}
-
-						if (resp)
-							g_free (resp);
-						resp = NULL;
-					}
-				}
-
-				if (l)
-					g_static_rec_mutex_unlock (store->idle_lock);
-
-				if (resp)
-					g_free (resp);
-				resp = NULL;
-
-				/* If we are continuing the loop, handle idle_resp
-				 * now (this can invoke fetching new headers). */
-
-				if (store->idle_cont && idle_resp) {
-					process_idle_response (idle_resp);
-					idle_response_free (idle_resp);
-					idle_resp = NULL;
+			if ((cnt > store->idle_sleep) || senddone) {
+				do_send_done (store, folder, &idle_resp, &ex);
+				if (store->idle_cont) {
+					first = TRUE;
 					retval = NULL;
+				} else {
+					retval = idle_resp;
+					my_cont = FALSE;
 				}
-			}
 
-			if (store->idle_cont)
-				first = TRUE;
-			else
-				my_cont = FALSE;
-
 			cnt = 0;
+			}
+			CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
 		}
 
 		/* TNY TODO: try to use the select() of the non-blocking read
 		 * for this usleep() and cnt stuff. */
-
+		
 		if (my_cont)
 			usleep (500000);
 
@@ -4246,7 +4248,46 @@
 	return retval;
 }
 
+static void
+stop_idle (CamelImapStore *store, CamelFolder *folder, gboolean send_done)
+{
+	g_static_rec_mutex_lock (store->idle_t_lock);
+	if (store->in_idle && store->idle_thread && (g_thread_self () != store->idle_thread)) {
+		IdleResponse *idle_resp = NULL;
 
+		store->idle_cont = FALSE;
+		if (send_done && !store->idle_send_done_happened) {
+			idle_resp  = send_done_in_stop_idle (store, folder);
+			g_thread_join (store->idle_thread);
+		} else {
+			idle_resp = g_thread_join (store->idle_thread);
+		}
+				
+		g_static_rec_mutex_lock (store->idle_lock);
+		g_static_rec_mutex_lock (store->idle_prefix_lock);
+				
+		store->in_idle = FALSE;
+		store->idle_thread = NULL;
+		if (store->idle_prefix)
+			g_free (store->idle_prefix);
+		
+		g_static_rec_mutex_unlock (store->idle_prefix_lock);
+		g_static_rec_mutex_unlock (store->idle_lock);
+
+		/* We are doing this here because here we wont hit the
+		 * priv->folder's lock of TnyCamelFolder during its
+		 * folder_changed handler. */
+
+		if (idle_resp) {
+			process_idle_response (idle_resp);
+			idle_response_free (idle_resp);
+		}
+
+	}
+	store->idle_prefix = NULL;
+	g_static_rec_mutex_unlock (store->idle_t_lock);
+}
+
 void
 camel_imap_folder_stop_idle (CamelFolder *folder)
 {
@@ -4264,35 +4305,39 @@
 
 	if ((store->capabilities & IMAP_CAPABILITY_IDLE))
 	{
-		g_static_rec_mutex_lock (store->idle_t_lock);
-		if (store->in_idle && store->idle_thread && (g_thread_self () != store->idle_thread)) {
-			IdleResponse *idle_resp = NULL;
-			store->idle_cont = FALSE;
-			idle_resp = g_thread_join (store->idle_thread);
+		/* We can safely do this, as the access to this from idle thread is always protected
+		 * by a lock (we replace the idle thread once we joined, not before */
+		if (g_thread_self () != store->idle_thread) {
+			stop_idle (store, folder, FALSE);
+		}
 
-			g_static_rec_mutex_lock (store->idle_lock);
-			g_static_rec_mutex_lock (store->idle_prefix_lock);
+	}
 
-			store->in_idle = FALSE;
-			store->idle_thread = NULL;
-			if (store->idle_prefix)
-				g_free (store->idle_prefix);
+	return;
+}
 
-			g_static_rec_mutex_unlock (store->idle_prefix_lock);
-			g_static_rec_mutex_unlock (store->idle_lock);
+void
+camel_imap_folder_stop_idle_in_connect_lock (CamelFolder *folder)
+{
+	CamelImapStore *store;
+	CamelException ex = CAMEL_EXCEPTION_INITIALISER;
 
-			/* We are doing this here because here we wont hit the
-			 * priv->folder's lock of TnyCamelFolder during its
-			 * folder_changed handler. */
+	idle_debug ("camel_imap_folder_stop_idle_in_connect_lock\n");
 
-			if (idle_resp) {
-				process_idle_response (idle_resp);
-				idle_response_free (idle_resp);
-			}
+	store = CAMEL_IMAP_STORE (folder->parent_store);
 
+	store->idle_cont = FALSE;
+
+	if (!camel_disco_store_check_online ((CamelDiscoStore*)store, &ex))
+		return;
+
+	if ((store->capabilities & IMAP_CAPABILITY_IDLE))
+	{
+		/* We can safely do this, as the access to this from idle thread is always protected
+		 * by a lock (we replace the idle thread once we joined, not before */
+		if (g_thread_self () != store->idle_thread) {
+			stop_idle (store, folder, TRUE);
 		}
-		store->idle_prefix = NULL;
-		g_static_rec_mutex_unlock (store->idle_t_lock);
 
 	}
 
@@ -4317,6 +4362,11 @@
 	if (!imap_folder->do_push_email)
 		return;
 
+	if (store->idle_blocked) {
+		idle_debug ("idle is blocked\n");
+		return;
+	}
+
 	g_static_rec_mutex_lock (store->idle_lock);
 
 	if (store->capabilities & IMAP_CAPABILITY_IDLE)
@@ -4329,6 +4379,8 @@
 
 			g_static_rec_mutex_lock (store->idle_t_lock);
 
+			/* We should never enter into a start idle from the idle thread */
+			g_assert ((store->idle_thread == NULL) || (g_thread_self () != store->idle_thread));
 			if (!store->in_idle && store->idle_thread && (g_thread_self () != store->idle_thread)) {
 				IdleResponse *idle_resp = NULL;
 
@@ -4590,8 +4642,10 @@
 		{
 			if (imap_folder->gmsgstore) {
 				imap_debug ("Get-Message service dies\n");
+				/* camel_imap_store_stop_idle_connect_lock (imap_folder->gmsgstore); */
 				camel_service_disconnect (CAMEL_SERVICE (imap_folder->gmsgstore),
 					imap_folder->gmsgstore->clean_exit, NULL);
+				/* camel_imap_store_connect_unlock_start_idle (imap_folder->gmsgstore); */
 				camel_object_unref (CAMEL_OBJECT (imap_folder->gmsgstore));
 				imap_folder->gmsgstore = NULL;
 				camel_object_unref (imap_folder);
@@ -4955,7 +5009,7 @@
 			}
 
 convert_berrorhander:
-			CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+			camel_imap_store_connect_unlock_start_idle (store);
 
 			if (err)
 				goto convert_errorhandler;
@@ -5065,6 +5119,14 @@
 		{
 			retry = FALSE;
 
+			g_free (path);
+
+			if (binary && *binary && store->capabilities & IMAP_CAPABILITY_BINARY)
+			{
+				path = g_strdup_printf ("%s/%s_%s", imap_folder->cache->path, uid, spec);
+			} else {
+				path = g_strdup_printf ("%s/%s_%s_ENCODED", imap_folder->cache->path, uid, spec);
+			}
 			fil = fopen (path, "w");
 
 			if (!fil) {
@@ -5096,9 +5158,6 @@
 				char *pos, *ppos;
 				gboolean unsolicited = TRUE;
 
-				g_free (path);
-				path = g_strdup_printf ("%s/%s_%s", imap_folder->cache->path, uid, spec);
-
 				nread = 0;
 
 				/* Stops idle */
@@ -5147,7 +5206,7 @@
 						unlink (path);
 						g_free (path);
 						path = g_strdup_printf ("%s/%s_%s_ENCODED", imap_folder->cache->path, uid, spec);
-						CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+						camel_imap_store_connect_unlock_start_idle (store);
 						goto fetch_retry;
 					}
 
@@ -5228,7 +5287,7 @@
 					*binary = TRUE;
 
 fetch_berrorhander:
-				CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+				camel_imap_store_connect_unlock_start_idle (store);
 
 				if (err)
 					goto fetch_errorhandler;
@@ -5245,8 +5304,6 @@
 
 				nread = 0;
 
-				g_free (path);
-				path = g_strdup_printf ("%s/%s_%s_ENCODED", imap_folder->cache->path, uid, spec);
 
 				/*
 				a01 UID FETCH 1:10 BODY.PEEK[0]
@@ -5357,7 +5414,7 @@
 				  }
 				}
 
-				CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+				camel_imap_store_connect_unlock_start_idle (store);
 
 				if (nread <= 0) {
 					err = TRUE;
@@ -5599,18 +5656,21 @@
 		return NULL;
 	}
 
+	g_message ("%s: BEGIN NOOP IMAP COMMAND", __FUNCTION__);
 
 	noop_response = camel_imap_command (store, (CamelFolder *) imap_folder, ex, "NOOP");
 	if (noop_response)
 		camel_imap_response_free (store, noop_response);
 	else {
 		stop_gmsgstore (imap_folder, ctchecker, FALSE);
+		g_message ("%s: NO NOOP RESPONSE -> EXIT", __FUNCTION__);
 		return NULL;
 	}
+	g_message ("%s: END NOOP IMAP COMMAND", __FUNCTION__);
 
 	camel_operation_start (NULL, _("Retrieving message"));
 
-  CAMEL_SERVICE_REC_LOCK(store, connect_lock);
+	camel_imap_store_stop_idle_connect_lock (store);
 
 	CAMEL_IMAP_FOLDER_REC_LOCK (imap_folder, cache_lock);
 
@@ -5624,6 +5684,7 @@
 	if (stream == NULL) {
 		ex_id = CAMEL_EXCEPTION_SYSTEM_IO_WRITE;
 		errmessage = g_strdup_printf (_("Write to cache failed: %s"), g_strerror (errno));
+		g_message ("%s: AFTER STREAM CACHE MESSAGE INSERT", __FUNCTION__);
 		goto errorhander;
 	}
 
@@ -5635,6 +5696,8 @@
 	 * code. Right now, all who use this function should check for the 
 	 * instance being valid cause of this reason. */
 
+	g_message ("%s: BEGIN WHILE RETRY", __FUNCTION__);
+	
 	while (retry)
 	{
 	retry = FALSE;
@@ -5656,6 +5719,8 @@
 			char *pos, *ppos;
 			gboolean unsolicited = TRUE;
 
+			g_message ("%s: IMAP COMMAND START UID FETCH BINARY PEEK", __FUNCTION__);
+	
 			/* Stops idle */
 			camel_imap_command_start (store, folder, ex,
 				"UID FETCH %s BINARY.PEEK[%s]", uid, section_text);
@@ -5698,7 +5763,8 @@
 						" we use BINARY (%s)\n", line);
 					store->capabilities &= ~IMAP_CAPABILITY_BINARY;
 					retry = TRUE;
-					CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+					/* This pais with the internal lock in imap_command_start */
+					camel_imap_store_connect_unlock_start_idle (store);
 					goto myretry;
 				}
 
@@ -5784,10 +5850,12 @@
 					nread = camel_stream_read (store->ostream, two_bytes, 1);
 			}
 berrorhander:
-			CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
-
-			if (err)
+			/* This is for the imap_command_start internal lock */
+			camel_imap_store_connect_unlock_start_idle (store);
+			if (err) {
+				g_message ("ERROR: ERR MESSAGE %s", errmessage);
 				goto errorhander;
+			}
 		} else
 		{
 			CamelImapResponse *response;
@@ -5867,8 +5935,6 @@
 				err = TRUE;
 			}
 
-			CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
-
 			camel_stream_reset (stream);
 
 			if (err)
@@ -6055,8 +6121,6 @@
 				memset (line, 0, MAX_LINE_LEN);
 			  }
 
-			CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
-
 			if (nread <= 0) {
 				err = TRUE;
 				ex_id = CAMEL_EXCEPTION_SERVICE_PROTOCOL;
@@ -6072,6 +6136,9 @@
 					g_free (boundary);
 				goto errorhander;
 			}
+			/* This is for the imap_command_start internal lock */
+			camel_imap_store_connect_unlock_start_idle (store);
+
 		}
 
 		if (boundary_len > 0)
@@ -6087,7 +6154,7 @@
 
 	CAMEL_IMAP_FOLDER_REC_UNLOCK (imap_folder, cache_lock);
 
-  CAMEL_SERVICE_REC_UNLOCK(store, connect_lock);
+	camel_imap_store_connect_unlock_start_idle (store);
 
 	stop_gmsgstore (imap_folder, ctchecker, FALSE);
 
@@ -6115,7 +6182,7 @@
 
 	if (store)
 	{
-  CAMEL_SERVICE_REC_UNLOCK(store, connect_lock);
+		camel_imap_store_connect_unlock_start_idle (store);
 
 		stop_gmsgstore (imap_folder, ctchecker, TRUE);
 	}
Index: libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-command.c
===================================================================
--- libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-command.c	(revisión: 3792)
+++ libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-command.c	(copia de trabajo)
@@ -122,7 +122,7 @@
 	va_list ap;
 	char *cmd = NULL;
 
-	CAMEL_SERVICE_REC_LOCK (store, connect_lock);
+	camel_imap_store_stop_idle_connect_lock (store);
 
 	if (fmt) {
 		va_start (ap, fmt);
@@ -179,7 +179,7 @@
 
 	if (!imap_command_start (store, folder, cmd, ex)) {
 		g_free (cmd);
-		CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+		camel_imap_store_connect_unlock_start_idle (store);
 		return NULL;
 	}
 	g_free (cmd);
@@ -234,13 +234,13 @@
 	cmd = imap_command_strdup_vprintf (store, fmt, ap);
 	va_end (ap);
 
-	CAMEL_SERVICE_REC_LOCK (store, connect_lock);
+	camel_imap_store_stop_idle_connect_lock (store);
 
 	ok = imap_command_start (store, folder, cmd, ex);
 	g_free (cmd);
 
 	if (!ok)
-		CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+		camel_imap_store_connect_unlock_start_idle (store);
 
 	return ok;
 }
@@ -250,6 +250,7 @@
 		    const char *cmd, CamelException *ex)
 {
 	ssize_t nwritten;
+	ssize_t nread;
 	gchar *resp = NULL;
 	CamelException myex = CAMEL_EXCEPTION_INITIALISER;
 	gchar *full_cmd = NULL;
@@ -354,11 +355,19 @@
 	}
 
 	/* Read away whatever we got */
-	while (camel_imap_store_readline_nb (store, &resp, &myex) > 0)
+	while ((nread = camel_imap_store_readline_nb (store, &resp, &myex)) > 0)
 	{
+#ifdef IMAP_DEBUG
+		gchar *debug_resp;
+		gchar *debug_resp_escaped;
 		imap_debug ("unsolitcited: ");
-		imap_debug (resp);
+		debug_resp = g_strndup (resp, nread);
+		debug_resp_escaped = g_strescape (debug_resp, "");
+		g_free (debug_resp);
+		imap_debug (debug_resp_escaped);
+		g_free (debug_resp_escaped);
 		imap_debug ("\n");
+#endif
 
 		g_free (resp);
 		resp=NULL;
@@ -434,7 +443,7 @@
 					     _("Operation cancelled"));
 			camel_imap_recon (store, &mex, TRUE);
 			imap_debug ("Recon in cont: %s\n", camel_exception_get_description (&mex));
-			CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+			camel_imap_store_connect_unlock_start_idle (store);
 			camel_exception_clear (&mex);
 			return NULL;
 		} else
@@ -442,7 +451,7 @@
 					     g_strerror (errno));
 		camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL);
 
-		CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+		camel_imap_store_connect_unlock_start_idle (store);
 		return NULL;
 	}
 
@@ -474,7 +483,7 @@
 	int len = -1;
 
 	if (camel_imap_store_readline (store, &respbuf, ex) < 0) {
-		CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+		camel_imap_store_connect_unlock_start_idle (store);
 		return CAMEL_IMAP_RESPONSE_ERROR;
 	}
 
@@ -537,7 +546,7 @@
 
 	if (type == CAMEL_IMAP_RESPONSE_ERROR ||
 	    type == CAMEL_IMAP_RESPONSE_TAGGED)
-		CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+		camel_imap_store_connect_unlock_start_idle (store);
 
 	return type;
 }
@@ -622,7 +631,7 @@
 	 * and gets unlocked when response is freed.
 	 */
 
-	CAMEL_SERVICE_REC_LOCK (store, connect_lock);
+	camel_imap_store_stop_idle_connect_lock (store);
 
 	response = g_new0 (CamelImapResponse, 1);
 	if (store->current_folder && camel_disco_store_status (CAMEL_DISCO_STORE (store)) != CAMEL_DISCO_STORE_RESYNCING) {
@@ -1071,7 +1080,7 @@
 
 	g_free (response);
 
-	CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+	camel_imap_store_connect_unlock_start_idle (store);
 }
 
 /**
Index: libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-folder.h
===================================================================
--- libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-folder.h	(revisión: 3792)
+++ libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-folder.h	(copia de trabajo)
@@ -92,6 +92,7 @@
 CamelType camel_imap_folder_get_type (void);
 
 void camel_imap_folder_stop_idle (CamelFolder *folder);
+void camel_imap_folder_stop_idle_in_connect_lock (CamelFolder *folder);
 void camel_imap_folder_start_idle (CamelFolder *folder);
 
 char* camel_imap_folder_get_highestmodseq (CamelImapFolder *imap_folder);
Index: libtinymail-camel/camel-lite/camel/camel-service.c
===================================================================
--- libtinymail-camel/camel-lite/camel/camel-service.c	(revisión: 3792)
+++ libtinymail-camel/camel-lite/camel/camel-service.c	(copia de trabajo)
@@ -59,6 +59,7 @@
 static gboolean service_connect(CamelService *service, CamelException *ex);
 static gboolean service_disconnect(CamelService *service, gboolean clean,
 				   CamelException *ex);
+static void service_can_idle (CamelService *service, gboolean can_idle);
 static void cancel_connect (CamelService *service);
 static GList *query_auth_types (CamelService *service, CamelException *ex);
 static char *get_name (CamelService *service, gboolean brief);
@@ -87,6 +88,7 @@
 	camel_service_class->query_auth_types = query_auth_types;
 	camel_service_class->get_name = get_name;
 	camel_service_class->get_path = get_path;
+	camel_service_class->can_idle = service_can_idle;
 }
 
 static void
@@ -769,3 +771,28 @@
 
 	return ret;
 }
+
+/**
+ * camel_service_can_idle:
+ * @service: a #CamelService
+ * @can_idle: a #gboolean
+ *
+ * Sets if service can do idle operations or not. This is for
+ * avoiding the service believe it can do idle operations in
+ * the middle of queued operations.
+ */
+void
+camel_service_can_idle (CamelService *service,
+			gboolean can_idle)
+{
+	g_return_val_if_fail (CAMEL_IS_SERVICE (service), NULL);
+
+	CSERV_CLASS (service)->can_idle (service, can_idle);
+}
+
+static void
+service_can_idle (CamelService *service,
+		  gboolean can_idle)
+{
+	/* Default implementation is empty */
+}
Index: libtinymail-camel/camel-lite/camel/camel-service.h
===================================================================
--- libtinymail-camel/camel-lite/camel/camel-service.h	(revisión: 3792)
+++ libtinymail-camel/camel-lite/camel/camel-service.h	(copia de trabajo)
@@ -73,6 +73,8 @@
 	gpointer data;
 	gboolean reconnecting;
 
+	gboolean can_idle;
+
 	con_op connecting;
 	con_op disconnecting;
 	con_op reconnecter;
@@ -101,6 +103,7 @@
 	char *    (*get_name)          (CamelService *service,
 					gboolean brief);
 	char *    (*get_path)          (CamelService *service);
+	void      (*can_idle)          (CamelService *service, gboolean can_idle);
 
 } CamelServiceClass;
 
@@ -141,6 +144,9 @@
 						      gboolean clean,
 						      CamelException *ex);
 
+void                camel_service_can_idle            (CamelService *service,
+						       gboolean can_idle);
+
 /* Standard Camel function */
 CamelType camel_service_get_type (void);
 
Index: libtinymail-camel/tny-camel-queue.c
===================================================================
--- libtinymail-camel/tny-camel-queue.c	(revisión: 3792)
+++ libtinymail-camel/tny-camel-queue.c	(copia de trabajo)
@@ -183,6 +183,7 @@
 tny_camel_queue_thread_main_func (gpointer user_data)
 {
 	TnyCamelQueue *queue = user_data;
+	TnyCamelAccountPriv *apriv;
 
 	while (!queue->stopped)
 	{
@@ -214,6 +215,9 @@
 			queue->current = item;
 		} else
 			wait = TRUE;
+		/* If no next item is scheduled then we can go idle after finishing operation */
+		apriv = TNY_CAMEL_ACCOUNT_GET_PRIVATE (queue->account);
+		camel_service_can_idle (apriv->service, !first || !first->next);
 		g_static_rec_mutex_unlock (queue->lock);
 
 		if (item) {
@@ -397,6 +401,7 @@
 _tny_camel_queue_launch_wflags (TnyCamelQueue *queue, GThreadFunc func, GSourceFunc callback, GDestroyNotify destroyer, GSourceFunc cancel_callback, GDestroyNotify cancel_destroyer, gboolean *cancel_field, gpointer data, gsize data_size, TnyCamelQueueItemFlags flags, const gchar *name)
 {
 	QueueItem *item = g_slice_new (QueueItem);
+	TnyCamelAccountPriv *apriv;
 
 	if (!g_thread_supported ())
 		g_thread_init (NULL);
@@ -437,6 +442,10 @@
 	} else /* Normal items simply get appended */
 		queue->list = g_list_append (queue->list, item);
 
+	/* If no next item is scheduled then we can go idle after finishing operation */
+	apriv = TNY_CAMEL_ACCOUNT_GET_PRIVATE (queue->account);
+	camel_service_can_idle (apriv->service, !queue->list || !queue->list->next);
+
 	if (queue->stopped) 
 	{
 		GError *err = NULL;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]