Re: [Evolution-hackers] Let the porting begin



On Wed, 2007-10-24 at 11:58 -0400, Jeffrey Stedfast wrote:
> I took a look at the IDLE implementation last night and felt it went
> about it the wrong way.

Yes, you are right. I think the right fix is to create a new API called
camel_tcp_stream_wait that works like this:


int bytes = camel_tcp_stream_wait (tcp_stream, stop_fd,
	 store->idle_sleep, line_buffer, 1023);

I need the amount of read-read bytes, to know where the buffer stops, so
I return it. I need a stop_fd to get the select() to early-stop. I need
a timeout for in case of connection problems. I need the buffer to put
the newly read data in and I need a size to tell it how large my buffer
max is.


.. idle_thread () ..
{

  start_idle (store);
  line_buffer = malloc (1024)
  memset (line_buffer, 0, sizeof (*line_buffer));
  ...

  while (store->idle_cont)  {
	char *lasts = NULL;
	int bytes = camel_tcp_stream_wait (tcp_stream, stop_fd, store->idle_sleep, line_buffer, 1023);

	if (bytes > 0) {
		char *resp;
		line_buffer[bytes+1] = '\0';

		for (resp = strtok_r (line_buffer, "\n", &lasts); resp; resp = strtok_r (NULL, "\n", &lasts)) {
			if (resp && strlen (resp) > 1 && resp[0] == '*') {
				if (!idle_resp)
					idle_resp = idle_response_new (folder);
				consume_idle_line (store, folder, resp, idle_resp);
				lines++;
			}
		}
		printf ("IDLE: read %d bytes %s\n", bytes, line_buffer);
	}

	if (!store->idle_cont || (idle_resp && idle_resp->exists_happened)) {
		idle_done (store, folder, idle_resp);
		stopped = TRUE;
		if (!store->idle_cont)
			retval = idle_resp;
	} 

	if (store->idle_cont) {
		if (idle_resp) {
			process_idle_response (idle_resp);
			idle_response_free (idle_resp);
			idle_resp = NULL;
			printf ("Processed %d lines\n", lines);
			lines = 0;
		}
		if (stopped)
			idle_start (store);
	}
	memset (line_buffer, 0, sizeof (*line_buffer));
  }
}

That "wait" is implemented like this:


static ssize_t
stream_wait (CamelTcpStream *stream, int stop_fd, int timeout, char *buffer, size_t max_len)
{
	CamelTcpStreamRaw *raw = CAMEL_TCP_STREAM_RAW (stream);
	int fd = raw->sockfd;
	ssize_t nread;
	int fdmax;
	fd_set rdset;
	u_long yes = 1;
	struct timeval tv;
	int res;

	//ioctlsocket (fd, FIONBIO, &yes);
	fdmax = MAX (fd, stop_fd) + 1;

	FD_ZERO (&rdset);
	FD_SET (fd, &rdset);
	FD_SET (stop_fd, &rdset);

	tv.tv_sec = timeout;
	tv.tv_usec = 0;
	nread = -1;

	res = select (fdmax, &rdset, 0, 0, &tv);
	if (res > 0 && !FD_ISSET (stop_fd, &rdset))
		nread = recv (fd, buffer, max_len, 0);
	else
		nread = -1;

	return nread;
}


Afaics It's not true that you don't need to change any API:

The camel_stream_read() will block until all n bytes are read. This is
something you don't know during IDLE (how many bytes you can expect to
receive), and on top of that you want to continue immediately after
select returns, not keep retrying until you have n bytes (to simulate a
blocking read). You also want a dedicated stop fildescriptor, not the
standard cancel_fd as then any cancel will interfere with this (while
you want strict control over this to let other threads start and stop
IDLE).

Well ... let me put it this way: I tried it from a few angles, I didn't
succeed with the normal camel_stream_read :-(

I have reworked the IDLE implementation. You can apply this patch to
Tinymail's upstream (trunk). You most likely can't apply it to upstream
Camel. (http://svn.tinymail.org/svn/tinymail/trunk)

There's still one problem: sometimes camel_imap_folder_stop_idle is not
returning late enough (the socket is still in IDLE state when it
returns).

Other than that, it usually works.

I'm trying to fix this last problem right now, and after that there will
most likely be a few days of testing before I put this in Tinymail's
repository.


> You should simply poll() on the socket descriptors (and a pipe fd used
> for telling the IDLE thread's I/O loop to finish and send DONE).

Yep


> Jeff
> 
> On Mon, 2007-10-08 at 00:41 +0200, Philip Van Hoof wrote:
> > On Sun, 2007-10-07 at 14:15 +0200, Philip Van Hoof wrote:
> > > Hi there,
> > 
> > > Using this changeset you can follow the changes to camel-lite:
> > > 
> > > 	http://tinymail.org/trac/tinymail/changeset/2823
> > > 
> > 
> > This changeset are a bunch of compilation warnings for Matthew's Base64
> > patch to Camel: http://tinymail.org/trac/tinymail/changeset/2827
> > 
> > 
> > ps. Adding Matthew in CC.
> > 
> 
-- 
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/providers/imap/camel-imap-store.c
===================================================================
--- libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-store.c	(revision 2884)
+++ libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-store.c	(working copy)
@@ -197,44 +197,29 @@
 static void 
 let_idle_die (CamelImapStore *store, gboolean connect_buz)
 {
-
 	idle_debug ("let_idle_die starts\n");
-
-	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->idle_prefix)
+	if (store->in_idle && store->idle_thread) 
 	{
-		gchar *resp = NULL;
-		int nwritten = 0;
-		CamelException ex = CAMEL_EXCEPTION_INITIALISER;
+		IdleResponse *idle_resp;
+		store->idle_cont = FALSE;
+		if (store->current_idle)
+			camel_operation_cancel (store->current_idle);
+		idle_resp = g_thread_join (store->idle_thread);
+		if (store->current_idle)
+			camel_operation_uncancel (store->current_idle);
 
-		idle_debug ("Sending DONE in let_idle_die\n");
-		CAMEL_SERVICE_REC_LOCK (store, connect_lock);
-		nwritten = camel_stream_printf (store->ostream, "DONE\r\n");
+		g_static_rec_mutex_lock (store->idle_prefix_lock);
+		g_static_rec_mutex_lock (store->idle_lock);
 		store->in_idle = FALSE;
-		if (nwritten != -1) {
-			resp = NULL;
-			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) {
-				idle_debug ("(.., ..) <- %s\n", resp);
-				g_free (resp);
-			}
-		}
-		CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
-		g_free (store->idle_prefix); 
-		store->idle_prefix=NULL;
+		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);
+		if (idle_resp)
+			idle_response_free (idle_resp);
 	}
-
-	g_static_rec_mutex_unlock (store->idle_lock);
-	g_static_rec_mutex_unlock (store->idle_prefix_lock);
-
+	store->idle_prefix = NULL;
 	idle_debug ("let_idle_die finished\n");
 
 	return;
@@ -245,41 +230,8 @@
 {
 	if (store->current_folder && CAMEL_IS_IMAP_FOLDER (store->current_folder))
 		camel_imap_folder_stop_idle (store->current_folder);
-	else {
-		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->idle_prefix) {
-			gchar *resp = NULL;
-			int nwritten = 0;
-			CamelException ex = CAMEL_EXCEPTION_INITIALISER;
-
-			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");
-			store->in_idle = FALSE;
-			if (nwritten != -1) {
-				resp = NULL;
-				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) {
-					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 (store->idle_lock);
-		g_static_rec_mutex_unlock (store->idle_prefix_lock);
-	}
+	else
+		let_idle_die (store, FALSE);
 }
 
 
@@ -415,6 +367,9 @@
 	g_free (imap_store->sum_lock);
 	imap_store->sum_lock = NULL;
 
+	if (imap_store->current_idle)
+		camel_operation_unref (imap_store->current_idle);
+
 }
 
 static void
@@ -422,6 +377,7 @@
 {
 	CamelImapStore *imap_store = CAMEL_IMAP_STORE (object);
 
+	imap_store->current_idle = NULL;
 	imap_store->got_online = FALSE;
 	imap_store->going_online = FALSE;
 	imap_store->courier_crap = FALSE;
@@ -4078,191 +4034,3 @@
 	return nread;
 }
 
-
-
-/* FIXME: please god, when will the hurting stop? Thus function is so
-   fucking broken it's not even funny. */
-ssize_t
-camel_imap_store_readline_idle (CamelImapStore *store, char **dest, CamelException *ex)
-{
-	CamelStreamBuffer *stream;
-	char linebuf[1024] = {0};
-	GByteArray *ba;
-	ssize_t nread;
-	
-	g_return_val_if_fail (CAMEL_IS_IMAP_STORE (store), -1);
-	g_return_val_if_fail (dest, -1);
-	
-	*dest = NULL;
-	
-	/* Check for connectedness. Failed (or cancelled) operations will
-	 * close the connection. We can't expect a read to have any
-	 * meaning if we reconnect, so always set an exception.
-	 */
-
-	if (!camel_disco_store_check_online((CamelDiscoStore *)store, ex))
-		return -1;
-
-	camel_imap_store_restore_stream_buffer (store);
-	stream = CAMEL_STREAM_BUFFER (store->istream);
-
-	ba = g_byte_array_new ();
-	while ((nread = camel_stream_buffer_gets_idle (stream, linebuf, sizeof (linebuf))) > 0) {
-		g_byte_array_append (ba, (const guchar*) linebuf, nread);
-		if (linebuf[nread - 1] == '\n')
-			break;
-	}
-
-	if (nread <= 0) {
-		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 idle: %s\n", camel_exception_get_description (&mex));
-		} else {
-			camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
-					      _("Server unexpectedly disconnected: %s"),
-					      g_strerror (errno));
-			camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL);
-		}
-
-		g_byte_array_free (ba, TRUE);
-		return -1;
-	}
-	
-	if (camel_verbose_debug) {
-		fprintf (stderr, "received: ");
-		fwrite (ba->data, 1, ba->len, stderr);
-	}
-	
-	/* camel-imap-command.c:imap_read_untagged expects the CRLFs
-           to be stripped off and be nul-terminated *sigh* */
-	nread = ba->len - 1;
-	ba->data[nread] = '\0';
-	if (ba->data[nread - 1] == '\r') {
-		ba->data[nread - 1] = '\0';
-		nread--;
-	}
-	
-	*dest = (char *) ba->data;
-	g_byte_array_free (ba, FALSE);
-	
-	return nread;
-}
-
-ssize_t
-camel_imap_store_readline_nl (CamelImapStore *store, char **dest, CamelException *ex)
-{
-	CamelStreamBuffer *stream;
-	char linebuf[1024] = {0};
-	GByteArray *ba;
-	ssize_t nread;
-	
-	g_return_val_if_fail (CAMEL_IS_IMAP_STORE (store), -1);
-	g_return_val_if_fail (dest, -1);
-	
-	*dest = NULL;
-	
-	/* Check for connectedness. Failed (or cancelled) operations will
-	 * close the connection. We can't expect a read to have any
-	 * meaning if we reconnect, so always set an exception.
-	 */
-
-	if (!camel_disco_store_check_online((CamelDiscoStore *)store, ex))
-		return -1;
-
-	camel_imap_store_restore_stream_buffer (store);
-
-	if (!store->istream)
-		return -1;
-
-	stream = CAMEL_STREAM_BUFFER (store->istream);
-
-	ba = g_byte_array_new ();
-	while ((nread = camel_stream_buffer_gets (stream, linebuf, sizeof (linebuf))) > 0) {
-		g_byte_array_append (ba, (const guchar*) linebuf, nread);
-		if (linebuf[nread - 1] == '\n')
-			break;
-	}
-
-	if (nread <= 0) {
-		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 nl: %s\n", camel_exception_get_description (&mex));
-		} else {
-			camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
-					      _("Server unexpectedly disconnected: %s"),
-					      g_strerror (errno));
-			camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL);
-		}
-
-		g_byte_array_free (ba, TRUE);
-		return -1;
-	}
-	
-	if (camel_verbose_debug) {
-		fprintf (stderr, "received: ");
-		fwrite (ba->data, 1, ba->len, stderr);
-	}
-	
-	/* camel-imap-command.c:imap_read_untagged expects the CRLFs
-           to be stripped off and be nul-terminated *sigh* */
-	nread = ba->len - 1;
-	ba->data[nread] = '\0';
-	if (ba->data[nread - 1] == '\r') {
-		ba->data[nread - 1] = '\0';
-		nread--;
-	}
-	
-	*dest = (char *) ba->data;
-	g_byte_array_free (ba, FALSE);
-	
-	return nread;
-}
-
-ssize_t
-camel_imap_store_readline_nb (CamelImapStore *store, char **dest, CamelException *ex)
-{
-	CamelStreamBuffer *stream;
-	char linebuf[1024] = {0};
-	GByteArray *ba;
-	ssize_t nread;
-	
-	g_return_val_if_fail (CAMEL_IS_IMAP_STORE (store), -1);
-	g_return_val_if_fail (dest, -1);
-
-	*dest = NULL;
-
-	if (store->istream == NULL || ((CamelObject *)store->istream)->ref_count <= 0)
-		return -1;
-
-	stream = CAMEL_STREAM_BUFFER (store->istream);
-	ba = g_byte_array_new ();
-	while ((nread = camel_tcp_stream_buffer_gets_nb (stream, linebuf, sizeof (linebuf))) > 0) 
-	{
-		g_byte_array_append (ba, (const guchar*) linebuf, nread);
-		if (linebuf[nread - 1] == '\n')
-			break;
-	}
-
-	if (nread <= 0) {
-		g_byte_array_free (ba, TRUE);
-		return -1;
-	}
-
-	nread = ba->len - 1;
-	ba->data[nread] = '\0';
-	if (ba->data[nread - 1] == '\r') {
-		ba->data[nread - 1] = '\0';
-		nread--;
-	}
-	
-	*dest = (char *) ba->data;
-	g_byte_array_free (ba, FALSE);
-	
-	return nread;
-}
Index: libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-store.h
===================================================================
--- libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-store.h	(revision 2882)
+++ libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-store.h	(working copy)
@@ -52,6 +52,18 @@
 
 G_BEGIN_DECLS
 
+typedef struct {
+	guint32 exists;
+	guint32 recent;
+	GArray *expunged;
+	GList *vanished;
+	GPtrArray *fetch;
+	gboolean exists_happened;
+	CamelFolder *folder;
+} IdleResponse;
+
+void idle_response_free (IdleResponse *idle_resp);
+
 typedef struct _CamelImapMsg CamelImapMsg;
 
 struct _CamelImapMsg {
@@ -151,7 +163,8 @@
 	char tag_prefix;
 	guint32 command;
 	CamelFolder *current_folder, *last_folder, *old_folder;
-	
+	CamelOperation *current_idle;
+
 	/* Information about the server */
 	CamelImapServerLevel server_level;
 	guint32 capabilities, parameters;
@@ -185,10 +198,7 @@
 
 gboolean camel_imap_store_connected (CamelImapStore *store, CamelException *ex);
 
-ssize_t camel_imap_store_readline_nl (CamelImapStore *store, char **dest, CamelException *ex);
-ssize_t camel_imap_store_readline_nb (CamelImapStore *store, char **dest, CamelException *ex);
 ssize_t camel_imap_store_readline (CamelImapStore *store, char **dest, CamelException *ex);
-ssize_t camel_imap_store_readline_idle (CamelImapStore *store, char **dest, CamelException *ex);
 
 gboolean camel_imap_store_restore_stream_buffer (CamelImapStore *store);
 
Index: libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-folder.c
===================================================================
--- libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-folder.c	(revision 2884)
+++ libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-folder.c	(working copy)
@@ -3456,15 +3456,6 @@
 	guint32 flags;
 } FetchIdleResponse;
 
-typedef struct {
-	guint32 exists;
-	guint32 recent;
-	GArray *expunged;
-	GList *vanished;
-	GPtrArray *fetch;
-	gboolean exists_happened;
-	CamelFolder *folder;
-} IdleResponse;
 
 static void 
 process_idle_response (IdleResponse *idle_resp)
@@ -3600,7 +3591,7 @@
 	return idle_resp;
 }
 
-static void
+void
 idle_response_free (IdleResponse *idle_resp)
 {
 	idle_debug ("idle_response_free\n");
@@ -3624,41 +3615,30 @@
 
 
 static void
-idle_real_start (CamelImapStore *store)
+idle_start (CamelImapStore *store)
 {
 	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++);
-		nwritten = camel_stream_printf (store->ostream, "%s IDLE\r\n",
+	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++);
+
+	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;
-	}
 
-	/* The IDLE command is sent from the client to the server when the
-	 *  client is ready to accept unsolicited mailbox update messages.  The
-	 *  server requests a response to the IDLE command using the continuation
-	 * ("+") response.  The IDLE command remains active until the client
-	 * responds to the continuation, and as long as an IDLE command is
-	 * active, the server is now free to send untagged EXISTS, EXPUNGE, and
-	 *  other messages at any time. */
+	idle_debug ("(%d, %d) -> %s IDLE\n", strlen (store->idle_prefix)+5, 
+		nwritten, store->idle_prefix);
 
-	/* 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? */
+	/* According to the RFC, we will wait for the server for its + 
+	 * continuation. */
 
 	resp = NULL;
-	while (camel_imap_store_readline_nl (store, &resp, &ex) > 0)
+	while (camel_imap_store_readline (store, &resp, &ex) > 0)
 	{
 		gboolean tbreak = FALSE;
 		if (!strncmp (resp, "+ ", 2))
@@ -3667,16 +3647,18 @@
 			tbreak = TRUE;
 		if (camel_strstrcase (resp, "BAD") != NULL)
 			tbreak = TRUE;
-		idle_debug ("(.., ..) <- %s | in idle_real_start\n", resp);
-		g_free (resp); resp=NULL;
+		idle_debug ("(.., ..) <- %s\n", resp);
+		g_free (resp); 
+		resp=NULL;
 		if (tbreak)
 			break;
 	}
 	if (resp)
 		g_free (resp);
-errh:
+
 	if (l)
 		CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+
 	return;
 }
 
@@ -3697,6 +3679,52 @@
 	return;
 }
 
+static void
+idle_done (CamelImapStore *store, CamelFolder *folder, IdleResponse *idle_resp)
+{
+	char *resp;
+	CamelException ex = CAMEL_EXCEPTION_INITIALISER;
+	gboolean l = CAMEL_SERVICE_REC_TRYLOCK (store, connect_lock);
+	int nwritten = 0;
+
+	nwritten = camel_stream_printf (store->ostream, "DONE\r\n",
+		store->idle_prefix);
+	idle_debug ("(%d, %d) -> DONE\n", nwritten);
+
+	resp = NULL;
+	while (camel_imap_store_readline (store, &resp, &ex) > 0)
+	{
+		gboolean tbreak = FALSE;
+
+		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 (camel_strstrcase (resp, "OK") != NULL)
+			tbreak = TRUE;
+		if (camel_strstrcase (resp, "NO") != NULL)
+			tbreak = TRUE;
+		if (camel_strstrcase (resp, "BAD") != NULL)
+			tbreak = TRUE;
+
+		idle_debug ("(.., ..) <- %s\n", resp);
+		g_free (resp); 
+		resp=NULL;
+
+		if (tbreak)
+			break;
+	}
+	if (resp)
+		g_free (resp);
+
+	if (l)
+		CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+
+	return;
+}
+
 typedef struct {
 	CamelFolder *folder;
 	GCond *condition;
@@ -3715,6 +3743,12 @@
 	int cnt = 0;
 	int nwritten=0;
 	gpointer retval = NULL;
+	gchar line_buffer [1024];
+	CamelTcpStream *tcp_stream;
+	IdleResponse *idle_resp = NULL;
+	gboolean stopped = FALSE;
+	int lines = 0;
+	int stop_fd;
 
 	idle_debug ("idle_thread starts\n");
 
@@ -3776,201 +3810,70 @@
 		idle_debug ("idle_thread starting but immediately stopping\n");
 	}
 
+	idle_start (store);
+
+	if (!info->had_cond && info->condition) {
+		g_mutex_lock (info->mutex);
+		g_cond_broadcast (info->condition);
+		info->had_cond = TRUE;
+		had_cond = TRUE;
+		g_mutex_unlock (info->mutex);
+	}
+
 	/* 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) 
-	{
-		CamelException ex = CAMEL_EXCEPTION_INITIALISER;
-		char *resp = NULL;
-		IdleResponse *idle_resp = NULL;
-		gboolean senddone = FALSE;
+	tcp_stream = (CamelTcpStream *) store->ostream;
+	stop_fd = camel_operation_cancel_fd (store->current_idle);
 
-		/* 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. */
+	memset (line_buffer, 0, sizeof (*line_buffer));
 
-		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;
-		}
+	while (store->idle_cont) 
+	{
+		char *lasts = NULL;
+		int bytes = camel_tcp_stream_wait (tcp_stream, stop_fd, store->idle_sleep, line_buffer, 1023);
 
-		/* 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 (bytes > 0) 
 		{
-			/* 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. */
+			char *resp;
+			line_buffer[bytes+1] = '\0';
 
-			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;
+			for (resp = strtok_r (line_buffer, "\n", &lasts); resp; resp = strtok_r (NULL, "\n", &lasts))
+			{
+				if (resp && strlen (resp) > 1 && resp[0] == '*') {
+					if (!idle_resp)
+						idle_resp = idle_response_new (folder);
+					consume_idle_line (store, folder, resp, idle_resp);
+					lines++;
 				}
 			}
-			g_static_rec_mutex_unlock (store->idle_lock);
+
+			printf ("IDLE: read %d bytes %s\n", bytes, line_buffer);
 		}
 
-		if (resp)
-			g_free (resp);
+		if (!store->idle_cont || (idle_resp && idle_resp->exists_happened)) {
+			idle_done (store, folder, idle_resp);
+			stopped = TRUE;
+			if (!store->idle_cont)
+				retval = idle_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 */
+		if (store->idle_cont) {
+			if (idle_resp) {
 				process_idle_response (idle_resp);
 				idle_response_free (idle_resp);
 				idle_resp = 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) */
-
-				senddone = TRUE;
-				retval = idle_resp;
+				printf ("Processed %d lines\n", lines);
+				lines = 0;
 			}
-		} else {
-			/* If store->idle_cont was FALSE, we're going to handle
-			 * idle_resp differently (look below). */
-			senddone = TRUE;
-			retval = idle_resp; 
+			if (stopped)
+				idle_start (store);
 		}
 
-		/* 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 (store->idle_cont)
-				first = TRUE; 
-			else
-				my_cont = FALSE;
-
-			cnt = 0;
-		}
-
-		/* TNY TODO: try to use the select() of the non-blocking read 
-		 * for this usleep() and cnt stuff. */
-
-		if (my_cont)
-			usleep (500000);
-		cnt++;
+		memset (line_buffer, 0, sizeof (*line_buffer));
 	}
 
+
 	/* 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) */
@@ -4009,8 +3912,14 @@
 	{
 		if (store->in_idle && store->idle_thread) {
 			IdleResponse *idle_resp = NULL;
+
 			store->idle_cont = FALSE;
+			if (store->current_idle)
+				camel_operation_cancel (store->current_idle);
 			idle_resp = g_thread_join (store->idle_thread);
+			if (store->current_idle)
+				camel_operation_uncancel (store->current_idle);
+
 			g_static_rec_mutex_lock (store->idle_prefix_lock);
 			g_static_rec_mutex_lock (store->idle_lock);
 			store->in_idle = FALSE;
@@ -4065,7 +3974,6 @@
 
 			if (!store->in_idle && store->idle_thread) {
 				IdleResponse *idle_resp = NULL;
-
 				store->idle_cont = FALSE;
 				idle_resp = g_thread_join (store->idle_thread);
 				store->idle_thread = NULL;
@@ -4093,6 +4001,10 @@
 				info->folder = folder;
 				camel_object_ref (info->folder);
 
+				if (!store->current_idle)
+					store->current_idle = camel_operation_new (NULL, NULL);
+
+
 				store->idle_thread = g_thread_create (idle_thread, 
 					info, TRUE, NULL);
 				g_mutex_lock (info->mutex);
Index: libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-command.c
===================================================================
--- libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-command.c	(revision 2883)
+++ libtinymail-camel/camel-lite/camel/providers/imap/camel-imap-command.c	(working copy)
@@ -355,19 +355,6 @@
 		fprintf (stderr, "sending : %c%.5u %s\r\n", store->tag_prefix, store->command, mask);
 	}
 
-	/* Read away whatever we got */
-	while (camel_imap_store_readline_nb (store, &resp, &myex) > 0)
-	{
-		imap_debug ("unsolitcited: ");
-		imap_debug (resp);
-		imap_debug ("\n");
-
-		g_free (resp);
-		resp=NULL;
-	}
-	if (resp)
-		g_free (resp);
-
 	full_cmd = g_strdup_printf ("%c%.5u %s\r\n", store->tag_prefix, 
 		store->command++, cmd);
 	len = strlen (full_cmd);
@@ -531,72 +518,6 @@
 }
 
 
-CamelImapResponseType
-camel_imap_command_response_idle (CamelImapStore *store, char **response,
-			     CamelException *ex)
-{
-	CamelImapResponseType type;
-	char *respbuf;
-
-	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)) {
-			/* Connection was lost, no more data to fetch */
-			camel_service_disconnect (CAMEL_SERVICE (store), FALSE, NULL);
-			camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
-					      _("Server unexpectedly disconnected: %s"),
-					      _("Unknown error")); /* g_strerror (104));  FIXME after 1.0 is released */
-			store->connected = FALSE;
-			g_free (respbuf);
-			respbuf = NULL;
-			type = CAMEL_IMAP_RESPONSE_ERROR;
-			break;
-		}
-		
-		/* Read the rest of the response. */
-		type = CAMEL_IMAP_RESPONSE_UNTAGGED;
-		respbuf = imap_read_untagged (store, respbuf, ex);
-		if (!respbuf)
-			type = CAMEL_IMAP_RESPONSE_ERROR;
-		else if (!g_ascii_strncasecmp (respbuf, "* OK [ALERT]", 12)
-			 || !g_ascii_strncasecmp (respbuf, "* NO [ALERT]", 12)
-			 || !g_ascii_strncasecmp (respbuf, "* BAD [ALERT]", 13)) {
-			char *msg;
-
-			/* for imap ALERT codes, account user host */
-			/* we might get a ']' from a BAD response since we +12, but who cares? */
-			msg = g_strdup_printf(_("Alert from IMAP server %s %s:\n%s"),
-					      ((CamelService *)store)->url->user, ((CamelService *)store)->url->host, respbuf+12);
-			camel_session_alert_user_generic(((CamelService *)store)->session, 
-				CAMEL_SESSION_ALERT_WARNING, msg, FALSE, ((CamelService *)store));
-			g_free(msg);
-		} else if (!g_ascii_strncasecmp (respbuf, "* BAD Invalid tag",17))
-			type = CAMEL_IMAP_RESPONSE_ERROR;
-		break;
-	case '+':
-		type = CAMEL_IMAP_RESPONSE_CONTINUATION;
-		break;
-	default:
-		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;
-	
-	return type;
-}
-
 CamelImapResponse *
 imap_read_response (CamelImapStore *store, CamelException *ex)
 {
Index: libtinymail-camel/camel-lite/camel/camel-tcp-stream-openssl.c
===================================================================
--- libtinymail-camel/camel-lite/camel/camel-tcp-stream-openssl.c	(revision 2882)
+++ libtinymail-camel/camel-lite/camel/camel-tcp-stream-openssl.c	(working copy)
@@ -61,7 +61,7 @@
 /* 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_nb (CamelTcpStream *stream, char *buffer, size_t n);
+static ssize_t stream_wait (CamelTcpStream *stream, int stop_fd, int timeout, 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);
 static int stream_flush  (CamelStream *stream);
@@ -84,6 +84,9 @@
 	gboolean ssl_mode;
 	guint32 flags;
 	CamelService *service;
+
+	gchar *wait_buffer;
+	size_t wait_buffer_size;
 };
 
 
@@ -105,7 +108,7 @@
 	camel_stream_class->flush = stream_flush;
 	camel_stream_class->close = stream_close;
 	
-	camel_tcp_stream_class->read_nb = stream_read_nb;
+	camel_tcp_stream_class->wait = stream_wait;
 	camel_tcp_stream_class->connect = stream_connect;
 	camel_tcp_stream_class->getsockopt = stream_getsockopt;
 	camel_tcp_stream_class->setsockopt = stream_setsockopt;
@@ -124,6 +127,8 @@
 	
 	stream->priv = g_new0 (struct _CamelTcpStreamSSLPrivate, 1);
 	stream->priv->sockfd = -1;
+	stream->priv->wait_buffer = g_malloc (1024);
+	stream->priv->wait_buffer_size = -1;
 }
 
 static void
@@ -143,9 +148,10 @@
 	
 	if (stream->priv->sockfd != -1)
 		close (stream->priv->sockfd);
-	
+
 	g_free (stream->priv->expected_host);
-	
+	g_free (stream->priv->wait_buffer);
+
 	g_free (stream->priv);
 }
 
@@ -288,53 +294,42 @@
 
 
 static ssize_t
-stream_read_nb (CamelTcpStream *stream, char *buffer, size_t n)
+stream_wait (CamelTcpStream *stream, int stop_fd, int timeout, char *buffer, size_t max_len)
 {
 	CamelTcpStreamSSL *openssl = CAMEL_TCP_STREAM_SSL (stream);
 	SSL *ssl = openssl->priv->ssl;
 	ssize_t nread;
-
 	int error, flags, fdmax;
-	struct timeval timeout;
+	struct timeval tv;
 	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);
+
+	fdmax = MAX (openssl->priv->sockfd, stop_fd) + 1;
+	FD_ZERO (&rdset);
+	FD_SET (openssl->priv->sockfd, &rdset);
+	FD_SET (stop_fd, &rdset);
+
+	nread = -1;
+	tv.tv_sec = timeout;
+	tv.tv_usec = 0;
+
+	res = select (fdmax, &rdset, 0, 0, &tv);
+
+	if (res > 0 && !FD_ISSET (stop_fd, &rdset)) {
+		if (ssl)
+			nread = SSL_read (ssl, buffer, max_len);
+		else
+			nread = read (openssl->priv->sockfd, buffer, max_len);
+	} else
 		nread = -1;
-		timeout.tv_sec = NONBLOCKING_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;
 }
 
@@ -346,7 +341,7 @@
 	SSL *ssl = openssl->priv->ssl;
 	ssize_t nread;
 	int cancel_fd;
-	
+
 	if (camel_operation_cancel_check (NULL)) {
 		errno = EINTR;
 		return -1;
Index: libtinymail-camel/camel-lite/camel/camel-tcp-stream.c
===================================================================
--- libtinymail-camel/camel-lite/camel/camel-tcp-stream.c	(revision 2882)
+++ libtinymail-camel/camel-lite/camel/camel-tcp-stream.c	(working copy)
@@ -40,7 +40,7 @@
 static int tcp_setsockopt (CamelTcpStream *stream, const CamelSockOptData *data);
 static struct sockaddr *tcp_get_local_address (CamelTcpStream *stream, socklen_t *len);
 static struct sockaddr *tcp_get_remote_address (CamelTcpStream *stream, socklen_t *len);
-static ssize_t tcp_read_nb (CamelTcpStream *stream, char *buffer, size_t n);
+static ssize_t tcp_wait (CamelTcpStream *stream, int stop_fd, int timeout, char *buffer, size_t max_len);
 
 static void
 camel_tcp_stream_class_init (CamelTcpStreamClass *camel_tcp_stream_class)
@@ -50,12 +50,12 @@
 	parent_class = CAMEL_STREAM_CLASS (camel_type_get_global_classfuncs (CAMEL_STREAM_TYPE));
 	
 	/* tcp stream methods */
-	camel_tcp_stream_class->read_nb            = tcp_read_nb;
 	camel_tcp_stream_class->connect            = tcp_connect;
 	camel_tcp_stream_class->getsockopt         = tcp_getsockopt;
 	camel_tcp_stream_class->setsockopt         = tcp_setsockopt;
 	camel_tcp_stream_class->get_local_address  = tcp_get_local_address;
 	camel_tcp_stream_class->get_remote_address = tcp_get_remote_address;
+	camel_tcp_stream_class->wait               = tcp_wait;
 }
 
 static void
@@ -84,9 +84,9 @@
 }
 
 static ssize_t
-tcp_read_nb (CamelTcpStream *stream, char *buffer, size_t n)
+tcp_wait (CamelTcpStream *stream, int stop_fd, int timeout, char *buffer, size_t max_len)
 {
-	w(g_warning ("CamelTcpStream::read_nb called on default implementation"));
+	w(g_warning ("CamelTcpStream::wait called on default implementation"));
 	return -1;
 }
 
@@ -191,10 +191,10 @@
 	return CTS_CLASS (stream)->get_local_address (stream, len);
 }
 
-int 
-camel_tcp_stream_read_nb (CamelTcpStream *stream, char *buffer, size_t n)
+ssize_t 
+camel_tcp_stream_wait (CamelTcpStream *stream, int stop_fd, int timeout, char *buffer, size_t max_len)
 {
-	return CTS_CLASS (stream)->read_nb (stream, buffer, n);
+	return CTS_CLASS (stream)->wait (stream, stop_fd, timeout, buffer, max_len);
 }
 
 
Index: libtinymail-camel/camel-lite/camel/camel-tcp-stream.h
===================================================================
--- libtinymail-camel/camel-lite/camel/camel-tcp-stream.h	(revision 2882)
+++ libtinymail-camel/camel-lite/camel/camel-tcp-stream.h	(working copy)
@@ -106,7 +106,9 @@
 	
 	struct sockaddr * (*get_local_address)  (CamelTcpStream *stream, socklen_t *len);
 	struct sockaddr * (*get_remote_address) (CamelTcpStream *stream, socklen_t *len);
-	ssize_t (*read_nb)   (CamelTcpStream *stream, char *buffer, size_t n);
+
+	ssize_t (*wait) (CamelTcpStream *stream, int stop_fd, int timeout, char *buffer, size_t max_len);
+
 } CamelTcpStreamClass;
 
 /* Standard Camel function */
@@ -116,11 +118,11 @@
 int         camel_tcp_stream_connect    (CamelTcpStream *stream, struct addrinfo *host);
 int         camel_tcp_stream_getsockopt (CamelTcpStream *stream, CamelSockOptData *data);
 int         camel_tcp_stream_setsockopt (CamelTcpStream *stream, const CamelSockOptData *data);
+ssize_t     camel_tcp_stream_wait       (CamelTcpStream *stream, int stop_fd, int timeout, char *buffer, size_t max_len);
 
 struct sockaddr *camel_tcp_stream_get_local_address  (CamelTcpStream *stream, socklen_t *len);
 struct sockaddr *camel_tcp_stream_get_remote_address (CamelTcpStream *stream, socklen_t *len);
 
-int         camel_tcp_stream_read_nb    (CamelTcpStream *stream, char *buffer, size_t n);
 
 G_END_DECLS
 
Index: libtinymail-camel/camel-lite/camel/camel-file-utils.c
===================================================================
--- libtinymail-camel/camel-lite/camel/camel-file-utils.c	(revision 2882)
+++ libtinymail-camel/camel-lite/camel/camel-file-utils.c	(working copy)
@@ -798,89 +798,8 @@
 }
 
 
-ssize_t
-camel_read_socket_nb (int fd, char *buf, size_t n)
-{
-#ifndef G_OS_WIN32
-	return camel_read_nb (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 = NONBLOCKING_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 (0&&(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 = NONBLOCKING_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 (0&&(nread == -1 && WSAGetLastError () == WSAEWOULDBLOCK));
-	failed:
-		;
-	}
-	
-	return nread;
-#endif
-}
-
-
-
 /**
  * camel_write_socket:
  * @fd: file descriptor
Index: libtinymail-camel/camel-lite/camel/camel-tcp-stream-raw.c
===================================================================
--- libtinymail-camel/camel-lite/camel/camel-tcp-stream-raw.c	(revision 2882)
+++ libtinymail-camel/camel-lite/camel/camel-tcp-stream-raw.c	(working copy)
@@ -32,7 +32,12 @@
 #include <unistd.h>
 #include <sys/time.h>
 #include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <sys/types.h>
 
+#include <glib.h>
+
 #include "camel-file-utils.h"
 #include "camel-operation.h"
 #include "camel-tcp-stream-raw.h"
@@ -64,7 +69,7 @@
 static int stream_setsockopt (CamelTcpStream *stream, const CamelSockOptData *data);
 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_wait (CamelTcpStream *stream, int stop_fd, int timeout, char *buffer, size_t n);
 
 
 static void
@@ -83,7 +88,7 @@
 	camel_stream_class->flush = stream_flush;
 	camel_stream_class->close = stream_close;
 
-	camel_tcp_stream_class->read_nb = stream_read_nb;
+	camel_tcp_stream_class->wait = stream_wait;
 	camel_tcp_stream_class->connect = stream_connect;
 	camel_tcp_stream_class->getsockopt = stream_getsockopt;
 	camel_tcp_stream_class->setsockopt  = stream_setsockopt;
@@ -95,7 +100,6 @@
 camel_tcp_stream_raw_init (gpointer object, gpointer klass)
 {
 	CamelTcpStreamRaw *stream = CAMEL_TCP_STREAM_RAW (object);
-	
 	stream->sockfd = -1;
 }
 
@@ -103,7 +107,6 @@
 camel_tcp_stream_raw_finalize (CamelObject *object)
 {
 	CamelTcpStreamRaw *stream = CAMEL_TCP_STREAM_RAW (object);
-	
 	if (stream->sockfd != -1)
 		SOCKET_CLOSE (stream->sockfd);
 }
@@ -252,16 +255,40 @@
 stream_read (CamelStream *stream, char *buffer, size_t n)
 {
 	CamelTcpStreamRaw *raw = CAMEL_TCP_STREAM_RAW (stream);
-	
+
 	return camel_read_socket (raw->sockfd, buffer, n);
 }
 
 static ssize_t
-stream_read_nb (CamelTcpStream *stream, char *buffer, size_t n)
+stream_wait (CamelTcpStream *stream, int stop_fd, int timeout, char *buffer, size_t max_len)
 {
 	CamelTcpStreamRaw *raw = CAMEL_TCP_STREAM_RAW (stream);
-	
-	return camel_read_socket_nb (raw->sockfd, buffer, n);
+	int fd = raw->sockfd;
+	ssize_t nread;
+	int fdmax;
+	fd_set rdset;
+	u_long yes = 1;
+	struct timeval tv;
+	int res;
+
+	//ioctlsocket (fd, FIONBIO, &yes);
+	fdmax = MAX (fd, stop_fd) + 1;
+
+	FD_ZERO (&rdset);
+	FD_SET (fd, &rdset);
+	FD_SET (stop_fd, &rdset);
+
+	tv.tv_sec = timeout;
+	tv.tv_usec = 0;
+	nread = -1;
+
+	res = select (fdmax, &rdset, 0, 0, &tv);
+	if (res > 0 && !FD_ISSET (stop_fd, &rdset))
+		nread = recv (fd, buffer, max_len, 0);
+	else
+		nread = -1;
+
+	return nread;
 }
 
 static ssize_t
Index: libtinymail-camel/camel-lite/camel/camel-stream-buffer.c
===================================================================
--- libtinymail-camel/camel-lite/camel/camel-stream-buffer.c	(revision 2882)
+++ libtinymail-camel/camel-lite/camel/camel-stream-buffer.c	(working copy)
@@ -429,49 +429,7 @@
 }
 
 
-int
-camel_tcp_stream_buffer_gets_nb (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_tcp_stream_read_nb ((CamelTcpStream *)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);
-}
-
 /**
  * camel_stream_buffer_read_line: read a complete line from the stream
  * @sbf: a #CamelStreamBuffer object
Index: libtinymail-camel/camel-lite/camel/camel-stream-buffer.h
===================================================================
--- libtinymail-camel/camel-lite/camel/camel-stream-buffer.h	(revision 2882)
+++ libtinymail-camel/camel-lite/camel/camel-stream-buffer.h	(working copy)
@@ -94,7 +94,6 @@
 int camel_stream_buffer_gets (CamelStreamBuffer *sbf, char *buf, unsigned int max);
 
 char *camel_stream_buffer_read_line (CamelStreamBuffer *sbf);
-int camel_tcp_stream_buffer_gets_nb (CamelStreamBuffer *sbf, char *buf, unsigned int max);
 
 
 G_END_DECLS


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