A different angle to IDLE
- From: Philip Van Hoof <spam pvanhoof be>
- To: tinymail-devel-list gnome org
- Subject: A different angle to IDLE
- Date: Fri, 26 Oct 2007 03:27:23 +0200
This is a completely different angle to IDLE, and I'm pretty sure I will
replace the implementation with this soon.
I'm first fine tuning it, then aggressively testing it and then
committing.
But please apply it and test it a bit yourself, read the code, comment
on it, etc etc.
--
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]