Re: Some IDLE improvements



Added inline comments and a bugfix


On Wed, 2007-10-24 at 02:56 +0200, Philip Van Hoof wrote:
> On Tue, 2007-10-23 at 18:51 +0200, Philip Van Hoof wrote:
> > On Tue, 2007-10-23 at 15:13 +0200, Philip Van Hoof wrote:
> > 
> > And another version :)
> 
> And another version. I have done quite a lot of testing with Modest and
> the demoui using this version. It also fixes the problem that previous
> versions of this patch had: that not all responses in IDLE where handled
> and that we where seeing unsolicited responses.
> 
> The reason was because non-blocking read in OpenSSL on the device seems
> to behave quite strange (there is stuff it can read, as I'm seeing it
> being retrieved in wireshark, but SSL_read() is not fetching it).
> 
> I first tried to figure out how SSL_read() is supposed to be called when
> doing a non-blocking read. But all that seemed alright.
> 
> As a solution I tried to just cope with that by reading away what is
> still available after the DONE is sent. Surprisingly does OpenSSL on the
> device read the content as soon as you SSL_write() something to the
> socket. Magic at work, I guess (or .. strange OpenSSL at work).
> 
> There was one problem with that: The CamelStreamBuffer didn't cope with
> non-blocking reads correctly, so it left a small part of the last read
> in its own buffer. This makes camel_imap_store_readline put that last
> part in the buffer-pointer that you give it byref.
> 
> That buffer-pointer was checked for being a tagged line or not. But if a
> last part of a previous buffer was put in that line, then that piece of
> string is of course not tagged (as it doesn't start with '*'). So I made
> an extra check for the lines that we expect after we send "DONE\r\n" to
> the server: I read until I receive a line with "OK", "NO" or "BAD", as
> those are the possible untagged responses that DONE (to get out of IDLE)
> can cause.
> 
> Luckily the CamelStreamBuffer gives the correct piece of buffer if you
> call its "gets" again, so in the body of the loop we simply ignore (and
> freeup) that corrupt string-piece and handle the next one.
> 
> Yeah :-\ Camel is absolutely not designed to cope with non blocking
> reading. IDLE more or less requires this, though. If the solution is
> handling just one known kludge, when switching between non-blocked and
> blocked reading, I guess it's okay (as long as the kludge is controlled
> and known).
> 
> I'm also not select()ing the socket. In stead I'm simlpy usleep()ing in
> some sort of loop. Future plans are indeed to get the select() wrapped
> in a CamelStream API, and call that from the code that is now doing an
> usleep(). I of course know that this usleep() is not ideal and that a
> timeout in select() is preferable.
> 
> I'm atm reviewing my code a few times. Will commit later today.
> 
> 
> _______________________________________________
> tinymail-devel-list mailing list
> tinymail-devel-list gnome org
> http://mail.gnome.org/mailman/listinfo/tinymail-devel-list
-- 
Philip Van Hoof, software developer
home: me at pvanhoof dot be 
gnome: pvanhoof at gnome dot org 
http://www.pvanhoof.be/blog



Index: libtinymail-camel/camel-lite/camel/camel-stream.c
===================================================================
--- libtinymail-camel/camel-lite/camel/camel-stream.c	(revision 2872)
+++ libtinymail-camel/camel-lite/camel/camel-stream.c	(working copy)
@@ -98,20 +98,8 @@
 	return (CS_CLASS (stream)->read) (stream, buffer, n);
 }
 
-ssize_t
-camel_stream_read_idle (CamelStream *stream, char *buffer, size_t n)
-{
-	g_return_val_if_fail (CAMEL_IS_STREAM (stream), -1);
-	g_return_val_if_fail (n == 0 || buffer, -1);
 
-	/* Default impl */
-	if (!CS_CLASS (stream)->read_idle)
-		return (CS_CLASS (stream)->read) (stream, buffer, n);
 
-	return (CS_CLASS (stream)->read_idle) (stream, buffer, n);
-}
-
-
 /**
  * camel_stream_write:
  * @stream: a #CamelStream object
Index: libtinymail-camel/camel-lite/camel/camel-stream.h
===================================================================
--- libtinymail-camel/camel-lite/camel/camel-stream.h	(revision 2872)
+++ libtinymail-camel/camel-lite/camel/camel-stream.h	(working copy)
@@ -56,15 +56,12 @@
 	gboolean  (*eos)        (CamelStream *stream);
 	int       (*reset)      (CamelStream *stream);
 
-	ssize_t   (*read_idle)  (CamelStream *stream, char *buffer, size_t n);
-
 } CamelStreamClass;
 
 /* Standard Camel function */
 CamelType camel_stream_get_type (void);
 
 /* public methods */
-ssize_t    camel_stream_read_idle  (CamelStream *stream, char *buffer, size_t n);
 
 ssize_t    camel_stream_read       (CamelStream *stream, char *buffer, size_t n);
 ssize_t    camel_stream_write      (CamelStream *stream, const char *buffer, size_t n);
Index: libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-store.c
===================================================================
--- libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-store.c	(revision 2872)
+++ libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-store.c	(working copy)
@@ -195,49 +195,48 @@
 }
 
 static void 
-let_idle_die (CamelImapStore *imap_store, gboolean connect_buz)
+let_idle_die (CamelImapStore *store, gboolean connect_buz)
 {
-	imap_store->idle_cont = FALSE;
 
-	g_static_rec_mutex_lock (imap_store->idle_prefix_lock);
-	g_static_rec_mutex_lock (imap_store->idle_lock);
+	idle_debug ("let_idle_die starts\n");
 
-	imap_store->idle_cont = FALSE;
+	g_static_rec_mutex_lock (store->idle_prefix_lock);
+	g_static_rec_mutex_lock (store->idle_lock);
 
-	/* This one can get called from within the thread! This would deadlock
+	store->idle_kill = TRUE;
+	store->idle_cont = FALSE;
 
-	if (imap_store->in_idle && imap_store->idle_thread) {
-		g_thread_join (imap_store->idle_thread);
-		imap_store->idle_thread = NULL;
-	} */
-
-	if (imap_store->idle_prefix)
+	if (store->idle_prefix)
 	{
 		gchar *resp = NULL;
 		int nwritten = 0;
 		CamelException ex = CAMEL_EXCEPTION_INITIALISER;
 
-		g_free (imap_store->idle_prefix); 
-		imap_store->idle_prefix=NULL;
-
 		idle_debug ("Sending DONE in let_idle_die\n");
-		nwritten = camel_stream_printf (imap_store->ostream, "DONE\r\n");
-		if (nwritten != -1) 
-		{
+		CAMEL_SERVICE_REC_LOCK (store, connect_lock);
+		nwritten = camel_stream_printf (store->ostream, "DONE\r\n");
+		store->in_idle = FALSE;
+		if (nwritten != -1) {
 			resp = NULL;
-			while ((camel_imap_command_response_idle (imap_store, &resp, &ex)) == CAMEL_IMAP_RESPONSE_UNTAGGED) 
-			{
-				idle_debug ("(.., ..) <- %s | in idle_deal_with_stuff in let_idle_die\n", resp); 
+			while ((camel_imap_command_response_idle (store, &resp, &ex)) == CAMEL_IMAP_RESPONSE_UNTAGGED) {
+				idle_debug ("(.., ..) <- %s | in let_idle_die\n", resp); 
 				g_free (resp); resp=NULL; 
 			}
-			if (resp)
+			if (resp) {
+				idle_debug ("(.., ..) <- %s\n", resp);
 				g_free (resp);
+			}
 		}
+		CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+		g_free (store->idle_prefix); 
+		store->idle_prefix=NULL;
 	}
 
-	g_static_rec_mutex_unlock (imap_store->idle_lock);
-	g_static_rec_mutex_unlock (imap_store->idle_prefix_lock);
+	g_static_rec_mutex_unlock (store->idle_lock);
+	g_static_rec_mutex_unlock (store->idle_prefix_lock);
 
+	idle_debug ("let_idle_die finished\n");
+
 	return;
 }
 
@@ -247,41 +246,33 @@
 	if (store->current_folder && CAMEL_IS_IMAP_FOLDER (store->current_folder))
 		camel_imap_folder_stop_idle (store->current_folder);
 	else {
-		store->idle_cont = FALSE;
-
 		g_static_rec_mutex_lock (store->idle_prefix_lock);
 		g_static_rec_mutex_lock (store->idle_lock);
 
+		store->idle_kill = TRUE;
 		store->idle_cont = FALSE;
-		if (store->in_idle && store->idle_thread) {
-			g_thread_join (store->idle_thread);
-			store->idle_thread = NULL;
-		}
 
-		if (store->idle_prefix) 
-		{
+		if (store->idle_prefix) {
 			gchar *resp = NULL;
 			int nwritten = 0;
 			CamelException ex = CAMEL_EXCEPTION_INITIALISER;
 
-			idle_debug ("Sending DONE in camel_imap_store_stop_idle (no current folder?)\n");
+			idle_debug ("Sending DONE in camel_imap_store_stop_idle\n");
 			CAMEL_SERVICE_REC_LOCK (store, connect_lock);
 			nwritten = camel_stream_printf (store->ostream, "DONE\r\n");
-
-			if (nwritten != -1) 
-			{
+			store->in_idle = FALSE;
+			if (nwritten != -1) {
 				resp = NULL;
-				while ((camel_imap_command_response_idle (store, &resp, &ex)) == CAMEL_IMAP_RESPONSE_UNTAGGED) 
-				{
+				while ((camel_imap_command_response_idle (store, &resp, &ex)) == CAMEL_IMAP_RESPONSE_UNTAGGED) {
 					idle_debug ("(.., ..) <- %s | in idle_deal_with_stuff (no current folder?)\n", resp); 
 					g_free (resp); resp=NULL; 
 				}
-				if (resp)
+				if (resp) {
+					idle_debug ("(.., ..) <- %s\n", resp);
 					g_free (resp);
+				}
 			}
-
 			CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
-
 			g_free (store->idle_prefix);
 			store->idle_prefix = NULL;
 		}
@@ -312,6 +303,7 @@
 			camel_imap_folder_selected (folder, response2, &nex, TRUE);
 			camel_imap_response_free (imap_store, response2);
 		}
+		camel_imap_store_start_idle (imap_store);
 	}
 
 	return;
@@ -441,7 +433,7 @@
 
 	imap_store->dontdistridlehack = FALSE;
 
-	imap_store->idle_sleep = 20; /* default of 20s */
+	imap_store->idle_sleep = 600; /* default of 10m */
 	imap_store->getsrv_sleep = 100; /* default of 100s */
 
 	imap_store->in_idle = FALSE;
@@ -2588,8 +2580,8 @@
 	}
 	imap_status_item_free (items);
 
-	camel_imap_store_start_idle (imap_store);
 	CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
+	camel_imap_store_start_idle (imap_store);
 
 	return;
 }
@@ -2630,16 +2622,18 @@
 		const char *c;
 		
 		if (camel_exception_get_id(ex) == CAMEL_EXCEPTION_USER_CANCEL) {
-			camel_imap_store_start_idle (imap_store);
 			CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
+			camel_imap_store_start_idle (imap_store);
+
 			return NULL;
 		}
 		
 		camel_exception_clear (ex);
 		
 		if (!(flags & CAMEL_STORE_FOLDER_CREATE)) {
-			camel_imap_store_start_idle (imap_store);
 			CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
+			camel_imap_store_start_idle (imap_store);
+
 			camel_exception_setv (ex, CAMEL_EXCEPTION_STORE_NO_FOLDER,
 					      _("No such folder %s"), folder_name);
 			return NULL;
@@ -2651,11 +2645,11 @@
 			c++;
 		
 		if (*c != '\0') {
-			camel_imap_store_start_idle (imap_store);
 			CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
 			camel_exception_setv (ex, CAMEL_EXCEPTION_FOLDER_INVALID_PATH,
 					      _("The folder name \"%s\" is invalid because it contains the character \"%c\""),
 					      folder_name, *c);
+			camel_imap_store_start_idle (imap_store);
 			return NULL;
 		}
 
@@ -2673,10 +2667,12 @@
 			int i;
 			
 			if (!(response = camel_imap_command (imap_store, NULL, ex, "LIST \"\" %G", parent_real))) {
-				camel_imap_store_start_idle (imap_store);
-				CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
 				g_free (parent_name);
 				g_free (parent_real);
+
+				CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
+				camel_imap_store_start_idle (imap_store);
+
 				return NULL;
 			}
 			
@@ -2717,12 +2713,13 @@
 				imap_status_item_free (items);
 				
 				if (messages > 0) {
-					camel_imap_store_start_idle (imap_store);
 					camel_exception_set (ex, CAMEL_EXCEPTION_FOLDER_INVALID_STATE,
 							     _("The parent folder is not allowed to contain subfolders"));
-					CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
 					g_free (parent_name);
 					g_free (parent_real);
+					CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
+					camel_imap_store_start_idle (imap_store);
+
 					return NULL;
 				}
 				
@@ -2730,11 +2727,11 @@
 				camel_exception_init (&lex);
 				delete_folder (store, parent_name, &lex);
 				if (camel_exception_is_set (&lex)) {
-					camel_imap_store_start_idle (imap_store);
-					CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
-					camel_exception_xfer (ex, &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_exception_xfer (ex, &lex);
 					return NULL;
 				}
 				
@@ -2745,10 +2742,11 @@
 				g_free (name);
 				
 				if (!response) {
-					camel_imap_store_start_idle (imap_store);
-					CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
 					g_free (parent_name);
 					g_free (parent_real);
+					CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
+					camel_imap_store_start_idle (imap_store);
+
 					return NULL;
 				} else
 					camel_imap_response_free (imap_store, response);
@@ -2770,8 +2768,9 @@
 		}
 		g_free(folder_real);
 		if (!response) {
-			camel_imap_store_start_idle (imap_store);
 			CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
+			camel_imap_store_start_idle (imap_store);
+
 			return NULL;
 		}
 	} else if (flags & CAMEL_STORE_FOLDER_EXCL) {
@@ -2780,9 +2779,9 @@
 				      folder_name);
 		
 		camel_imap_response_free_without_processing (imap_store, response);
-		camel_imap_store_start_idle (imap_store);
 		CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
-		
+		camel_imap_store_start_idle (imap_store);
+
 		return NULL;
 	}
 
@@ -2809,9 +2808,9 @@
 	}
 	camel_imap_response_free_without_processing (imap_store, response);
 
-	camel_imap_store_start_idle (imap_store);
 	CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
-	
+	camel_imap_store_start_idle (imap_store);
+
 	return new_folder;
 }
 
@@ -2850,7 +2849,6 @@
 {
 	CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
 	CamelImapResponse *response;
-	gboolean did_start_idle = FALSE;
 	CamelFolder *old_in_case;
 
 	CAMEL_SERVICE_REC_LOCK (imap_store, connect_lock);
@@ -2881,7 +2879,6 @@
 		if (response2) {
 			camel_imap_folder_selected (old_in_case, response2, &nex, TRUE);
 			camel_imap_response_free (imap_store, response2);
-			did_start_idle = TRUE;
 		}
 	}
 
@@ -2890,9 +2887,10 @@
 		imap_forget_folder (imap_store, folder_name, ex);
 	}
 fail:
-	if (!did_start_idle)
-		camel_imap_store_start_idle (imap_store);
 	CAMEL_SERVICE_REC_UNLOCK(imap_store, connect_lock);
+
+	camel_imap_store_start_idle (imap_store);
+
 }
 
 static void
@@ -3033,7 +3031,6 @@
 	char *oldpath, *newpath, *storage_path;
 	char *tpath, *lslash;
 	CamelFolder *old_in_case = NULL;
-	gboolean did_start_idle = FALSE;
 
 	CAMEL_SERVICE_REC_LOCK (imap_store, connect_lock);
 
@@ -3078,7 +3075,6 @@
 		if (response2) {
 			camel_imap_folder_selected (old_in_case, response2, &nex, TRUE);
 			camel_imap_response_free (imap_store, response2);
-			did_start_idle = TRUE;
 		}
 	}
 
@@ -3126,10 +3122,11 @@
 	g_free (newpath);
 fail:
 	imap_store->renaming = FALSE;
-	if (!did_start_idle)
-		camel_imap_store_start_idle (imap_store);
 	CAMEL_SERVICE_REC_UNLOCK(imap_store, connect_lock);
 	camel_operation_end (NULL);
+
+	camel_imap_store_start_idle (imap_store);
+
 }
 
 static CamelFolderInfo *
@@ -3955,8 +3952,10 @@
 
 	imap_folder_effectively_unsubscribed (imap_store, folder_name, ex);
 done:
-	camel_imap_store_start_idle (imap_store);
 	CAMEL_SERVICE_REC_UNLOCK(store, connect_lock);
+
+	camel_imap_store_start_idle (imap_store);
+
 }
 
 #if 0
Index: libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-store.h
===================================================================
--- libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-store.h	(revision 2872)
+++ libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-store.h	(working copy)
@@ -165,7 +165,7 @@
 
 	GStaticRecMutex *idle_prefix_lock, *idle_lock, *sum_lock;
 	GThread *idle_thread;
-	gboolean idle_cont, in_idle;
+	gboolean idle_cont, in_idle, idle_kill;
 	guint idle_sleep, getsrv_sleep;
 	gboolean courier_crap;
 	gboolean going_online, got_online, clean_exit;
Index: libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-folder.c
===================================================================
--- libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-folder.c	(revision 2872)
+++ libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-folder.c	(working copy)
@@ -38,6 +38,8 @@
 
 #include <config.h> 
 
+#include <sched.h>
+
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -161,7 +163,7 @@
 
 static GData *parse_fetch_response (CamelImapFolder *imap_folder, char *msg_att);
 static void camel_imap_folder_changed_for_idle (CamelFolder *folder, int exists,
-			   GArray *expunged, CamelException *ex, CamelFolderChangeInfo *changes);
+			   GArray *expunged, CamelException *ex, CamelFolderChangeInfo *changes, gboolean exists_happened);
 
 GPtrArray* _camel_imap_store_get_recent_messages (CamelImapStore *imap_store, const char *folder_name, int *messages, int *unseen, gboolean withthem);
 
@@ -760,8 +762,6 @@
 		camel_folder_change_info_free(changes);
 	}
 
-	if (idle)
-		camel_imap_folder_start_idle (folder);
 }
 
 
@@ -907,18 +907,17 @@
 		 * messages. */
 		imap_rescan (folder, camel_folder_summary_count (folder->summary), ex);
 	} else {
+
 #if 0
 		/* on some servers need to CHECKpoint INBOX to recieve new messages?? */
 		/* rfc2060 suggests this, but havent seen a server that requires it */
 		if (g_ascii_strcasecmp(folder->full_name, "INBOX") == 0) {
 			response = camel_imap_command (imap_store, folder, ex, "CHECK");
 			camel_imap_response_free (imap_store, response);
-			camel_imap_folder_start_idle (folder);
 		}
 #endif
 		response = camel_imap_command (imap_store, folder, ex, "NOOP");
 		camel_imap_response_free (imap_store, response);
-		camel_imap_folder_start_idle (folder);
 	}
 
 	si = camel_store_summary_path((CamelStoreSummary *)((CamelImapStore *)folder->parent_store)->summary, folder->full_name);
@@ -939,8 +938,10 @@
 	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_store_summary_save((CamelStoreSummary *)((CamelImapStore *)folder->parent_store)->summary, ex);
+	camel_imap_folder_start_idle (folder);
+
 }
 
 #if 0
@@ -1522,19 +1523,17 @@
 		}
 		g_ptr_array_free (matches, TRUE);
 
-		if (camel_exception_is_set (&local_ex))
-			camel_imap_folder_start_idle (folder);
-
 		/* 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)) {
-			/* Look up */
+			
 			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);
 	}
@@ -1542,9 +1541,9 @@
 	/* Save the summary */
 	imap_sync_offline (folder, ex);
 
+	CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
 	camel_imap_folder_start_idle (folder);
-	CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
-	/* camel_imap_folder_start_idle (folder); */
+
 }
 
 static int
@@ -1643,7 +1642,6 @@
 	
 	CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
 
-
 	camel_imap_folder_start_idle (folder);
 
 }
@@ -3463,7 +3461,7 @@
 	GArray *expunged;
 	GList *vanished;
 	GPtrArray *fetch;
-	gboolean fetch_happened;
+	gboolean exists_happened;
 	CamelFolder *folder;
 } IdleResponse;
 
@@ -3529,7 +3527,7 @@
 	}
 
 	camel_imap_folder_changed_for_idle (idle_resp->folder, idle_resp->exists, 
-		idle_resp->expunged, &ex, changes);
+		idle_resp->expunged, &ex, changes, idle_resp->exists_happened);
 
 }
 
@@ -3541,8 +3539,10 @@
 
 	idle_debug ("read_idle_response (%s)\n", resp);
 
-	if (ptr && camel_strstrcase (resp, "EXISTS") != NULL)
+	if (ptr && camel_strstrcase (resp, "EXISTS") != NULL) {
 		idle_resp->exists = strtoul (resp + 1, NULL, 10);
+		idle_resp->exists_happened = TRUE;
+	}
 
 	if (ptr && camel_strstrcase (resp, "RECENT") != NULL)
 		idle_resp->recent = strtoul (resp + 1, NULL, 10);
@@ -3591,12 +3591,10 @@
 idle_response_new (CamelFolder *folder)
 {
 	IdleResponse *idle_resp = g_slice_new0 (IdleResponse);
-
+	idle_debug ("idle_response_new\n");
 	idle_resp->vanished = NULL;
-
-	idle_debug ("idle_response_new\n");
-
 	idle_resp->folder = folder;
+	idle_resp->exists_happened = FALSE;
 	camel_object_ref (CAMEL_OBJECT (folder));
 	return idle_resp;
 }
@@ -3604,27 +3602,23 @@
 static void
 idle_response_free (IdleResponse *idle_resp)
 {
-	guint i=0;
-
 	idle_debug ("idle_response_free\n");
-
 	if (idle_resp->expunged)
 		g_array_free (idle_resp->expunged, TRUE);
-
 	if (idle_resp->vanished) {
-		g_list_foreach (idle_resp->vanished, (GFunc)g_free, NULL);
+		g_list_foreach (idle_resp->vanished, (GFunc) g_free, NULL);
 		g_list_free (idle_resp->vanished);
 		idle_resp->vanished = NULL;
 	}
-
-	if (idle_resp->fetch) 
+	if (idle_resp->fetch) {
+		guint i=0;
 		for (i=0 ;i < idle_resp->fetch->len; i++)
 			g_slice_free (FetchIdleResponse, idle_resp->fetch->pdata[i]);
-
+	}
 	if (idle_resp->folder)
 		camel_object_unref (CAMEL_OBJECT (idle_resp->folder));
-
 	g_slice_free (IdleResponse, idle_resp);
+	return;
 }
 
 
@@ -3633,18 +3627,18 @@
 {
 	char *resp;
 	CamelException ex = CAMEL_EXCEPTION_INITIALISER;
-
+	gboolean l = CAMEL_SERVICE_REC_TRYLOCK (store, connect_lock);
 	if (store->ostream && store->istream && CAMEL_IS_STREAM (store->ostream))
 	{
+		int nwritten = 0;
 		if (store->idle_prefix)
 			g_free (store->idle_prefix);
 		store->idle_prefix = g_strdup_printf ("%c%.5u", 
 			store->tag_prefix, store->command++);
-
-		idle_debug ("(.., ..) -> %s IDLE | in idle_real_start\n", store->idle_prefix);
-
-		camel_stream_printf (store->ostream, "%s IDLE\r\n",
+		nwritten = camel_stream_printf (store->ostream, "%s IDLE\r\n",
 			store->idle_prefix);
+		idle_debug ("(%d, %d) -> %s IDLE\n", strlen (store->idle_prefix)+5, 
+			nwritten, store->idle_prefix);
 	} else {
 		idle_debug ("idle_real_start connection lost\n");
 		goto errh;
@@ -3658,7 +3652,6 @@
 	 * active, the server is now free to send untagged EXISTS, EXPUNGE, and
 	 *  other messages at any time. */
 
-
 	/* So according to the RFC, we will wait for the server for its + 
 	 * continuation. If the server doesn't do this, it's an incorrect 
 	 * IDLE implementation at the server. Right? */
@@ -3680,240 +3673,366 @@
 	}
 	if (resp)
 		g_free (resp);
-
 errh:
+	if (l)
+		CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+	return;
+}
 
+
+static void
+consume_idle_line (CamelImapStore *store, CamelFolder *folder, char *resp, IdleResponse *idle_resp)
+{
+	if (strchr (resp, '*') != NULL && (camel_strstrcase (resp, "EXISTS") || 
+		camel_strstrcase (resp, "FETCH")|| camel_strstrcase (resp, "EXPUNGE") || 
+		camel_strstrcase (resp, "VANISHED") || camel_strstrcase (resp, "RECENT")))
+	{
+		if (!idle_resp) 
+			idle_resp = idle_response_new (folder);
+		read_idle_response (folder, resp, idle_resp);
+	}
+	idle_debug ("(%d, ..) <- %s\n", 
+		strlen (resp), resp);
 	return;
 }
 
-static IdleResponse*
-idle_deal_with_stuff (CamelFolder *folder, CamelImapStore *store, gboolean *had_err, gboolean *had_lock)
+typedef struct {
+	CamelFolder *folder;
+	GCond *condition;
+	GMutex *mutex;
+	gboolean had_cond;
+} IdleThreadInfo;
+
+static gpointer 
+idle_thread (gpointer data)
 {
-  IdleResponse *idle_resp = NULL;
-  CamelException ex = CAMEL_EXCEPTION_INITIALISER;
-  char *resp = NULL;
-  int nwritten=0;
-  CamelImapResponseType type;
-  gboolean hlock = FALSE;
+	IdleThreadInfo *info = (IdleThreadInfo *) data;
+	CamelFolder *folder = (CamelFolder *) info->folder;
+	CamelImapFolder *imap_folder;
+	CamelImapStore *store;
+	gboolean tfirst = TRUE, first = TRUE, my_cont, had_cond = FALSE;
+	int cnt = 0;
+	int nwritten=0;
+	gpointer retval = NULL;
 
-  idle_debug ("idle_deal_with_stuff\n");
+	idle_debug ("idle_thread starts\n");
 
-  if (!camel_disco_store_check_online ((CamelDiscoStore*)store, &ex))
-	return NULL;
+	/* > a1 IDLE\r\n                        | A
+	 * < + idling\r\n                       |
+	 * < ...\r\n                            | B
+	 * < * 72 FETCH (FLAGS (\seen))\r\n     |
+	 * < * 106 FETCH (FLAGS (\seen))\r\n    |
+	 * < * 169 FETCH (FLAGS (\seen))\r\n    |
+	 * < ...\r\n                            |
+	 * > DONE\r\n                           | C
+	 * < * 111 FETCH (FLAGS (\seen))\r\n    |
+	 * < * 112 FETCH (FLAGS (\seen))\r\n    |
+	 * < * 113 FETCH (FLAGS (\seen))\r\n    |
+	 * < a1 OK IDLE terminated\r\n          | */
 
-  hlock = CAMEL_SERVICE_REC_TRYLOCK (store, connect_lock);
+	if (!folder || !folder->parent_store) { 
+		g_thread_exit (retval); 
+		return retval; 
+	}
 
-  if (hlock)
-  {
-	if (store->current_folder)
+	if (!CAMEL_IS_FOLDER (folder) || !CAMEL_IS_STORE (folder->parent_store)) { 
+		g_thread_exit (retval); 
+		return retval; 
+	}
+
+	store = CAMEL_IMAP_STORE (folder->parent_store);
+	imap_folder = CAMEL_IMAP_FOLDER (folder);
+
+	if (!imap_folder->do_push_email) {
+		idle_debug ("Folder set not to do idle\n");
+		g_thread_exit (retval);
+		return retval;
+	}
+
+	if (!(store->capabilities & IMAP_CAPABILITY_IDLE)) {
+		idle_debug ("Server has no IDLE capabilities\n");
+		g_thread_exit (retval);
+		return retval;
+	}
+
+
+	/* We add our own reference because the calling thread will immediately
+	 * after the GCond broadcast free the info (and its references). We add
+	 * this reference 'before' we broadcast! Of course. */
+
+	camel_object_ref (folder);
+
+	/* In case of an immediate stop after a start, we'll have FALSE here,
+	 * usually we'll have TRUE, of course. This is, however, the reason
+	 * for the had_cond broadcaster below (it's possible we never entered
+	 * the loop). */
+
+	my_cont = store->idle_cont;
+
+	if (my_cont) {
+		idle_debug ("idle_thread starting\n");
+	} else {
+		idle_debug ("idle_thread starting but immediately stopping\n");
+	}
+
+	/* 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) 
 	{
-		/* We read-away everything non-blocking and process it */
-		resp = NULL;
-		while (camel_imap_store_readline_nb (store, &resp, &ex) > 0)
+		CamelException ex = CAMEL_EXCEPTION_INITIALISER;
+		char *resp = NULL;
+		IdleResponse *idle_resp = NULL;
+		gboolean senddone = FALSE;
+
+		/* 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;
+		}
+
+		/* 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;
+		}
+
+		if (g_static_rec_mutex_trylock (store->idle_lock)) 
 		{
-			if (strchr (resp, '*') != NULL && (camel_strstrcase (resp, "EXISTS") || 
-				camel_strstrcase (resp, "FETCH")|| camel_strstrcase (resp, "EXPUNGE") || 
-				camel_strstrcase (resp, "VANISHED") || camel_strstrcase (resp, "RECENT")))
-			{
-				if (!idle_resp) 
-					idle_resp = idle_response_new (folder);
-				read_idle_response (folder, resp, idle_resp);
+			/* 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;
+				}
 			}
-			idle_debug ("(%d, ..) <- %s | in idle_deal_with_stuff at nb\n", 
-				strlen (resp), resp);
-			g_free (resp); resp=NULL;
+			g_static_rec_mutex_unlock (store->idle_lock);
 		}
+
 		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;
+			} else if (idle_resp && idle_resp->exists_happened) {
 
-		/* Here we force the server to tell us about the changes: */
+				/* We can't deal with new EXISTS responses 
+				 * without first stopping IDLE (we'll need to
+				 * fetch the new headers) */
 
-		/* The IDLE command is terminated by the receipt of a "DONE"
-		 * continuation from the client; such response satisfies the server's
-		 * continuation request.  At that point, the server MAY send any
-		 * remaining queued untagged responses and then MUST immediately send
-		 * the tagged response to the IDLE command and prepare to process other
-		 * commands. */
-
-		if (store->ostream && CAMEL_IS_STREAM (store->ostream)) {
-			nwritten = camel_stream_printf (store->ostream, "DONE\r\n");
-			idle_debug ("(%d, 8) -> DONE | Sending DONE in idle_deal_with_stuff (nb)\n",
-				nwritten);
+				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; 
 		}
 
-		if (nwritten == -1) 
-			goto outofhere;
+		/* 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). */
 
-		resp = NULL;
-		while ((type = camel_imap_command_response_idle (store, &resp, &ex)) == CAMEL_IMAP_RESPONSE_UNTAGGED) 
+		if ((cnt > store->idle_sleep) || senddone) 
 		{
-			/* printf ("D resp: %s\n", resp); */
-			if (strchr (resp, '*') != NULL && (camel_strstrcase (resp, "EXISTS") ||
-				camel_strstrcase (resp, "FETCH") || camel_strstrcase (resp, "EXPUNGE") || 
-				camel_strstrcase (resp, "RECENT")))
+			if (store->idle_prefix) 
 			{
-				if (!idle_resp)
-					idle_resp = idle_response_new (folder);
-				read_idle_response (folder, resp, idle_resp);
-			}
-			idle_debug ("(%d, ..) <- %s | in idle_deal_with_stuff at idle\n", 
-				strlen (resp), resp);
-			g_free (resp); resp=NULL;
-		}
+				CamelImapResponseType type;
+				gboolean l = g_static_rec_mutex_trylock (store->idle_lock);
 
-		if (type == CAMEL_IMAP_RESPONSE_ERROR)
-			*had_err = TRUE;
+				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). */
 
-		if (resp)
-			g_free (resp);
+					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);
+						}
 
-	} else {
-		/* Trying to deal while the current folder is gone: just read away everything */
-		if (store->ostream && CAMEL_IS_STREAM (store->ostream)) {
-			nwritten = camel_stream_printf (store->ostream, "DONE\r\n");
-			idle_debug ("(%d, 8) -> DONE | Sending DONE in idle_deal_with_stuff (b)\n",
-				nwritten);
-		}
-		if (nwritten == -1) 
-			goto outofhere;
-		resp = NULL;
-		while ((type = camel_imap_command_response_idle (store, &resp, &ex)) == CAMEL_IMAP_RESPONSE_UNTAGGED) 
-		{
-			idle_debug ("(.., ..) <- %s | in idle_deal_with_stuff in else\n", resp); 
-			g_free (resp); resp=NULL; 
-		}
-		if (resp)
-			g_free (resp);
-	}
+						if (resp)
+							g_free (resp);
+						resp = NULL;
+					}
+					if (resp)
+						g_free (resp);
+					resp = NULL;
 
-outofhere:
+					/* We send the DONE to the server */
 
-	CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
-  } 
+					nwritten = camel_stream_printf (store->ostream, "DONE\r\n");
+					idle_debug ("(%d, 8) -> DONE\n", nwritten);
 
-  *had_lock = hlock;
+					/* We read away everything the server sends 
+					 * until the we see the untagged OK response */
 
-  return idle_resp;
-}
+					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);
+						}
 
-void
-camel_imap_folder_stop_idle (CamelFolder *folder)
-{
-	CamelImapStore *store;
-	IdleResponse *idle_resp = NULL;
-	gboolean had_err = FALSE;
-	CamelException ex = CAMEL_EXCEPTION_INITIALISER;
+						if (resp)
+							g_free (resp);
+						resp = NULL;
+					}
+				}
 
-	idle_debug ("camel_imap_folder_stop_idle\n");
+				if (l)
+					g_static_rec_mutex_unlock (store->idle_lock);
 
-	store = CAMEL_IMAP_STORE (folder->parent_store);
+				if (resp)
+					g_free (resp);
+				resp = NULL;
 
-	if (!camel_disco_store_check_online ((CamelDiscoStore*)store, &ex))
-		return;
+				/* If we are continuing the loop, handle idle_resp
+				 * now (this can invoke fetching new headers). */
 
-	store->idle_cont = FALSE;
+				if (store->idle_cont) {
+					process_idle_response (idle_resp);
+					idle_response_free (idle_resp);
+					idle_resp = NULL;
+				}
+			}
 
-	g_static_rec_mutex_lock (store->idle_lock);
-	g_static_rec_mutex_lock (store->idle_prefix_lock);
+			if (store->idle_cont)
+				first = TRUE; 
+			else
+				my_cont = FALSE;
 
-	if ((store->capabilities & IMAP_CAPABILITY_IDLE) && store->idle_prefix)
-	{
-		gboolean had_lock = FALSE;
-
-		store->idle_cont = FALSE;
-		if (store->in_idle && store->idle_thread) {
-			g_thread_join (store->idle_thread);
-			store->idle_thread = NULL;
+			cnt = 0;
 		}
 
-		if (store->idle_prefix)
-			g_free (store->idle_prefix);
-		store->idle_prefix = NULL;
+		/* TNY TODO: try to use the select() of the non-blocking read 
+		 * for this usleep() and cnt stuff. */
 
-		idle_resp = idle_deal_with_stuff (folder, store, &had_err, &had_lock);
+		if (my_cont)
+			usleep (500000);
+		cnt++;
+	}
 
-		if (idle_resp && !had_err)
-			process_idle_response (idle_resp);
+	/* We have an extra bool for this, because it's possible that info
+	 * is already freed (of the broadcast happened above, the calling
+	 * thread will have freed it already) */
 
-		if (idle_resp) 
-			idle_response_free (idle_resp);
+	if (!had_cond && !info->had_cond && info->condition) {
+		g_mutex_lock (info->mutex);
+		g_cond_broadcast (info->condition);
+		info->had_cond = TRUE;
+		g_mutex_unlock (info->mutex);
 	}
 
-	g_static_rec_mutex_unlock (store->idle_prefix_lock);
-	g_static_rec_mutex_unlock (store->idle_lock);
+	camel_object_unref (folder);
 
+	g_thread_exit (retval);
+
+	return retval;
 }
 
 
-static gpointer 
-idle_thread (gpointer data)
+void
+camel_imap_folder_stop_idle (CamelFolder *folder)
 {
-	CamelFolder *folder = (CamelFolder *) data;
-	CamelImapFolder *imap_folder;
 	CamelImapStore *store;
-	gboolean had_err = FALSE, hadlock = FALSE;
+	CamelException ex = CAMEL_EXCEPTION_INITIALISER;
 
-	idle_debug ("idle_thread\n");
+	idle_debug ("camel_imap_folder_stop_idle\n");
 
-	if (!folder || !folder->parent_store)
-		{ g_thread_exit (NULL); return NULL; }
-
-	if (!CAMEL_IS_FOLDER (folder) || !CAMEL_IS_STORE (folder->parent_store))
-		{ g_thread_exit (NULL); return NULL; }
-
 	store = CAMEL_IMAP_STORE (folder->parent_store);
-	imap_folder = CAMEL_IMAP_FOLDER (folder);
 
-	if (!imap_folder->do_push_email) {
-		idle_debug ("Folder set not to do idle\n");
-		return NULL;
-	}
+	store->idle_cont = FALSE;
 
-	if (!(store->capabilities & IMAP_CAPABILITY_IDLE)) {
-		idle_debug ("Server has no IDLE capabilities\n");
-		return NULL;
-	}
+	if (!camel_disco_store_check_online ((CamelDiscoStore*)store, &ex))
+		return;
 
-	idle_debug ("idle_thread starting (%s)\n", store->idle_prefix?store->idle_prefix:"(none)");
-
-	store->idle_cont = TRUE;
-
-	while (store->idle_cont && store->idle_prefix != NULL)
+	if ((store->capabilities & IMAP_CAPABILITY_IDLE))
 	{
-		int x = 0;
+		if (store->in_idle && store->idle_thread) {
+			IdleResponse *idle_resp = NULL;
+			store->idle_cont = FALSE;
+			idle_resp = g_thread_join (store->idle_thread);
+			g_static_rec_mutex_lock (store->idle_prefix_lock);
+			g_static_rec_mutex_lock (store->idle_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_lock);
+			g_static_rec_mutex_unlock (store->idle_prefix_lock);
 
-		g_static_rec_mutex_lock (store->idle_lock);
-		g_static_rec_mutex_lock (store->idle_prefix_lock);
+			/* We are doing this here because here we wont hit the
+			 * priv->folder's lock of TnyCamelFolder during its
+			 * folder_changed handler. */
 
-		store->in_idle = TRUE;
-		if (store->idle_prefix != NULL)
-		{
-			IdleResponse *idle_resp = idle_deal_with_stuff (folder, store, &had_err,&hadlock);
-
-			if (idle_resp && !had_err)
+			if (idle_resp) {
 				process_idle_response (idle_resp);
+				idle_response_free (idle_resp);
+			}
 
-			if (hadlock)
-				idle_real_start (store);
-
-			if (idle_resp)
-				idle_response_free (idle_resp);
 		}
-
-		g_static_rec_mutex_unlock (store->idle_prefix_lock);
-		g_static_rec_mutex_unlock (store->idle_lock);
-
-		idle_debug ("idle checked in idle_thread, waiting %ds for new check\n", store->idle_sleep);
-
-		for (x=0; x<1000 && store->idle_cont; x++)
-			usleep (store->idle_sleep * 1000);
+		store->idle_prefix = NULL;
 	}
 
-	store->in_idle = FALSE;
-
-	g_thread_exit (NULL);
-	return NULL;
+	return;
 }
 
 
@@ -3922,6 +4041,7 @@
 {
 	CamelImapStore *store;
 	CamelException ex = CAMEL_EXCEPTION_INITIALISER;
+	CamelImapFolder *imap_folder = (CamelImapFolder *) folder;
 
 	idle_debug ("camel_imap_folder_start_idle\n");
 
@@ -3930,6 +4050,9 @@
 	if (!camel_disco_store_check_online ((CamelDiscoStore*)store, &ex))
 		return;
 
+	if (!imap_folder->do_push_email)
+		return;
+
 	g_static_rec_mutex_lock (store->idle_lock);
 
 	if (store->capabilities & IMAP_CAPABILITY_IDLE)
@@ -3939,17 +4062,48 @@
 		{
 			folder->folder_flags |= CAMEL_FOLDER_HAS_PUSHEMAIL_CAPABILITY;
 
-			if (!store->in_idle && store->idle_thread)
-			{
+			if (!store->in_idle && store->idle_thread) {
+				IdleResponse *idle_resp = NULL;
+
 				store->idle_cont = FALSE;
-				g_thread_join (store->idle_thread);
+				idle_resp = g_thread_join (store->idle_thread);
 				store->idle_thread = NULL;
+
+				/* 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);
+				}
+
 			}
 
 			if (!store->in_idle) {
-				idle_real_start (store);
+				IdleThreadInfo *info = g_slice_new0 (IdleThreadInfo);
+				store->idle_kill = FALSE;
+				store->in_idle = TRUE;
+				store->idle_cont = TRUE;
+
+				info->mutex = g_mutex_new ();
+				info->condition = g_cond_new ();
+				info->had_cond = FALSE;
+				info->folder = folder;
+				camel_object_ref (info->folder);
+
 				store->idle_thread = g_thread_create (idle_thread, 
-					folder, TRUE, NULL);
+					info, TRUE, NULL);
+				g_mutex_lock (info->mutex);
+				if (!info->had_cond)
+					g_cond_wait (info->condition, info->mutex);
+				g_mutex_unlock (info->mutex);
+
+				camel_object_unref (info->folder);
+				g_mutex_free (info->mutex);
+				g_cond_free (info->condition);
+				g_slice_free (IdleThreadInfo, info);
+
 			}
 
 		}
@@ -3977,6 +4131,8 @@
 
 	return;
 }
+
+
 /* Called with the store's connect_lock locked */
 void
 camel_imap_folder_changed (CamelFolder *folder, int exists,
@@ -4018,9 +4174,9 @@
 	len = camel_folder_summary_count (folder->summary);
 
 	if (exists > len) {
+		/* TNY Question: is this stop really necessary? Why? */
 		camel_imap_folder_stop_idle (folder);
 		imap_update_summary (folder, exists, changes, ex);
-		/* camel_imap_folder_start_idle (folder); will happen later? */
 	}
 
 	if (camel_folder_change_info_changed (changes))
@@ -4033,7 +4189,7 @@
 
 static void
 camel_imap_folder_changed_for_idle (CamelFolder *folder, int exists,
-			   GArray *expunged, CamelException *ex, CamelFolderChangeInfo *changes)
+			   GArray *expunged, CamelException *ex, CamelFolderChangeInfo *changes, gboolean exists_happened)
 {
 	CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
 	CamelMessageInfo *info;
@@ -4075,7 +4231,7 @@
 	}
 
 	len = camel_folder_summary_count (folder->summary);
-	if (exists > len)
+	if (exists_happened && (exists > len))
 		imap_update_summary (folder, exists, changes, ex);
 	if (camel_folder_change_info_changed (changes))
 		camel_object_trigger_event (CAMEL_OBJECT (folder), "folder_changed", changes);
Index: libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-command.c
===================================================================
--- libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-command.c	(revision 2872)
+++ libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-command.c	(working copy)
@@ -48,6 +48,8 @@
 #include "camel-imap-utils.h"
 #include "camel-imap-summary.h"
 
+#include "camel-string-utils.h"
+
 extern int camel_verbose_debug;
 
 static gboolean imap_command_start (CamelImapStore *store, CamelFolder *folder,
@@ -61,9 +63,7 @@
 static char *imap_command_strdup_printf (CamelImapStore *store,
 					 const char *fmt, ...);
 
-static char * imap_read_untagged_idle (CamelImapStore *store, char *line, CamelException *ex);
 
-
 static int
 uid_compar (const void *va, const void *vb)
 {
@@ -538,9 +538,11 @@
 	CamelImapResponseType type;
 	char *respbuf;
 
-	if (camel_imap_store_readline_idle (store, &respbuf, ex) < 0)
+	if (camel_imap_store_readline_nl (store, &respbuf, ex) < 0)
 		return CAMEL_IMAP_RESPONSE_ERROR;
 
+	imap_debug ("(.., ..) <- %s (IDLE response)\n", respbuf);
+
 	switch (*respbuf) {
 	case '*':
 		if (!g_ascii_strncasecmp (respbuf, "* BYE", 5)) {
@@ -558,7 +560,7 @@
 		
 		/* Read the rest of the response. */
 		type = CAMEL_IMAP_RESPONSE_UNTAGGED;
-		respbuf = imap_read_untagged_idle (store, respbuf, ex);
+		respbuf = imap_read_untagged (store, respbuf, ex);
 		if (!respbuf)
 			type = CAMEL_IMAP_RESPONSE_ERROR;
 		else if (!g_ascii_strncasecmp (respbuf, "* OK [ALERT]", 12)
@@ -580,7 +582,14 @@
 		type = CAMEL_IMAP_RESPONSE_CONTINUATION;
 		break;
 	default:
-		type = CAMEL_IMAP_RESPONSE_TAGGED;
+		if (camel_strstrcase (respbuf, "OK") != NULL || 
+			camel_strstrcase (respbuf, "NO") != NULL ||
+			camel_strstrcase (respbuf, "BAD") != NULL) {
+
+			type = CAMEL_IMAP_RESPONSE_TAGGED;
+
+		} else 
+			type = CAMEL_IMAP_RESPONSE_UNTAGGED;
 		break;
 	}
 	*response = respbuf;
@@ -817,167 +826,6 @@
 }
 
 
-
-static char *
-imap_read_untagged_idle (CamelImapStore *store, char *line, CamelException *ex)
-{
-	int fulllen, ldigits, nread, n, i, sexp = 0;
-	unsigned int length;
-	GPtrArray *data;
-	GString *str;
-	char *end, *p, *s, *d;
-	
-	p = strrchr (line, '{');
-	if (!p)
-		return line;
-	
-	data = g_ptr_array_new ();
-	fulllen = 0;
-	
-	while (1) {
-		str = g_string_new (line);
-		g_free (line);
-		fulllen += str->len;
-		g_ptr_array_add (data, str);
-		
-		if (!(p = strrchr (str->str, '{')) || p[1] == '-')
-			break;
-		
-		/* HACK ALERT: We scan the non-literal part of the string, looking for possible s expression braces.
-		   This assumes we're getting s-expressions, which we should be.
-		   This is so if we get a blank line after a literal, in an s-expression, we can keep going, since
-		   we do no other parsing at this level.
-		   TODO: handle quoted strings? */
-		for (s=str->str; s<p; s++) {
-			if (*s == '(')
-				sexp++;
-			else if (*s == ')')
-				sexp--;
-		}
-		
-		length = strtoul (p + 1, &end, 10);
-		if (*end != '}' || *(end + 1) || end == p + 1 || length >= UINT_MAX - 2)
-			break;
-		ldigits = end - (p + 1);
-		
-		/* Read the literal */
-		str = g_string_sized_new (length + 2);
-		str->str[0] = '\n';
-		nread = 0;
-		
-		do {
-			if ((n = camel_stream_read_idle (store->istream, str->str + nread + 1, length - nread)) == -1) {
-				if (errno == EINTR) {
-					CamelException mex = CAMEL_EXCEPTION_INITIALISER;
-					camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
-							     _("Operation cancelled"));
-					camel_imap_recon (store, &mex);
-					imap_debug ("Recon in untagged idle: %s\n", camel_exception_get_description (&mex));
-				} else {
-					camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
-							     g_strerror (errno));
-					camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL);
-				}
-				g_string_free (str, TRUE);
-				goto lose;
-			}
-			
-			nread += n;
-		} while (n > 0 && nread < length);
-		
-		if (nread < length) {
-			if (errno == EINTR) {
-				CamelException mex = CAMEL_EXCEPTION_INITIALISER;
-				camel_exception_set (ex, CAMEL_EXCEPTION_USER_CANCEL,
-						     _("Operation cancelled"));
-				camel_imap_recon (store, &mex);
-				imap_debug ("Recon in untagged idle: %s\n", camel_exception_get_description (&mex));
-			}  else {
-				camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
-					     _("Server response ended too soon."));
-				camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL);
-			}
-			g_string_free (str, TRUE);
-			goto lose;
-		}
-		str->str[length + 1] = '\0';
-
-		if (camel_debug("imap")) {
-			printf("Literal: -->");
-			fwrite(str->str+1, 1, length, stdout);
-			printf("<--\n");
-		}
-		
-		/* Fix up the literal, turning CRLFs into LF. Also, if
-		 * we find any embedded NULs, strip them. This is
-		 * dubious, but:
-		 *   - The IMAP grammar says you can't have NULs here
-		 *     anyway, so this will not affect our behavior
-		 *     against any completely correct server.
-		 *   - WU-imapd 12.264 (at least) will cheerily pass
-		 *     NULs along if they are embedded in the message
-		 */
-		
-		s = d = str->str + 1;
-		end = str->str + 1 + length;
-		while (s < end) {
-			while (s < end && *s == '\0') {
-				s++;
-				length--;
-			}
-			if (*s == '\r' && *(s + 1) == '\n') {
-				s++;
-				length--;
-			}
-			*d++ = *s++;
-		}
-		*d = '\0';
-		str->len = length + 1;
-		
-		/* p points to the "{" in the line that starts the
-		 * literal. The length of the CR-less response must be
-		 * less than or equal to the length of the response
-		 * with CRs, therefore overwriting the old value with
-		 * the new value cannot cause an overrun. However, we
-		 * don't want it to be shorter either, because then the
-		 * GString's length would be off...
-		 */
-		sprintf (p, "{%0*u}", ldigits, length);
-		
-		fulllen += str->len;
-		g_ptr_array_add (data, str);
-
-		/* Read the next line. */
-		do {
-			if (camel_imap_store_readline_idle (store, &line, ex) < 0)
-				goto lose;
-
-			/* MAJOR HACK ALERT, gropuwise sometimes sends an extra blank line after literals, check that here
-			   But only do it if we're inside an sexpression */
-			if (line[0] == 0 && sexp > 0)
-				g_warning("Server sent empty line after a literal, assuming in error");
-		} while (line[0] == 0 && sexp > 0);
-	}
-	
-	/* Now reassemble the data. */
-	p = line = g_malloc (fulllen + 1);
-	for (i = 0; i < data->len; i++) {
-		str = data->pdata[i];
-		memcpy (p, str->str, str->len);
-		p += str->len;
-		g_string_free (str, TRUE);
-	}
-	*p = '\0';
-	g_ptr_array_free (data, TRUE);
-	return line;
-	
- lose:
-	for (i = 0; i < data->len; i++)
-		g_string_free (data->pdata[i], TRUE);
-	g_ptr_array_free (data, TRUE);
-	return NULL;
-}
-
 /**
  * camel_imap_response_free:
  * @store: the CamelImapStore the response is from
Index: libtinymail-camel/camel-lite/camel/camel-tcp-stream-openssl.c
===================================================================
--- libtinymail-camel/camel-lite/camel/camel-tcp-stream-openssl.c	(revision 2872)
+++ libtinymail-camel/camel-lite/camel/camel-tcp-stream-openssl.c	(working copy)
@@ -61,7 +61,6 @@
 /* Returns the class for a CamelTcpStreamSSL */
 #define CTSR_CLASS(so) CAMEL_TCP_STREAM_SSL_CLASS (CAMEL_OBJECT_GET_CLASS (so))
 
-static ssize_t stream_read_idle (CamelStream *stream, char *buffer, size_t n);
 static ssize_t stream_read_nb (CamelTcpStream *stream, char *buffer, size_t n);
 static ssize_t stream_read (CamelStream *stream, char *buffer, size_t n);
 static ssize_t stream_write (CamelStream *stream, const char *buffer, size_t n);
@@ -100,9 +99,6 @@
 
 
 	parent_class = CAMEL_TCP_STREAM_CLASS (camel_type_get_global_classfuncs (camel_tcp_stream_get_type ()));
-	
-	/* virtual method overload */
-	camel_stream_class->read_idle = stream_read_idle;
 
 	camel_stream_class->read = stream_read;
 	camel_stream_class->write = stream_write;
@@ -290,58 +286,7 @@
 	return 0;
 }
 
-static ssize_t 
-stream_read_idle (CamelStream *stream, char *buffer, size_t n)
-{
-	CamelTcpStreamSSL *openssl = CAMEL_TCP_STREAM_SSL (stream);
-	SSL *ssl = openssl->priv->ssl;
-	ssize_t nread;
 
-	int error, flags, fdmax;
-	struct timeval timeout;
-	fd_set rdset;
-	int res;
-
-	flags = fcntl (openssl->priv->sockfd, F_GETFL);
-	fcntl (openssl->priv->sockfd, F_SETFL, flags | O_NONBLOCK);
-	
-	fdmax = openssl->priv->sockfd + 1;
-	
-	do {
-		FD_ZERO (&rdset);
-		FD_SET (openssl->priv->sockfd, &rdset);
-		nread = -1;
-		timeout.tv_sec = IDLE_READ_TIMEOUT;
-		timeout.tv_usec = 0;
-		res = select (fdmax, &rdset, 0, 0, &timeout);
-		
-		if (res == -1)
-			;
-		else if (res == 0)
-			errno = ETIMEDOUT;
-		else {
-
-		  do {
-			if (ssl) {
-				nread = SSL_read (ssl, buffer, n);
-				if (nread < 0)
-					errno = ssl_errno (ssl, nread);
-			} else {
-				nread = read (openssl->priv->sockfd, buffer, n);
-			}
-		  } while (0 && (nread < 0 && errno == EINTR));
-		}
-	} while (0 && (nread < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)));
-	
-	error = errno;
-	fcntl (openssl->priv->sockfd, F_SETFL, flags);
-	errno = error;
-
-
-	return nread;
-}
-
-
 static ssize_t
 stream_read_nb (CamelTcpStream *stream, char *buffer, size_t n)
 {
Index: libtinymail-camel/camel-lite/camel/camel-file-utils.c
===================================================================
--- libtinymail-camel/camel-lite/camel/camel-file-utils.c	(revision 2872)
+++ libtinymail-camel/camel-lite/camel/camel-file-utils.c	(working copy)
@@ -703,49 +703,6 @@
 }
 
 
-
-ssize_t
-camel_read_idle (int fd, char *buf, size_t n)
-{
-	ssize_t nread;
-
-	int errnosav, flags, fdmax;
-	fd_set rdset;
-	
-	flags = fcntl (fd, F_GETFL);
-	fcntl (fd, F_SETFL, flags | O_NONBLOCK);
-	
-	do {
-		struct timeval tv;
-		int res;
-
-		FD_ZERO (&rdset);
-		FD_SET (fd, &rdset);
-		fdmax = fd + 1;
-		tv.tv_sec = IDLE_READ_TIMEOUT;
-		tv.tv_usec = 0;
-		nread = -1;
-
-		res = select(fdmax, &rdset, 0, 0, &tv);
-		if (res == -1)
-			;
-		else if (res == 0)
-			errno = ETIMEDOUT;
-		else {
-			do {
-				nread = read (fd, buf, n);
-			} while (0 && (nread == -1 && errno == EINTR));
-		}
-	} while (0 && (nread == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)));
-
-	errnosav = errno;
-	fcntl (fd, F_SETFL, flags);
-	errno = errnosav;
-
-	return nread;
-}
-
-
 /**
  * camel_read_socket:
  * @fd: a socket
@@ -842,86 +799,6 @@
 
 
 ssize_t
-camel_read_socket_idle (int fd, char *buf, size_t n)
-{
-#ifndef G_OS_WIN32
-	return camel_read_idle (fd, buf, n);
-#else
-	ssize_t nread;
-	int cancel_fd;
-	
-	if (camel_operation_cancel_check (NULL)) {
-		errno = EINTR;
-		return -1;
-	}
-	cancel_fd = camel_operation_cancel_fd (NULL);
-
-	if (cancel_fd == -1) {
-
-		int fdmax;
-		fd_set rdset;
-		u_long yes = 1;
-
-		ioctlsocket (fd, FIONBIO, &yes);
-		fdmax = fd + 1;
-		do {
-			struct timeval tv;
-			int res;
-
-			FD_ZERO (&rdset);
-			FD_SET (fd, &rdset);
-			tv.tv_sec = IDLE_READ_TIMEOUT;
-			tv.tv_usec = 0;
-			nread = -1;
-
-			res = select(fdmax, &rdset, 0, 0, &tv);
-			if (res == -1)
-				;
-			else if (res == 0)
-				errno = ETIMEDOUT;
-			} else {				
-				nread = recv (fd, buf, n, 0);
-			}
-		} while ((nread == -1 && WSAGetLastError () == WSAEWOULDBLOCK));
-
-	} else {
-		int fdmax;
-		fd_set rdset;
-		u_long yes = 1;
-
-		ioctlsocket (fd, FIONBIO, &yes);
-		fdmax = MAX (fd, cancel_fd) + 1;
-		do {
-			struct timeval tv;
-			int res;
-
-			FD_ZERO (&rdset);
-			FD_SET (fd, &rdset);
-			FD_SET (cancel_fd, &rdset);
-			tv.tv_sec = IDLE_READ_TIMEOUT;
-			tv.tv_usec = 0;
-			nread = -1;
-
-			res = select(fdmax, &rdset, 0, 0, &tv);
-			if (res == -1)
-				;
-			else if (res == 0)
-				errno = ETIMEDOUT;
-			else if (FD_ISSET (cancel_fd, &rdset)) {
-				errno = EINTR;
-				goto failed;
-			} else {				
-				nread = recv (fd, buf, n, 0);
-			}
-		} while ((nread == -1 && WSAGetLastError () == WSAEWOULDBLOCK));
-	failed:
-		;
-	}
-	
-	return nread;
-#endif
-}
-ssize_t
 camel_read_socket_nb (int fd, char *buf, size_t n)
 {
 #ifndef G_OS_WIN32
Index: libtinymail-camel/camel-lite/camel/camel-file-utils.h
===================================================================
--- libtinymail-camel/camel-lite/camel/camel-file-utils.h	(revision 2872)
+++ libtinymail-camel/camel-lite/camel/camel-file-utils.h	(working copy)
@@ -88,7 +88,6 @@
 ssize_t camel_read (int fd, char *buf, size_t n);
 ssize_t camel_write (int fd, const char *buf, size_t n);
 
-ssize_t camel_read_socket_idle (int fd, char *buf, size_t n);
 ssize_t camel_write_socket (int fd, const char *buf, size_t n);
 
 ssize_t camel_read_socket (int fd, char *buf, size_t n);
Index: libtinymail-camel/camel-lite/camel/camel-tcp-stream-raw.c
===================================================================
--- libtinymail-camel/camel-lite/camel/camel-tcp-stream-raw.c	(revision 2872)
+++ libtinymail-camel/camel-lite/camel/camel-tcp-stream-raw.c	(working copy)
@@ -65,7 +65,6 @@
 static struct sockaddr *stream_get_local_address (CamelTcpStream *stream, socklen_t *len);
 static struct sockaddr *stream_get_remote_address (CamelTcpStream *stream, socklen_t *len);
 static ssize_t stream_read_nb (CamelTcpStream *stream, char *buffer, size_t n);
-static ssize_t stream_read_idle (CamelStream *stream, char *buffer, size_t n);
 
 
 static void
@@ -79,7 +78,6 @@
 	parent_class = CAMEL_TCP_STREAM_CLASS (camel_type_get_global_classfuncs (camel_tcp_stream_get_type ()));
 
 	/* virtual method overload */
-	camel_stream_class->read_idle = stream_read_idle;
 	camel_stream_class->read = stream_read;
 	camel_stream_class->write = stream_write;
 	camel_stream_class->flush = stream_flush;
@@ -258,15 +256,6 @@
 	return camel_read_socket (raw->sockfd, buffer, n);
 }
 
-
-static ssize_t 
-stream_read_idle (CamelStream *stream, char *buffer, size_t n)
-{
-	CamelTcpStreamRaw *raw = CAMEL_TCP_STREAM_RAW (stream);
-	
-	return camel_read_socket_idle (raw->sockfd, buffer, n);
-}
-
 static ssize_t
 stream_read_nb (CamelTcpStream *stream, char *buffer, size_t n)
 {
Index: libtinymail-camel/camel-lite/camel/camel-stream-buffer.c
===================================================================
--- libtinymail-camel/camel-lite/camel/camel-stream-buffer.c	(revision 2872)
+++ libtinymail-camel/camel-lite/camel/camel-stream-buffer.c	(working copy)
@@ -429,51 +429,7 @@
 }
 
 
-
 int
-camel_stream_buffer_gets_idle (CamelStreamBuffer *sbf, char *buf, unsigned int max)
-{
-	register char *outptr, *inptr, *inend, c, *outend;
-	int bytes_read;
-
-	outptr = buf;
-	inptr = (char*)sbf->ptr;
-	inend = (char*)sbf->end;
-	outend = buf+max-1;	/* room for NUL */
-
-	do {
-		while (inptr<inend && outptr<outend) {
-			c = *inptr++;
-			*outptr++ = c;
-			if (c == '\n') {
-				*outptr = 0;
-				sbf->ptr = (unsigned char*) inptr;
-				return outptr-buf;
-			}
-		}
-		if (outptr == outend)
-			break;
-
-		bytes_read = camel_stream_read_idle (sbf->stream, (char*)sbf->buf, sbf->size);
-		if (bytes_read == -1) {
-			if (buf == outptr)
-				return -1;
-			else
-				bytes_read = 0;
-		}
-		sbf->ptr = sbf->buf;
-		sbf->end = sbf->buf + bytes_read;
-		inptr = (char*)sbf->ptr;
-		inend = (char*)sbf->end;
-	} while (bytes_read>0);
-
-	sbf->ptr = (unsigned char*)inptr;
-	*outptr = 0;
-
-	return (int)(outptr - buf);
-}
-
-int
 camel_tcp_stream_buffer_gets_nb (CamelStreamBuffer *sbf, char *buf, unsigned int max)
 {
 	register char *outptr, *inptr, *inend, c, *outend;
Index: libtinymail-camel/camel-lite/camel/camel-stream-buffer.h
===================================================================
--- libtinymail-camel/camel-lite/camel/camel-stream-buffer.h	(revision 2872)
+++ libtinymail-camel/camel-lite/camel/camel-stream-buffer.h	(working copy)
@@ -95,7 +95,6 @@
 
 char *camel_stream_buffer_read_line (CamelStreamBuffer *sbf);
 int camel_tcp_stream_buffer_gets_nb (CamelStreamBuffer *sbf, char *buf, unsigned int max);
-int camel_stream_buffer_gets_idle (CamelStreamBuffer *sbf, char *buf, unsigned int max);
 
 
 G_END_DECLS
Index: libtinymail-camel/camel-lite/camel/camel-tcp-stream-ssl.c
===================================================================
--- libtinymail-camel/camel-lite/camel/camel-tcp-stream-ssl.c	(revision 2872)
+++ libtinymail-camel/camel-lite/camel/camel-tcp-stream-ssl.c	(working copy)
@@ -84,7 +84,6 @@
 static struct sockaddr *stream_get_local_address (CamelTcpStream *stream, socklen_t *len);
 static struct sockaddr *stream_get_remote_address (CamelTcpStream *stream, socklen_t *len);
 static ssize_t stream_read_nb (CamelTcpStream *stream, char *buffer, size_t n);
-static ssize_t stream_read_idle (CamelStream *stream, char *buffer, size_t n);
 
 struct _CamelTcpStreamSSLPrivate {
 	PRFileDesc *sockfd;
@@ -106,9 +105,6 @@
 		CAMEL_STREAM_CLASS (camel_tcp_stream_ssl_class);
 	
 	parent_class = CAMEL_TCP_STREAM_CLASS (camel_type_get_global_classfuncs (camel_tcp_stream_get_type ()));
-	
-	/* virtual method overload */
-	camel_stream_class->read_idle = stream_read_idle;
 
 	camel_stream_class->read = stream_read;
 	camel_stream_class->write = stream_write;
@@ -546,136 +542,6 @@
 }
 
 
-
-static ssize_t 
-stream_read_idle (CamelStream *stream, char *buffer, size_t n)
-{
-	CamelTcpStreamSSL *tcp_stream_ssl = CAMEL_TCP_STREAM_SSL (stream);
-	PRFileDesc *cancel_fd;
-	ssize_t nread;
-	
-	if (camel_operation_cancel_check (NULL)) {
-		errno = EINTR;
-		return -1;
-	}
-	
-	cancel_fd = camel_operation_cancel_prfd (NULL);
-	if (cancel_fd == NULL) {
-
-		PRSocketOptionData sockopts;
-		PRPollDesc pollfds[1];
-		gboolean nonblock;
-		int error;
-		
-		/* get O_NONBLOCK options */
-		sockopts.option = PR_SockOpt_Nonblocking;
-		PR_GetSocketOption (tcp_stream_ssl->priv->sockfd, &sockopts);
-		sockopts.option = PR_SockOpt_Nonblocking;
-		nonblock = sockopts.value.non_blocking;
-		sockopts.value.non_blocking = TRUE;
-		PR_SetSocketOption (tcp_stream_ssl->priv->sockfd, &sockopts);
-
-		pollfds[0].fd = tcp_stream_ssl->priv->sockfd;
-		pollfds[0].in_flags = PR_POLL_READ;
-
-		do {
-			PRInt32 res;
-
-			pollfds[0].out_flags = 0;
-			nread = -1;
-
-			res = PR_Poll(pollfds, 1, PR_TicksPerSecond () * IDLE_READ_TIMEOUT);
-
-			if (res == -1)
-				set_errno(PR_GetError());
-			else if (res == 0) {
-#ifdef ETIMEDOUT
-				errno = ETIMEDOUT;
-#else
-				errno = EIO;
-#endif
-			} else {
-				do {
-					nread = PR_Read (tcp_stream_ssl->priv->sockfd, buffer, n);
-					if (nread == -1)
-						set_errno (PR_GetError ());
-				} while (nread == -1 && PR_GetError () == PR_PENDING_INTERRUPT_ERROR);
-			}
-		} while (nread == -1 && (PR_GetError () == PR_PENDING_INTERRUPT_ERROR ||
-					 PR_GetError () == PR_IO_PENDING_ERROR ||
-					 PR_GetError () == PR_WOULD_BLOCK_ERROR));
-		
-		/* restore O_NONBLOCK options */
-		error = errno;
-		sockopts.option = PR_SockOpt_Nonblocking;
-		sockopts.value.non_blocking = nonblock;
-		PR_SetSocketOption (tcp_stream_ssl->priv->sockfd, &sockopts);
-		errno = error;
-
-
-	} else {
-		PRSocketOptionData sockopts;
-		PRPollDesc pollfds[2];
-		gboolean nonblock;
-		int error;
-		
-		/* get O_NONBLOCK options */
-		sockopts.option = PR_SockOpt_Nonblocking;
-		PR_GetSocketOption (tcp_stream_ssl->priv->sockfd, &sockopts);
-		sockopts.option = PR_SockOpt_Nonblocking;
-		nonblock = sockopts.value.non_blocking;
-		sockopts.value.non_blocking = TRUE;
-		PR_SetSocketOption (tcp_stream_ssl->priv->sockfd, &sockopts);
-
-		pollfds[0].fd = tcp_stream_ssl->priv->sockfd;
-		pollfds[0].in_flags = PR_POLL_READ;
-		pollfds[1].fd = cancel_fd;
-		pollfds[1].in_flags = PR_POLL_READ;
-		
-		do {
-			PRInt32 res;
-
-			pollfds[0].out_flags = 0;
-			pollfds[1].out_flags = 0;
-			nread = -1;
-
-			res = PR_Poll(pollfds, 2, PR_TicksPerSecond () * IDLE_READ_TIMEOUT);
-
-			if (res == -1)
-				set_errno(PR_GetError());
-			else if (res == 0) {
-#ifdef ETIMEDOUT
-				errno = ETIMEDOUT;
-#else
-				errno = EIO;
-#endif
-			} else if (pollfds[1].out_flags == PR_POLL_READ) {
-				errno = EINTR;
-				goto failed;
-			} else {
-				do {
-					nread = PR_Read (tcp_stream_ssl->priv->sockfd, buffer, n);
-					if (nread == -1)
-						set_errno (PR_GetError ());
-				} while (nread == -1 && PR_GetError () == PR_PENDING_INTERRUPT_ERROR);
-			}
-		} while (nread == -1 && (PR_GetError () == PR_PENDING_INTERRUPT_ERROR ||
-					 PR_GetError () == PR_IO_PENDING_ERROR ||
-					 PR_GetError () == PR_WOULD_BLOCK_ERROR));
-		
-		/* restore O_NONBLOCK options */
-	failed:
-		error = errno;
-		sockopts.option = PR_SockOpt_Nonblocking;
-		sockopts.value.non_blocking = nonblock;
-		PR_SetSocketOption (tcp_stream_ssl->priv->sockfd, &sockopts);
-		errno = error;
-	}
-	
-	return nread;
-}
-
-
 static ssize_t
 stream_write (CamelStream *stream, const char *buffer, size_t n)
 {
Index: tests/c-demo/tny-demoui-summary-view.c
===================================================================
--- tests/c-demo/tny-demoui-summary-view.c	(revision 2872)
+++ tests/c-demo/tny-demoui-summary-view.c	(working copy)
@@ -940,11 +940,15 @@
 
 			set_header_view_model (header_view, sortable);
 
+#ifndef NONASYNC_TEST
 			tny_folder_refresh_async (folder, 
 				refresh_current_folder, 
 				status_update, self);
-
-			g_object_unref (G_OBJECT (folder));
+#else
+			tny_folder_refresh (folder, NULL);
+			refresh_current_folder (folder, FALSE, NULL, self);
+#endif
+			g_object_unref (folder);
 		}
 	  }
 	} else {
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 2874)
+++ ChangeLog	(working copy)
@@ -3,6 +3,12 @@
 	* Reference count problem in TnyCamelHeader
 	* priv->folder_name in TnyCamelFolder sometimes is NULL, which doesn't
 	seem right (and is racy).
+	* Improvements for the IDLE support. The Nonblocking read is now
+	actually used correctly, various racy situations should be fixed now
+	and instant event throwing is put in place (during IDLE state).
+	* Removed the (*read_idle) funcptr from CamelTcpStream, as this is no longer
+	required. This to reduce the complexity of the IDLE patch so that we
+	can later, perhaps, more easily bring this feature to upstream Camel.
 
 2007-10-19  Philip Van Hoof  <pvanhoof gnome org>
 


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