[evolution-data-server] CamelIMAPXServer: Add a "stream" property.



commit 2449ff17a92b80bc8e9ed7a19907cfe391a7805b
Author: Matthew Barnes <mbarnes redhat com>
Date:   Thu Aug 30 11:29:46 2012 -0400

    CamelIMAPXServer: Add a "stream" property.
    
    Protect the stream with a mutex and add camel_imapx_server_ref_stream().
    
    Additionally, the stream pointer is now in the private structure, and
    is explicitly passed to various parsing functions to ensure a reference
    is held on the stream for the duration of a parser thread iteration.
    
    This alters the signature of CamelIMAPUntaggedRespHandler.
    
    I am, however, NOT changing libcamel's soname for these changes since
    only evolution-kolab is affected and a soname bump at this point in the
    development cycle is extremely disruptive to the rest of GNOME.

 camel/camel-imapx-server.c              |  467 +++++++++++++++++++++++--------
 camel/camel-imapx-server.h              |   12 +-
 camel/camel-imapx-store.c               |   15 +-
 docs/reference/camel/camel-sections.txt |    1 +
 4 files changed, 375 insertions(+), 120 deletions(-)
---
diff --git a/camel/camel-imapx-server.c b/camel/camel-imapx-server.c
index f006dc4..88ce604 100644
--- a/camel/camel-imapx-server.c
+++ b/camel/camel-imapx-server.c
@@ -195,20 +195,62 @@ struct _CamelIMAPXServerUntaggedContext {
 };
 
 /* internal untagged handler prototypes */
-static gboolean imapx_untagged_bye (CamelIMAPXServer *is, GCancellable *cancellable, GError **error);
-static gboolean imapx_untagged_capability (CamelIMAPXServer *is, GCancellable *cancellable, GError **error);
-static gboolean imapx_untagged_exists (CamelIMAPXServer *is, GCancellable *cancellable, GError **error);
-static gboolean imapx_untagged_expunge (CamelIMAPXServer *is, GCancellable *cancellable, GError **error);
-static gboolean imapx_untagged_fetch (CamelIMAPXServer *is, GCancellable *cancellable, GError **error);
-static gboolean imapx_untagged_flags (CamelIMAPXServer *is, GCancellable *cancellable, GError **error);
-static gboolean imapx_untagged_list (CamelIMAPXServer *is, GCancellable *cancellable, GError **error);
-static gboolean imapx_untagged_lsub (CamelIMAPXServer *is, GCancellable *cancellable, GError **error);
-static gboolean imapx_untagged_namespace (CamelIMAPXServer *is, GCancellable *cancellable, GError **error);
-static gboolean imapx_untagged_ok_no_bad (CamelIMAPXServer *is, GCancellable *cancellable, GError **error);
-static gboolean imapx_untagged_preauth (CamelIMAPXServer *is, GCancellable *cancellable, GError **error);
-static gboolean imapx_untagged_recent (CamelIMAPXServer *is, GCancellable *cancellable, GError **error);
-static gboolean imapx_untagged_status (CamelIMAPXServer *is, GCancellable *cancellable, GError **error);
-static gboolean imapx_untagged_vanished (CamelIMAPXServer *is, GCancellable *cancellable, GError **error);
+static gboolean	imapx_untagged_bye		(CamelIMAPXServer *is,
+						 CamelIMAPXStream *stream,
+						 GCancellable *cancellable,
+						 GError **error);
+static gboolean	imapx_untagged_capability	(CamelIMAPXServer *is,
+						 CamelIMAPXStream *stream,
+						 GCancellable *cancellable,
+						 GError **error);
+static gboolean	imapx_untagged_exists		(CamelIMAPXServer *is,
+						 CamelIMAPXStream *stream,
+						 GCancellable *cancellable,
+						 GError **error);
+static gboolean	imapx_untagged_expunge		(CamelIMAPXServer *is,
+						 CamelIMAPXStream *stream,
+						 GCancellable *cancellable,
+						 GError **error);
+static gboolean	imapx_untagged_fetch		(CamelIMAPXServer *is,
+						 CamelIMAPXStream *stream,
+						 GCancellable *cancellable,
+						 GError **error);
+static gboolean	imapx_untagged_flags		(CamelIMAPXServer *is,
+						 CamelIMAPXStream *stream,
+						 GCancellable *cancellable,
+						 GError **error);
+static gboolean	imapx_untagged_list		(CamelIMAPXServer *is,
+						 CamelIMAPXStream *stream,
+						 GCancellable *cancellable,
+						 GError **error);
+static gboolean	imapx_untagged_lsub		(CamelIMAPXServer *is,
+						 CamelIMAPXStream *stream,
+						 GCancellable *cancellable,
+						 GError **error);
+static gboolean	imapx_untagged_namespace	(CamelIMAPXServer *is,
+						 CamelIMAPXStream *stream,
+						 GCancellable *cancellable,
+						 GError **error);
+static gboolean	imapx_untagged_ok_no_bad	(CamelIMAPXServer *is,
+						 CamelIMAPXStream *stream,
+						 GCancellable *cancellable,
+						 GError **error);
+static gboolean	imapx_untagged_preauth		(CamelIMAPXServer *is,
+						 CamelIMAPXStream *stream,
+						 GCancellable *cancellable,
+						 GError **error);
+static gboolean	imapx_untagged_recent		(CamelIMAPXServer *is,
+						 CamelIMAPXStream *stream,
+						 GCancellable *cancellable,
+						 GError **error);
+static gboolean	imapx_untagged_status		(CamelIMAPXServer *is,
+						 CamelIMAPXStream *stream,
+						 GCancellable *cancellable,
+						 GError **error);
+static gboolean	imapx_untagged_vanished		(CamelIMAPXServer *is,
+						 CamelIMAPXStream *stream,
+						 GCancellable *cancellable,
+						 GError **error);
 
 enum {
 	IMAPX_UNTAGGED_ID_BAD = 0,
@@ -252,6 +294,14 @@ static const CamelIMAPXUntaggedRespHandlerDesc _untagged_descr[] = {
 struct _CamelIMAPXServerPrivate {
 	CamelIMAPXServerUntaggedContext *context;
 	GHashTable *untagged_handlers;
+
+	CamelIMAPXStream *stream;
+	GMutex stream_lock;
+};
+
+enum {
+	PROP_0,
+	PROP_STREAM
 };
 
 enum {
@@ -265,12 +315,19 @@ static guint signals[LAST_SIGNAL];
 void imapx_uidset_init (struct _uidset_state *ss, gint total, gint limit);
 gint imapx_uidset_done (struct _uidset_state *ss, struct _CamelIMAPXCommand *ic);
 gint imapx_uidset_add (struct _uidset_state *ss, struct _CamelIMAPXCommand *ic, const gchar *uid);
-static gboolean imapx_command_idle_stop (CamelIMAPXServer *is, GError **error);
-static gboolean imapx_continuation (CamelIMAPXServer *is, gboolean litplus, GCancellable *cancellable, GError **error);
-static gboolean imapx_disconnect (CamelIMAPXServer *is);
-static gint imapx_uid_cmp (gconstpointer ap, gconstpointer bp, gpointer data);
 
-static gboolean imapx_is_command_queue_empty (CamelIMAPXServer *is);
+static gboolean	imapx_command_idle_stop		(CamelIMAPXServer *is,
+						 GError **error);
+static gboolean	imapx_continuation		(CamelIMAPXServer *is,
+						 CamelIMAPXStream *stream,
+						 gboolean litplus,
+						 GCancellable *cancellable,
+						 GError **error);
+static gboolean	imapx_disconnect		(CamelIMAPXServer *is);
+static gboolean	imapx_is_command_queue_empty	(CamelIMAPXServer *is);
+static gint	imapx_uid_cmp			(gconstpointer ap,
+						 gconstpointer bp,
+						 gpointer data);
 
 /* states for the connection? */
 enum {
@@ -660,10 +717,13 @@ imapx_command_start (CamelIMAPXServer *is,
                      GCancellable *cancellable,
                      GError **error)
 {
+	CamelIMAPXStream *stream = NULL;
 	CamelIMAPXCommandPart *cp;
 	gboolean cp_continuation;
 	gboolean cp_literal_plus;
 	GList *head;
+	gboolean success = FALSE;
+	gchar *string;
 	gint retval;
 
 	camel_imapx_command_close (ic);
@@ -686,34 +746,41 @@ imapx_command_start (CamelIMAPXServer *is,
 
 	g_static_rec_mutex_lock (&is->ostream_lock);
 
+	stream = camel_imapx_server_ref_stream (is);
+
+	if (stream == NULL) {
+		g_set_error (
+			error, CAMEL_IMAPX_ERROR, 1,
+			"Cannot issue command, no stream available");
+		goto err;
+	}
+
 	c (is->tagprefix, "Starting command (active=%d,%s) %c%05u %s\r\n", camel_imapx_command_queue_get_length (is->active), is->literal?" literal":"", is->tagprefix, ic->tag, cp->data && g_str_has_prefix (cp->data, "LOGIN") ? "LOGIN..." : cp->data);
-	if (is->stream != NULL) {
-		gchar *string;
 
-		string = g_strdup_printf ("%c%05u %s\r\n", is->tagprefix, ic->tag, cp->data);
-		retval = camel_stream_write_string ((CamelStream *) is->stream, string, cancellable, NULL);
-		g_free (string);
-	} else
-		retval = -1;
+	string = g_strdup_printf (
+		"%c%05u %s\r\n", is->tagprefix, ic->tag, cp->data);
+	retval = camel_stream_write_string (
+		CAMEL_STREAM (stream), string, cancellable, NULL);
+	g_free (string);
+
 	if (retval == -1) {
 		g_set_error (
 			error, CAMEL_IMAPX_ERROR, 1,
 			"Failed to issue the command");
 		goto err;
 	}
+
 	while (is->literal == ic && cp_literal_plus) {
 		/* Sent LITERAL+ continuation immediately */
-		if (!imapx_continuation (is, TRUE, cancellable, error))
+		if (!imapx_continuation (is, stream, TRUE, cancellable, error))
 			goto err;
 	}
 
-	g_static_rec_mutex_unlock (&is->ostream_lock);
+	success = TRUE;
 
-	return TRUE;
+	goto exit;
 
 err:
-	g_static_rec_mutex_unlock (&is->ostream_lock);
-
 	camel_imapx_command_queue_remove (is->active, ic);
 
 	/* HACK: Since we're failing, make sure the command has a status
@@ -730,7 +797,13 @@ err:
 	if (ic != NULL && ic->complete != NULL)
 		ic->complete (is, ic, NULL);
 
-	return FALSE;
+exit:
+	if (stream != NULL)
+		g_object_unref (stream);
+
+	g_static_rec_mutex_unlock (&is->ostream_lock);
+
+	return success;
 }
 
 static gboolean
@@ -1242,6 +1315,7 @@ invalidate_local_cache (CamelIMAPXFolder *ifolder,
 
 static gboolean
 imapx_untagged_capability (CamelIMAPXServer *is,
+                           CamelIMAPXStream *stream,
                            GCancellable *cancellable,
                            GError **error)
 {
@@ -1251,7 +1325,7 @@ imapx_untagged_capability (CamelIMAPXServer *is,
 
 	if (is->cinfo)
 		imapx_free_capability (is->cinfo);
-	is->cinfo = imapx_parse_capability (is->stream, cancellable, error);
+	is->cinfo = imapx_parse_capability (stream, cancellable, error);
 	if (is->cinfo == NULL)
 		return FALSE;
 	c (is->tagprefix, "got capability flags %08x\n", is->cinfo->capa);
@@ -1260,6 +1334,7 @@ imapx_untagged_capability (CamelIMAPXServer *is,
 
 static gboolean
 imapx_untagged_expunge (CamelIMAPXServer *is,
+                        CamelIMAPXStream *stream,
                         GCancellable *cancellable,
                         GError **error)
 {
@@ -1293,6 +1368,7 @@ imapx_untagged_expunge (CamelIMAPXServer *is,
 
 static gboolean
 imapx_untagged_vanished (CamelIMAPXServer *is,
+                         CamelIMAPXStream *stream,
                          GCancellable *cancellable,
                          GError **error)
 {
@@ -1308,21 +1384,21 @@ imapx_untagged_vanished (CamelIMAPXServer *is,
 	/* cancellable may be NULL */
 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-	tok = camel_imapx_stream_token (is->stream, &token, &len, cancellable, error);
+	tok = camel_imapx_stream_token (stream, &token, &len, cancellable, error);
 	if (tok < 0)
 		return FALSE;
 	if (tok == '(') {
 		unsolicited = FALSE;
 		while (tok != ')') {
 			/* We expect this to be 'EARLIER' */
-			tok = camel_imapx_stream_token (is->stream, &token, &len, cancellable, error);
+			tok = camel_imapx_stream_token (stream, &token, &len, cancellable, error);
 			if (tok < 0)
 				return FALSE;
 		}
 	} else
-		camel_imapx_stream_ungettoken (is->stream, tok, token, len);
+		camel_imapx_stream_ungettoken (stream, tok, token, len);
 
-	uids = imapx_parse_uids (is->stream, cancellable, error);
+	uids = imapx_parse_uids (stream, cancellable, error);
 	if (uids == NULL)
 		return FALSE;
 
@@ -1356,6 +1432,7 @@ imapx_untagged_vanished (CamelIMAPXServer *is,
 
 static gboolean
 imapx_untagged_namespace (CamelIMAPXServer *is,
+                          CamelIMAPXStream *stream,
                           GCancellable *cancellable,
                           GError **error)
 {
@@ -1367,7 +1444,7 @@ imapx_untagged_namespace (CamelIMAPXServer *is,
 	/* cancellable may be NULL */
 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-	nsl = imapx_parse_namespace_list (is->stream, cancellable, error);
+	nsl = imapx_parse_namespace_list (stream, cancellable, error);
 	if (nsl == NULL)
 		return FALSE;
 
@@ -1391,6 +1468,7 @@ imapx_untagged_namespace (CamelIMAPXServer *is,
 
 static gboolean
 imapx_untagged_exists (CamelIMAPXServer *is,
+                       CamelIMAPXStream *stream,
                        GCancellable *cancellable,
                        GError **error)
 {
@@ -1414,6 +1492,7 @@ imapx_untagged_exists (CamelIMAPXServer *is,
 
 static gboolean
 imapx_untagged_flags (CamelIMAPXServer *is,
+                      CamelIMAPXStream *stream,
                       GCancellable *cancellable,
                       GError **error)
 {
@@ -1423,7 +1502,7 @@ imapx_untagged_flags (CamelIMAPXServer *is,
 	/* cancellable may be NULL */
 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-	imapx_parse_flags (is->stream, &flags, NULL, cancellable, error);
+	imapx_parse_flags (stream, &flags, NULL, cancellable, error);
 	c (is->tagprefix, "flags: %08x\n", flags);
 
 	return TRUE;
@@ -1431,6 +1510,7 @@ imapx_untagged_flags (CamelIMAPXServer *is,
 
 static gboolean
 imapx_untagged_fetch (CamelIMAPXServer *is,
+                      CamelIMAPXStream *stream,
                       GCancellable *cancellable,
                       GError **error)
 {
@@ -1440,7 +1520,7 @@ imapx_untagged_fetch (CamelIMAPXServer *is,
 	/* cancellable may be NULL */
 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-	finfo = imapx_parse_fetch (is->stream, cancellable, error);
+	finfo = imapx_parse_fetch (stream, cancellable, error);
 	if (finfo == NULL) {
 		imapx_free_fetch (finfo);
 		return FALSE;
@@ -1668,6 +1748,7 @@ imapx_untagged_fetch (CamelIMAPXServer *is,
 
 static gboolean
 imapx_untagged_lsub (CamelIMAPXServer *is,
+                     CamelIMAPXStream *stream,
                      GCancellable *cancellable,
                      GError **error)
 {
@@ -1682,6 +1763,7 @@ imapx_untagged_lsub (CamelIMAPXServer *is,
 
 static gboolean
 imapx_untagged_list (CamelIMAPXServer *is,
+                     CamelIMAPXStream *stream,
                      GCancellable *cancellable,
                      GError **error)
 {
@@ -1693,7 +1775,7 @@ imapx_untagged_list (CamelIMAPXServer *is,
 	/* cancellable may be NULL */
 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-	linfo = imapx_parse_list (is->stream, cancellable, error);
+	linfo = imapx_parse_list (stream, cancellable, error);
 	if (!linfo)
 		return TRUE;
 
@@ -1724,6 +1806,7 @@ imapx_untagged_list (CamelIMAPXServer *is,
 
 static gboolean
 imapx_untagged_recent (CamelIMAPXServer *is,
+                       CamelIMAPXStream *stream,
                        GCancellable *cancellable,
                        GError **error)
 {
@@ -1739,6 +1822,7 @@ imapx_untagged_recent (CamelIMAPXServer *is,
 
 static gboolean
 imapx_untagged_status (CamelIMAPXServer *is,
+                       CamelIMAPXStream *stream,
                        GCancellable *cancellable,
                        GError **error)
 {
@@ -1748,7 +1832,7 @@ imapx_untagged_status (CamelIMAPXServer *is,
 	/* cancellable may be NULL */
 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-	sinfo = imapx_parse_status_info (is->stream, cancellable, error);
+	sinfo = imapx_parse_status_info (stream, cancellable, error);
 
 	if (sinfo) {
 		CamelIMAPXStoreSummary *s = ((CamelIMAPXStore *) is->store)->summary;
@@ -1789,6 +1873,7 @@ imapx_untagged_status (CamelIMAPXServer *is,
 
 static gboolean
 imapx_untagged_bye (CamelIMAPXServer *is,
+                    CamelIMAPXStream *stream,
                     GCancellable *cancellable,
                     GError **error)
 {
@@ -1798,7 +1883,7 @@ imapx_untagged_bye (CamelIMAPXServer *is,
 	/* cancellable may be NULL */
 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-	if (camel_imapx_stream_text (is->stream, &token, cancellable, NULL)) {
+	if (camel_imapx_stream_text (stream, &token, cancellable, NULL)) {
 		c (is->tagprefix, "BYE: %s\n", token);
 		g_set_error (error, CAMEL_IMAPX_ERROR, 1,
 			     "IMAP server said BYE: %s", token);
@@ -1810,6 +1895,7 @@ imapx_untagged_bye (CamelIMAPXServer *is,
 
 static gboolean
 imapx_untagged_preauth (CamelIMAPXServer *is,
+                        CamelIMAPXStream *stream,
                         GCancellable *cancellable,
                         GError **error)
 {
@@ -1826,6 +1912,7 @@ imapx_untagged_preauth (CamelIMAPXServer *is,
 
 static gboolean
 imapx_untagged_ok_no_bad (CamelIMAPXServer *is,
+                          CamelIMAPXStream *stream,
                           GCancellable *cancellable,
                           GError **error)
 {
@@ -1835,11 +1922,13 @@ imapx_untagged_ok_no_bad (CamelIMAPXServer *is,
 
 	/* TODO: validate which ones of these can happen as unsolicited responses */
 	/* TODO: handle bye/preauth differently */
-	camel_imapx_stream_ungettoken (is->stream,
-				       is->priv->context->tok,
-				       is->priv->context->token,
-				       is->priv->context->len);
-	is->priv->context->sinfo = imapx_parse_status (is->stream, cancellable, error);
+	camel_imapx_stream_ungettoken (
+		stream,
+		is->priv->context->tok,
+		is->priv->context->token,
+		is->priv->context->len);
+	is->priv->context->sinfo =
+		imapx_parse_status (stream, cancellable, error);
 	if (is->priv->context->sinfo == NULL)
 		return FALSE;
 	switch (is->priv->context->sinfo->condition) {
@@ -1899,6 +1988,7 @@ imapx_untagged_ok_no_bad (CamelIMAPXServer *is,
 /* handle any untagged responses */
 static gboolean
 imapx_untagged (CamelIMAPXServer *is,
+                CamelIMAPXStream *stream,
                 GCancellable *cancellable,
                 GError **error)
 {
@@ -1929,7 +2019,7 @@ imapx_untagged (CamelIMAPXServer *is,
 	e (is->tagprefix, "got untagged response\n");
 	is->priv->context->id = 0;
 	is->priv->context->tok = camel_imapx_stream_token (
-		is->stream,
+		stream,
 		&(is->priv->context->token),
 		&(is->priv->context->len),
 		cancellable, error);
@@ -1940,11 +2030,10 @@ imapx_untagged (CamelIMAPXServer *is,
 		is->priv->context->id = strtoul (
 			(gchar *) is->priv->context->token, NULL, 10);
 		is->priv->context->tok = camel_imapx_stream_token (
-			is->stream,
+			stream,
 			&(is->priv->context->token),
 			&(is->priv->context->len),
-							       cancellable,
-							       error);
+			cancellable, error);
 		if (is->priv->context->tok < 0)
 			goto exit;
 	}
@@ -1977,7 +2066,7 @@ imapx_untagged (CamelIMAPXServer *is,
 		}
 
 		/* call the handler function */
-		ok = desc->handler (is, cancellable, error);
+		ok = desc->handler (is, stream, cancellable, error);
 		if (!ok)
 			goto exit;
 
@@ -2000,7 +2089,7 @@ imapx_untagged (CamelIMAPXServer *is,
 			goto exit;
 	}
 
-	ok = (camel_imapx_stream_skip (is->stream, cancellable, error) == 0);
+	ok = (camel_imapx_stream_skip (stream, cancellable, error) == 0);
  exit:
 	g_free (is->priv->context);
 	is->priv->context = NULL;
@@ -2012,6 +2101,7 @@ imapx_untagged (CamelIMAPXServer *is,
  * either data continuations, or auth continuation */
 static gboolean
 imapx_continuation (CamelIMAPXServer *is,
+                    CamelIMAPXStream *stream,
                     gboolean litplus,
                     GCancellable *cancellable,
                     GError **error)
@@ -2025,7 +2115,7 @@ imapx_continuation (CamelIMAPXServer *is,
 	 * ohter lock here.  All other writes go through
 	 * queue-lock */
 	if (imapx_idle_supported (is) && imapx_in_idle (is)) {
-		camel_imapx_stream_skip (is->stream, cancellable, error);
+		camel_imapx_stream_skip (stream, cancellable, error);
 
 		c (is->tagprefix, "Got continuation response for IDLE \n");
 		IDLE_LOCK (is->idle);
@@ -2058,7 +2148,7 @@ imapx_continuation (CamelIMAPXServer *is,
 	ic = is->literal;
 	if (!litplus) {
 		if (ic == NULL) {
-			camel_imapx_stream_skip (is->stream, cancellable, error);
+			camel_imapx_stream_skip (stream, cancellable, error);
 			c (is->tagprefix, "got continuation response with no outstanding continuation requests?\n");
 			return TRUE;
 		}
@@ -2074,17 +2164,17 @@ imapx_continuation (CamelIMAPXServer *is,
 	switch (cp->type & CAMEL_IMAPX_COMMAND_MASK) {
 	case CAMEL_IMAPX_COMMAND_DATAWRAPPER:
 		c (is->tagprefix, "writing data wrapper to literal\n");
-		camel_data_wrapper_write_to_stream_sync ((CamelDataWrapper *) cp->ob, (CamelStream *) is->stream, cancellable, NULL);
+		camel_data_wrapper_write_to_stream_sync ((CamelDataWrapper *) cp->ob, (CamelStream *) stream, cancellable, NULL);
 		break;
 	case CAMEL_IMAPX_COMMAND_STREAM:
 		c (is->tagprefix, "writing stream to literal\n");
-		camel_stream_write_to_stream ((CamelStream *) cp->ob, (CamelStream *) is->stream, cancellable, NULL);
+		camel_stream_write_to_stream ((CamelStream *) cp->ob, (CamelStream *) stream, cancellable, NULL);
 		break;
 	case CAMEL_IMAPX_COMMAND_AUTH: {
 		gchar *resp;
 		guchar *token;
 
-		if (camel_imapx_stream_text (is->stream, &token, cancellable, error))
+		if (camel_imapx_stream_text (stream, &token, cancellable, error))
 			return FALSE;
 
 		resp = camel_sasl_challenge_base64_sync (
@@ -2095,7 +2185,7 @@ imapx_continuation (CamelIMAPXServer *is,
 			return FALSE;
 		c (is->tagprefix, "got auth continuation, feeding token '%s' back to auth mech\n", resp);
 
-		camel_stream_write ((CamelStream *) is->stream, resp, strlen (resp), cancellable, NULL);
+		camel_stream_write ((CamelStream *) stream, resp, strlen (resp), cancellable, NULL);
 		g_free (resp);
 		/* we want to keep getting called until we get a status reponse from the server
 		 * ignore what sasl tells us */
@@ -2110,14 +2200,14 @@ imapx_continuation (CamelIMAPXServer *is,
 
 		// FIXME: errors
 		if (cp->ob && (file = camel_stream_fs_new_with_name (cp->ob, O_RDONLY, 0, NULL))) {
-			camel_stream_write_to_stream (file, (CamelStream *) is->stream, cancellable, NULL);
+			camel_stream_write_to_stream (file, (CamelStream *) stream, cancellable, NULL);
 			g_object_unref (file);
 		} else if (cp->ob_size > 0) {
 			// Server is expecting data ... ummm, send it zeros?  abort?
 		}
 		break; }
 	case CAMEL_IMAPX_COMMAND_STRING:
-		camel_stream_write ((CamelStream *) is->stream, cp->ob, cp->ob_size, cancellable, NULL);
+		camel_stream_write ((CamelStream *) stream, cp->ob, cp->ob_size, cancellable, NULL);
 		break;
 	default:
 		/* should we just ignore? */
@@ -2129,7 +2219,7 @@ imapx_continuation (CamelIMAPXServer *is,
 	}
 
 	if (!litplus)
-		camel_imapx_stream_skip (is->stream, cancellable, error);
+		camel_imapx_stream_skip (stream, cancellable, error);
 
 noskip:
 	link = g_list_next (link);
@@ -2138,8 +2228,8 @@ noskip:
 		cp = (CamelIMAPXCommandPart *) link->data;
 
 		c (is->tagprefix, "next part of command \"%c%05u: %s\"\n", is->tagprefix, ic->tag, cp->data);
-		camel_stream_write_string ((CamelStream *) is->stream, cp->data, cancellable, NULL);
-		camel_stream_write_string ((CamelStream *) is->stream, "\r\n", cancellable, NULL);
+		camel_stream_write_string ((CamelStream *) stream, cp->data, cancellable, NULL);
+		camel_stream_write_string ((CamelStream *) stream, "\r\n", cancellable, NULL);
 		if (cp->type & (CAMEL_IMAPX_COMMAND_CONTINUATION | CAMEL_IMAPX_COMMAND_LITERAL_PLUS)) {
 			newliteral = ic;
 		} else {
@@ -2147,7 +2237,7 @@ noskip:
 		}
 	} else {
 		c (is->tagprefix, "%p: queueing continuation\n", ic);
-		camel_stream_write_string ((CamelStream *) is->stream, "\r\n", cancellable, NULL);
+		camel_stream_write_string ((CamelStream *) stream, "\r\n", cancellable, NULL);
 	}
 
 	QUEUE_LOCK (is);
@@ -2163,6 +2253,7 @@ noskip:
 /* handle a completion line */
 static gboolean
 imapx_completion (CamelIMAPXServer *is,
+                  CamelIMAPXStream *stream,
                   guchar *token,
                   gint len,
                   GCancellable *cancellable,
@@ -2224,7 +2315,7 @@ imapx_completion (CamelIMAPXServer *is,
 
 	QUEUE_UNLOCK (is);
 
-	ic->status = imapx_parse_status (is->stream, cancellable, error);
+	ic->status = imapx_parse_status (stream, cancellable, error);
 
 	if (ic->status == NULL)
 		return FALSE;
@@ -2245,27 +2336,45 @@ imapx_step (CamelIMAPXServer *is,
             GCancellable *cancellable,
             GError **error)
 {
+	CamelIMAPXStream *stream;
 	guint len;
 	guchar *token;
 	gint tok;
+	gboolean success = FALSE;
+
+	stream = camel_imapx_server_ref_stream (is);
 
 	// poll ?  wait for other stuff? loop?
-	tok = camel_imapx_stream_token (is->stream, &token, &len, cancellable, error);
-	if (tok < 0)
-		return FALSE;
+	tok = camel_imapx_stream_token (
+		stream, &token, &len, cancellable, error);
 
-	if (tok == '*')
-		return imapx_untagged (is, cancellable, error);
-	else if (tok == IMAPX_TOK_TOKEN)
-		return imapx_completion (is, token, len, cancellable, error);
-	else if (tok == '+')
-		return imapx_continuation (is, FALSE, cancellable, error);
+	switch (tok) {
+		case IMAPX_TOK_PROTOCOL:
+		case IMAPX_TOK_ERROR:
+			/* GError is already set. */
+			break;
+		case '*':
+			success = imapx_untagged (
+				is, stream, cancellable, error);
+			break;
+		case IMAPX_TOK_TOKEN:
+			success = imapx_completion (
+				is, stream, token, len, cancellable, error);
+			break;
+		case '+':
+			success = imapx_continuation (
+				is, stream, FALSE, cancellable, error);
+			break;
+		default:
+			g_set_error (
+				error, CAMEL_IMAPX_ERROR, 1,
+				"unexpected server response:");
+			break;
+	}
 
-	g_set_error (
-		error, CAMEL_IMAPX_ERROR, 1,
-		"unexpected server response:");
+	g_object_unref (stream);
 
-	return FALSE;
+	return success;
 }
 
 /* Used to run 1 command synchronously,
@@ -2421,7 +2530,19 @@ static gboolean
 imapx_command_idle_stop (CamelIMAPXServer *is,
                          GError **error)
 {
-	if (!is->stream || camel_stream_write_string ((CamelStream *) is->stream, "DONE\r\n", NULL, NULL) == -1) {
+	CamelIMAPXStream *stream;
+	gboolean success = FALSE;
+
+	stream = camel_imapx_server_ref_stream (is);
+
+	if (stream != NULL) {
+		success = (camel_stream_write_string (
+			CAMEL_STREAM (stream),
+			"DONE\r\n", NULL, NULL) != -1);
+		g_object_unref (stream);
+	}
+
+	if (!success) {
 		g_set_error (
 			error, CAMEL_IMAPX_ERROR, 1,
 			"Unable to issue DONE");
@@ -2430,10 +2551,9 @@ imapx_command_idle_stop (CamelIMAPXServer *is,
 		is->parser_quit = TRUE;
 		if (is->cancellable)
 			g_cancellable_cancel (is->cancellable);
-		return FALSE;
 	}
 
-	return TRUE;
+	return success;
 }
 
 static gboolean
@@ -3042,6 +3162,7 @@ connect_to_server_process (CamelIMAPXServer *is,
 	CamelProvider *provider;
 	CamelSettings *settings;
 	CamelStream *cmd_stream;
+	CamelStream *imapx_stream;
 	CamelService *service;
 	CamelURL url;
 	gint ret, i = 0;
@@ -3154,9 +3275,18 @@ connect_to_server_process (CamelIMAPXServer *is,
 
 	g_free (full_cmd);
 
-	is->stream = (CamelIMAPXStream *) camel_imapx_stream_new (cmd_stream);
+	imapx_stream = camel_imapx_stream_new (cmd_stream);
+
 	g_object_unref (cmd_stream);
+
+	/* Server takes ownership of the IMAPX stream. */
+	g_mutex_lock (&is->priv->stream_lock);
+	g_warn_if_fail (is->priv->stream == NULL);
+	is->priv->stream = CAMEL_IMAPX_STREAM (imapx_stream);
 	is->is_process_stream = TRUE;
+	g_mutex_unlock (&is->priv->stream_lock);
+
+	g_object_notify (G_OBJECT (is), "stream");
 
 	return TRUE;
 }
@@ -3169,7 +3299,8 @@ imapx_connect_to_server (CamelIMAPXServer *is,
 {
 	CamelNetworkSettings *network_settings;
 	CamelNetworkSecurityMethod method;
-	CamelStream * tcp_stream = NULL;
+	CamelStream *tcp_stream = NULL;
+	CamelStream *imapx_stream = NULL;
 	CamelSockOptData sockopt;
 	CamelSettings *settings;
 	CamelService *service;
@@ -3229,21 +3360,34 @@ imapx_connect_to_server (CamelIMAPXServer *is,
 		goto exit;
 	}
 
-	is->stream = (CamelIMAPXStream *) camel_imapx_stream_new (tcp_stream);
-	g_object_unref (tcp_stream);
-
-	/* Disable Nagle - we send a lot of small requests which nagle slows down */
+	/* Disable Nagle
+	 * We send a lot of small requests which nagle slows down. */
 	sockopt.option = CAMEL_SOCKOPT_NODELAY;
 	sockopt.value.no_delay = TRUE;
-	camel_tcp_stream_setsockopt ((CamelTcpStream *) tcp_stream, &sockopt);
+	camel_tcp_stream_setsockopt (CAMEL_TCP_STREAM (tcp_stream), &sockopt);
 
-	/* Set keepalive - needed for some hosts/router configurations, we're idle a lot */
+	/* Set Keepalive
+	 * Needed for some hosts/router configurations, we're idle a lot. */
 	sockopt.option = CAMEL_SOCKOPT_KEEPALIVE;
 	sockopt.value.keep_alive = TRUE;
-	camel_tcp_stream_setsockopt ((CamelTcpStream *) tcp_stream, &sockopt);
+	camel_tcp_stream_setsockopt (CAMEL_TCP_STREAM (tcp_stream), &sockopt);
+
+	imapx_stream = camel_imapx_stream_new (tcp_stream);
+
+	/* CamelIMAPXServer takes ownership of the IMAPX stream.
+	 * We need to set this right away for imapx_command_run()
+	 * to work, but we delay emitting a "notify" signal until
+	 * we're fully connected. */
+	g_mutex_lock (&is->priv->stream_lock);
+	g_warn_if_fail (is->priv->stream == NULL);
+	is->priv->stream = CAMEL_IMAPX_STREAM (imapx_stream);
+	g_mutex_unlock (&is->priv->stream_lock);
+
+	g_object_unref (tcp_stream);
 
  connected:
-	is->stream->tagprefix = is->tagprefix;
+	CAMEL_IMAPX_STREAM (imapx_stream)->tagprefix = is->tagprefix;
+
 	while (1) {
 		// poll ?  wait for other stuff? loop?
 		if (camel_application_is_exiting || is->parser_quit) {
@@ -3255,21 +3399,28 @@ imapx_connect_to_server (CamelIMAPXServer *is,
 			goto exit;
 		}
 
-		tok = camel_imapx_stream_token (is->stream, &token, &len, cancellable, error);
+		tok = camel_imapx_stream_token (
+			CAMEL_IMAPX_STREAM (imapx_stream),
+			&token, &len, cancellable, error);
 		if (tok < 0) {
 			success = FALSE;
 			goto exit;
 		}
 
 		if (tok == '*') {
-			imapx_untagged (is, cancellable, error);
+			imapx_untagged (
+				is, CAMEL_IMAPX_STREAM (imapx_stream),
+				cancellable, error);
 			break;
 		}
-		camel_imapx_stream_ungettoken (is->stream, tok, token, len);
-		if (camel_imapx_stream_text (is->stream, &token, cancellable, error)) {
-			success = FALSE;
+		camel_imapx_stream_ungettoken (
+			CAMEL_IMAPX_STREAM (imapx_stream), tok, token, len);
+
+		success = camel_imapx_stream_text (
+			CAMEL_IMAPX_STREAM (imapx_stream),
+			&token, cancellable, error);
+		if (!success)
 			goto exit;
-		}
 		e (is->tagprefix, "Got unexpected line before greeting:  '%s'\n", token);
 		g_free (token);
 	}
@@ -3362,16 +3513,20 @@ imapx_connect_to_server (CamelIMAPXServer *is,
 	}
 
 exit:
-	if (!success) {
-		if (is->stream != NULL) {
-			g_object_unref (is->stream);
-			is->stream = NULL;
-		}
+	if (success) {
+		g_object_notify (G_OBJECT (is), "stream");
+	} else {
+		g_mutex_lock (&is->priv->stream_lock);
+
+		g_object_unref (is->priv->stream);
+		is->priv->stream = NULL;
 
 		if (is->cinfo != NULL) {
 			imapx_free_capability (is->cinfo);
 			is->cinfo = NULL;
 		}
+
+		g_mutex_unlock (&is->priv->stream_lock);
 	}
 
 	g_free (host);
@@ -5763,9 +5918,16 @@ parse_contents (CamelIMAPXServer *is,
                 GCancellable *cancellable,
                 GError **error)
 {
+	CamelIMAPXStream *stream;
+
+	stream = camel_imapx_server_ref_stream (is);
+	g_return_if_fail (stream != NULL);
+
 	while (imapx_step (is, cancellable, error))
-		if (camel_imapx_stream_buffered (is->stream) == 0)
+		if (camel_imapx_stream_buffered (stream) == 0)
 			break;
+
+	g_object_unref (stream);
 }
 
 /*
@@ -5779,7 +5941,9 @@ static gpointer
 imapx_parser_thread (gpointer d)
 {
 	CamelIMAPXServer *is = d;
+	CamelIMAPXStream *stream;
 	GCancellable *cancellable;
+	gboolean have_stream;
 	GError *local_error = NULL;
 
 	QUEUE_LOCK (is);
@@ -5787,7 +5951,19 @@ imapx_parser_thread (gpointer d)
 	is->cancellable = g_object_ref (cancellable);
 	QUEUE_UNLOCK (is);
 
-	while (local_error == NULL && is->stream) {
+	stream = camel_imapx_server_ref_stream (is);
+	if (stream != NULL) {
+		have_stream = TRUE;
+		g_object_unref (stream);
+	} else {
+		have_stream = FALSE;
+	}
+
+	/* FIXME This should really be a GMainLoop instead of a 'while' loop.
+	 *       Testing for a stream on each loop iteration is pretty hokey.
+	 *       Disconnecting the stream could just terminate the parser
+	 *       thread's main loop. */
+	while (local_error == NULL && have_stream) {
 		g_cancellable_reset (cancellable);
 
 #ifndef G_OS_WIN32
@@ -5796,7 +5972,8 @@ imapx_parser_thread (gpointer d)
 			CamelStream *source;
 			gint res;
 
-			source = camel_imapx_stream_ref_source (is->stream);
+			stream = camel_imapx_server_ref_stream (is);
+			source = camel_imapx_stream_ref_source (stream);
 
 			fds[0].fd = CAMEL_STREAM_PROCESS (source)->sockfd;
 			fds[0].events = G_IO_IN;
@@ -5812,6 +5989,7 @@ imapx_parser_thread (gpointer d)
 			g_cancellable_release_fd (cancellable);
 
 			g_object_unref (source);
+			g_object_unref (stream);
 		} else
 #endif
 		{
@@ -5839,6 +6017,14 @@ imapx_parser_thread (gpointer d)
 		/* Jump out of the loop if an error occurred. */
 		if (local_error != NULL)
 			break;
+
+		stream = camel_imapx_server_ref_stream (is);
+		if (stream != NULL) {
+			have_stream = TRUE;
+			g_object_unref (stream);
+		} else {
+			have_stream = FALSE;
+		}
 	}
 
 	QUEUE_LOCK (is);
@@ -5871,6 +6057,24 @@ join_helper (gpointer thread)
 }
 
 static void
+imapx_server_get_property (GObject *object,
+                           guint property_id,
+                           GValue *value,
+                           GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_STREAM:
+			g_value_take_object (
+				value,
+				camel_imapx_server_ref_stream (
+				CAMEL_IMAPX_SERVER (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
 imapx_server_dispose (GObject *object)
 {
 	CamelIMAPXServer *server = CAMEL_IMAPX_SERVER (object);
@@ -5914,6 +6118,8 @@ imapx_server_finalize (GObject *object)
 {
 	CamelIMAPXServer *is = CAMEL_IMAPX_SERVER (object);
 
+	g_mutex_clear (&is->priv->stream_lock);
+
 	camel_imapx_command_queue_free (is->queue);
 	camel_imapx_command_queue_free (is->active);
 	camel_imapx_command_queue_free (is->done);
@@ -5959,13 +6165,25 @@ camel_imapx_server_class_init (CamelIMAPXServerClass *class)
 	g_type_class_add_private (class, sizeof (CamelIMAPXServerPrivate));
 
 	object_class = G_OBJECT_CLASS (class);
+	object_class->get_property = imapx_server_get_property;
 	object_class->finalize = imapx_server_finalize;
-	object_class->constructed = imapx_server_constructed;
 	object_class->dispose = imapx_server_dispose;
+	object_class->constructed = imapx_server_constructed;
 
 	class->select_changed = NULL;
 	class->shutdown = NULL;
 
+	g_object_class_install_property (
+		object_class,
+		PROP_STREAM,
+		g_param_spec_object (
+			"stream",
+			"Stream",
+			"IMAP network stream",
+			CAMEL_TYPE_IMAPX_STREAM,
+			G_PARAM_READABLE |
+			G_PARAM_STATIC_STRINGS));
+
 	/**
 	 * CamelIMAPXServer::select_changed
 	 * @server: the #CamelIMAPXServer which emitted the signal
@@ -6002,6 +6220,8 @@ camel_imapx_server_init (CamelIMAPXServer *is)
 
 	is->priv->untagged_handlers = create_initial_untagged_handler_table ();
 
+	g_mutex_init (&is->priv->stream_lock);
+
 	is->queue = camel_imapx_command_queue_new ();
 	is->active = camel_imapx_command_queue_new ();
 	is->done = camel_imapx_command_queue_new ();
@@ -6041,6 +6261,23 @@ camel_imapx_server_new (CamelStore *store)
 	return is;
 }
 
+CamelIMAPXStream *
+camel_imapx_server_ref_stream (CamelIMAPXServer *server)
+{
+	CamelIMAPXStream *stream = NULL;
+
+	g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (server), NULL);
+
+	g_mutex_lock (&server->priv->stream_lock);
+
+	if (server->priv->stream != NULL)
+		stream = g_object_ref (server->priv->stream);
+
+	g_mutex_unlock (&server->priv->stream_lock);
+
+	return stream;
+}
+
 static gboolean
 imapx_disconnect (CamelIMAPXServer *is)
 {
@@ -6048,16 +6285,20 @@ imapx_disconnect (CamelIMAPXServer *is)
 
 	g_static_rec_mutex_lock (&is->ostream_lock);
 
-	if (is->stream) {
-		CamelStream *stream = CAMEL_STREAM (is->stream);
+	g_mutex_lock (&is->priv->stream_lock);
+
+	if (is->priv->stream != NULL) {
+		CamelStream *stream = CAMEL_STREAM (is->priv->stream);
 
 		if (camel_stream_close (stream, NULL, NULL) == -1)
 			ret = FALSE;
 
-		g_object_unref (is->stream);
-		is->stream = NULL;
+		g_object_unref (is->priv->stream);
+		is->priv->stream = NULL;
 	}
 
+	g_mutex_unlock (&is->priv->stream_lock);
+
 	/* TODO need a select lock */
 	if (is->select_folder) {
 		g_object_unref (is->select_folder);
@@ -6078,6 +6319,8 @@ imapx_disconnect (CamelIMAPXServer *is)
 
 	g_static_rec_mutex_unlock (&is->ostream_lock);
 
+	g_object_notify (G_OBJECT (is), "stream");
+
 	return ret;
 }
 
diff --git a/camel/camel-imapx-server.h b/camel/camel-imapx-server.h
index 42d56a5..631374c 100644
--- a/camel/camel-imapx-server.h
+++ b/camel/camel-imapx-server.h
@@ -63,9 +63,12 @@ typedef struct _CamelIMAPXIdle CamelIMAPXIdle;
 struct _IMAPXJobQueueInfo;
 
 /* untagged response handling */
-typedef gboolean (*CamelIMAPXUntaggedRespHandler) (CamelIMAPXServer *server,
-                                                   GCancellable *cancellable,
-                                                   GError **error);
+typedef gboolean
+		(*CamelIMAPXUntaggedRespHandler)
+						(CamelIMAPXServer *server,
+						 CamelIMAPXStream *stream,
+						 GCancellable *cancellable,
+						 GError **error);
 
 /**
  * CamelIMAPXUntaggedRespHandlerDesc:
@@ -105,7 +108,6 @@ struct _CamelIMAPXServer {
 	CamelSession *session;
 
 	/* Info about the current connection */
-	CamelIMAPXStream *stream;
 	struct _capability_info *cinfo;
 	gboolean is_process_stream;
 
@@ -179,6 +181,8 @@ struct _CamelIMAPXServerClass {
 GType		camel_imapx_server_get_type	(void);
 CamelIMAPXServer *
 		camel_imapx_server_new		(CamelStore *store);
+CamelIMAPXStream *
+		camel_imapx_server_ref_stream	(CamelIMAPXServer *is);
 gboolean	camel_imapx_server_connect	(CamelIMAPXServer *is,
 						 GCancellable *cancellable,
 						 GError **error);
diff --git a/camel/camel-imapx-store.c b/camel/camel-imapx-store.c
index 88b340a..93ba88a 100644
--- a/camel/camel-imapx-store.c
+++ b/camel/camel-imapx-store.c
@@ -265,8 +265,9 @@ imapx_query_auth_types_sync (CamelService *service,
 	CamelIMAPXStore *istore = CAMEL_IMAPX_STORE (service);
 	CamelServiceAuthType *authtype;
 	GList *sasl_types, *t, *next;
-	gboolean connected;
 	CamelIMAPXServer *server;
+	CamelIMAPXStream *stream;
+	gboolean connected;
 
 	if (!camel_offline_store_get_online (CAMEL_OFFLINE_STORE (istore))) {
 		g_set_error (
@@ -278,9 +279,15 @@ imapx_query_auth_types_sync (CamelService *service,
 
 	server = camel_imapx_server_new (CAMEL_STORE (istore));
 
-	connected = server->stream != NULL;
-	if (!connected)
-		connected = imapx_connect_to_server (server, cancellable, error);
+	stream = camel_imapx_server_ref_stream (server);
+	if (stream != NULL) {
+		connected = TRUE;
+		g_object_unref (stream);
+	} else {
+		connected = imapx_connect_to_server (
+			server, cancellable, error);
+	}
+
 	if (!connected)
 		return NULL;
 
diff --git a/docs/reference/camel/camel-sections.txt b/docs/reference/camel/camel-sections.txt
index e18400a..098b94a 100644
--- a/docs/reference/camel/camel-sections.txt
+++ b/docs/reference/camel/camel-sections.txt
@@ -832,6 +832,7 @@ uidset_state
 <TITLE>CamelIMAPXServer</TITLE>
 CamelIMAPXServer
 camel_imapx_server_new
+camel_imapx_server_ref_stream
 camel_imapx_server_connect
 camel_imapx_server_authenticate
 camel_imapx_server_list



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