[evolution-data-server/gnome-3-6] Bug #680497 - POP3 re-adds messages to local Inbox



commit 2b8c404fd91eda2bb4335ef7a2019e2fa1374ee1
Author: Milan Crha <mcrha redhat com>
Date:   Thu Oct 25 12:02:42 2012 +0200

    Bug #680497 - POP3 re-adds messages to local Inbox

 camel/providers/pop3/camel-pop3-engine.c |   58 +++++++++++++++++---------
 camel/providers/pop3/camel-pop3-engine.h |   10 +++-
 camel/providers/pop3/camel-pop3-folder.c |   66 ++++++++++++++++++++++--------
 camel/providers/pop3/camel-pop3-store.c  |   22 +++++++---
 4 files changed, 110 insertions(+), 46 deletions(-)
---
diff --git a/camel/providers/pop3/camel-pop3-engine.c b/camel/providers/pop3/camel-pop3-engine.c
index 916fa95..7ee2843 100644
--- a/camel/providers/pop3/camel-pop3-engine.c
+++ b/camel/providers/pop3/camel-pop3-engine.c
@@ -41,7 +41,7 @@ extern CamelServiceAuthType camel_pop3_apop_authtype;
 
 #define dd(x) (camel_debug ("pop3")?(x):0)
 
-static void get_capabilities (CamelPOP3Engine *pe, GCancellable *cancellable);
+static gboolean get_capabilities (CamelPOP3Engine *pe, GCancellable *cancellable, GError **error);
 
 G_DEFINE_TYPE (CamelPOP3Engine, camel_pop3_engine, CAMEL_TYPE_OBJECT)
 
@@ -124,6 +124,7 @@ read_greeting (CamelPOP3Engine *pe,
  * @source: source stream
  * @flags: engine flags
  * @cancellable: optional #GCancellable object, or %NULL
+ * @error: optional #GError, or %NULL
  *
  * Returns a NULL stream.  A null stream is always at eof, and
  * always returns success for all reads and writes.
@@ -133,7 +134,8 @@ read_greeting (CamelPOP3Engine *pe,
 CamelPOP3Engine *
 camel_pop3_engine_new (CamelStream *source,
                        guint32 flags,
-                       GCancellable *cancellable)
+                       GCancellable *cancellable,
+		       GError **error)
 {
 	CamelPOP3Engine *pe;
 
@@ -143,13 +145,12 @@ camel_pop3_engine_new (CamelStream *source,
 	pe->state = CAMEL_POP3_ENGINE_AUTH;
 	pe->flags = flags;
 
-	if (read_greeting (pe, cancellable) == -1) {
+	if (read_greeting (pe, cancellable) == -1 ||
+	    !get_capabilities (pe, cancellable, error)) {
 		g_object_unref (pe);
 		return NULL;
 	}
 
-	get_capabilities (pe, cancellable);
-
 	return pe;
 }
 
@@ -157,16 +158,18 @@ camel_pop3_engine_new (CamelStream *source,
  * camel_pop3_engine_reget_capabilities:
  * @engine: pop3 engine
  * @cancellable: optional #GCancellable object, or %NULL
+ * @error: optional #GError, or %NULL
  *
  * Regets server capabilities (needed after a STLS command is issued for example).
  **/
-void
+gboolean
 camel_pop3_engine_reget_capabilities (CamelPOP3Engine *engine,
-                                      GCancellable *cancellable)
+                                      GCancellable *cancellable,
+				      GError **error)
 {
-	g_return_if_fail (CAMEL_IS_POP3_ENGINE (engine));
+	g_return_val_if_fail (CAMEL_IS_POP3_ENGINE (engine), FALSE);
 
-	get_capabilities (engine, cancellable);
+	return get_capabilities (engine, cancellable, error);
 }
 
 /* TODO: read implementation too?
@@ -186,6 +189,7 @@ static void
 cmd_capa (CamelPOP3Engine *pe,
           CamelPOP3Stream *stream,
           GCancellable *cancellable,
+	  GError **error,
           gpointer data)
 {
 	guchar *line, *tok, *next;
@@ -199,7 +203,7 @@ cmd_capa (CamelPOP3Engine *pe,
 	g_return_if_fail (pe != NULL);
 
 	do {
-		ret = camel_pop3_stream_line (stream, &line, &len, cancellable, NULL);
+		ret = camel_pop3_stream_line (stream, &line, &len, cancellable, error);
 		if (ret >= 0) {
 			if (strncmp ((gchar *) line, "SASL ", 5) == 0) {
 				tok = line + 5;
@@ -227,13 +231,15 @@ cmd_capa (CamelPOP3Engine *pe,
 	} while (ret > 0);
 }
 
-static void
+static gboolean
 get_capabilities (CamelPOP3Engine *pe,
-                  GCancellable *cancellable)
+                  GCancellable *cancellable,
+		  GError **error)
 {
 	CamelPOP3Command *pc;
+	GError *local_error = NULL;
 
-	g_return_if_fail (pe != NULL);
+	g_return_val_if_fail (pe != NULL, FALSE);
 
 	if (!(pe->flags & CAMEL_POP3_ENGINE_DISABLE_EXTENSIONS)) {
 		pc = camel_pop3_engine_command_new (pe, CAMEL_POP3_COMMAND_MULTI, cmd_capa, NULL, cancellable, NULL, "CAPA\r\n");
@@ -243,8 +249,8 @@ get_capabilities (CamelPOP3Engine *pe,
 
 		if (pe->state == CAMEL_POP3_ENGINE_TRANSACTION && !(pe->capa & CAMEL_POP3_CAP_UIDL)) {
 			/* check for UIDL support manually */
-			pc = camel_pop3_engine_command_new (pe, CAMEL_POP3_COMMAND_SIMPLE, NULL, NULL, cancellable, NULL, "UIDL 1\r\n");
-			while (camel_pop3_engine_iterate (pe, pc, cancellable, NULL) > 0)
+			pc = camel_pop3_engine_command_new (pe, CAMEL_POP3_COMMAND_SIMPLE, NULL, NULL, cancellable, &local_error, "UIDL 1\r\n");
+			while (camel_pop3_engine_iterate (pe, pc, cancellable, &local_error) > 0)
 				;
 
 			if (pc->state == CAMEL_POP3_COMMAND_OK)
@@ -253,6 +259,13 @@ get_capabilities (CamelPOP3Engine *pe,
 			camel_pop3_engine_command_free (pe, pc);
 		}
 	}
+
+	if (local_error) {
+		g_propagate_error (error, local_error);
+		return FALSE;
+	}
+
+	return TRUE;
 }
 
 /* returns true if the command was sent, false if it was just queued */
@@ -324,23 +337,28 @@ camel_pop3_engine_iterate (CamelPOP3Engine *pe,
 			camel_pop3_stream_set_mode (pe->stream, CAMEL_POP3_STREAM_DATA);
 
 			if (pc->func)
-				pc->func (pe, pe->stream, cancellable, pc->func_data);
+				pc->func (pe, pe->stream, cancellable, error, pc->func_data);
 
 			/* Make sure we get all data before going back to command mode */
-			while (camel_pop3_stream_getd (pe->stream, &p, &len, cancellable, NULL) > 0)
+			while (camel_pop3_stream_getd (pe->stream, &p, &len, cancellable, error) > 0)
 				;
 			camel_pop3_stream_set_mode (pe->stream, CAMEL_POP3_STREAM_LINE);
 		} else {
 			pc->state = CAMEL_POP3_COMMAND_OK;
 		}
 		break;
-	case '-':
+	case '-': {
+		const gchar *text = (const gchar *) p;
+
 		pc->state = CAMEL_POP3_COMMAND_ERR;
+		pc->error_str = g_strdup (g_ascii_strncasecmp (text, "-ERR ", 5) == 0 ? text + 5 : text + 1);
+		}
 		break;
 	default:
 		/* what do we do now?  f'knows! */
 		g_warning ("Bad server response: %s\n", p);
 		pc->state = CAMEL_POP3_COMMAND_ERR;
+		pc->error_str = g_strdup ((const gchar *) p + 1);
 		break;
 	}
 
@@ -360,7 +378,7 @@ camel_pop3_engine_iterate (CamelPOP3Engine *pe,
 		    && pe->current != NULL)
 			break;
 
-		if (camel_stream_write ((CamelStream *) pe->stream, pc->data, strlen (pc->data), cancellable, NULL) == -1)
+		if (camel_stream_write ((CamelStream *) pe->stream, pc->data, strlen (pc->data), cancellable, error) == -1)
 			goto ioerror;
 
 		pe->sentlen += strlen (pc->data);
@@ -428,6 +446,7 @@ camel_pop3_engine_command_new (CamelPOP3Engine *pe,
 	pc->data = g_strdup_vprintf (fmt, ap);
 	va_end (ap);
 	pc->state = CAMEL_POP3_COMMAND_IDLE;
+	pc->error_str = NULL;
 
 	/* TODO: what about write errors? */
 	engine_command_queue (pe, pc, cancellable, error);
@@ -441,6 +460,7 @@ camel_pop3_engine_command_free (CamelPOP3Engine *pe,
 {
 	if (pe && pe->current != pc)
 		g_queue_remove (&pe->done, pc);
+	g_free (pc->error_str);
 	g_free (pc->data);
 	g_free (pc);
 }
diff --git a/camel/providers/pop3/camel-pop3-engine.h b/camel/providers/pop3/camel-pop3-engine.h
index 35ba1c7..cc58001 100644
--- a/camel/providers/pop3/camel-pop3-engine.h
+++ b/camel/providers/pop3/camel-pop3-engine.h
@@ -94,11 +94,13 @@ enum {
 typedef void	(*CamelPOP3CommandFunc)		(CamelPOP3Engine *pe,
 						 CamelPOP3Stream *stream,
 						 GCancellable *cancellable,
+						 GError **error,
 						 gpointer data);
 
 struct _CamelPOP3Command {
 	guint32 flags;
 	camel_pop3_command_t state;
+	gchar *error_str;
 
 	CamelPOP3CommandFunc func;
 	gpointer func_data;
@@ -141,10 +143,12 @@ GType		camel_pop3_engine_get_type	(void);
 CamelPOP3Engine *
 		camel_pop3_engine_new		(CamelStream *source,
 						 guint32 flags,
-						 GCancellable *cancellable);
-void		camel_pop3_engine_reget_capabilities
+						 GCancellable *cancellable,
+						 GError **error);
+gboolean	camel_pop3_engine_reget_capabilities
 						(CamelPOP3Engine *engine,
-						 GCancellable *cancellable);
+						 GCancellable *cancellable,
+						 GError **error);
 void		camel_pop3_engine_command_free	(CamelPOP3Engine *pe,
 						 CamelPOP3Command *pc);
 gint		camel_pop3_engine_iterate	(CamelPOP3Engine *pe,
diff --git a/camel/providers/pop3/camel-pop3-folder.c b/camel/providers/pop3/camel-pop3-folder.c
index 6eb6398..4c0a407 100644
--- a/camel/providers/pop3/camel-pop3-folder.c
+++ b/camel/providers/pop3/camel-pop3-folder.c
@@ -63,6 +63,7 @@ static void
 cmd_uidl (CamelPOP3Engine *pe,
           CamelPOP3Stream *stream,
           GCancellable *cancellable,
+	  GError **error,
           gpointer data)
 {
 	gint ret;
@@ -74,7 +75,7 @@ cmd_uidl (CamelPOP3Engine *pe,
 	CamelPOP3Folder *folder = data;
 
 	do {
-		ret = camel_pop3_stream_line (stream, &line, &len, cancellable, NULL);
+		ret = camel_pop3_stream_line (stream, &line, &len, cancellable, error);
 		if (ret >= 0) {
 			if (strlen ((gchar *) line) > 1024)
 				line[1024] = 0;
@@ -97,6 +98,7 @@ static void
 cmd_builduid (CamelPOP3Engine *pe,
               CamelPOP3Stream *stream,
               GCancellable *cancellable,
+	      GError **error,
               gpointer data)
 {
 	GChecksum *checksum;
@@ -145,6 +147,7 @@ static void
 cmd_list (CamelPOP3Engine *pe,
           CamelPOP3Stream *stream,
           GCancellable *cancellable,
+	  GError **error,
           gpointer data)
 {
 	gint ret;
@@ -173,7 +176,7 @@ cmd_list (CamelPOP3Engine *pe,
 	g_object_unref (settings);
 
 	do {
-		ret = camel_pop3_stream_line (stream, &line, &len, cancellable, NULL);
+		ret = camel_pop3_stream_line (stream, &line, &len, cancellable, error);
 		if (ret >= 0) {
 			if (sscanf ((gchar *) line, "%u %u", &id, &size) == 2) {
 				fi = g_malloc0 (sizeof (*fi));
@@ -185,7 +188,7 @@ cmd_list (CamelPOP3Engine *pe,
 						pe,
 						CAMEL_POP3_COMMAND_MULTI,
 						cmd_builduid, fi,
-						cancellable, NULL,
+						cancellable, error,
 						"TOP %u 0\r\n", id);
 				g_ptr_array_add (pop3_folder->uids, fi);
 				g_hash_table_insert (
@@ -319,22 +322,23 @@ static void
 cmd_tocache (CamelPOP3Engine *pe,
              CamelPOP3Stream *stream,
              GCancellable *cancellable,
+	     GError **error,
              gpointer data)
 {
 	CamelPOP3FolderInfo *fi = data;
 	gchar buffer[2048];
 	gint w = 0, n;
-	GError *error = NULL;
+	GError *local_error = NULL;
 
 	/* What if it fails? */
 
 	/* We write an '*' to the start of the stream to say its not complete yet */
 	/* This should probably be part of the cache code */
-	if ((n = camel_stream_write (fi->stream, "*", 1, cancellable, &error)) == -1)
+	if ((n = camel_stream_write (fi->stream, "*", 1, cancellable, &local_error)) == -1)
 		goto done;
 
-	while ((n = camel_stream_read ((CamelStream *) stream, buffer, sizeof (buffer), cancellable, &error)) > 0) {
-		n = camel_stream_write (fi->stream, buffer, n, cancellable, &error);
+	while ((n = camel_stream_read ((CamelStream *) stream, buffer, sizeof (buffer), cancellable, &local_error)) > 0) {
+		n = camel_stream_write (fi->stream, buffer, n, cancellable, &local_error);
 		if (n == -1)
 			break;
 
@@ -346,17 +350,16 @@ cmd_tocache (CamelPOP3Engine *pe,
 	}
 
 	/* it all worked, output a '#' to say we're a-ok */
-	if (error == NULL) {
+	if (local_error == NULL) {
 		g_seekable_seek (
 			G_SEEKABLE (fi->stream),
 			0, G_SEEK_SET, cancellable, NULL);
-		camel_stream_write (fi->stream, "#", 1, cancellable, &error);
+		camel_stream_write (fi->stream, "#", 1, cancellable, &local_error);
 	}
 
 done:
-	if (error != NULL) {
-		g_warning ("POP3 retrieval failed: %s", error->message);
-		g_error_free (error);
+	if (local_error != NULL) {
+		g_propagate_error (error, local_error);
 	}
 
 	g_object_unref (fi->stream);
@@ -574,7 +577,7 @@ pop3_folder_get_message_sync (CamelFolder *folder,
 			pop3_store->engine,
 			CAMEL_POP3_COMMAND_MULTI,
 			cmd_tocache, fi,
-			cancellable, NULL,
+			cancellable, error,
 			"RETR %u\r\n", fi->id);
 
 		/* Also initiate retrieval of some of the following
@@ -597,7 +600,7 @@ pop3_folder_get_message_sync (CamelFolder *folder,
 							pop3_store->engine,
 							CAMEL_POP3_COMMAND_MULTI,
 							cmd_tocache, pfi,
-							cancellable, NULL,
+							cancellable, error,
 							"RETR %u\r\n", pfi->id);
 					}
 				}
@@ -730,28 +733,57 @@ pop3_folder_refresh_info_sync (CamelFolder *folder,
 			cmd_uidl, folder,
 			cancellable, &local_error,
 			"UIDL\r\n");
-	while ((i = camel_pop3_engine_iterate (pop3_store->engine, NULL, cancellable, error)) > 0)
+	while ((i = camel_pop3_engine_iterate (pop3_store->engine, NULL, cancellable, &local_error)) > 0)
 		;
 
 	if (local_error) {
 		g_propagate_error (error, local_error);
+		g_prefix_error (error, _("Cannot get POP summary: "));
 		success = FALSE;
 	} else if (i == -1) {
-		g_prefix_error (error, _("Cannot get POP summary: "));
+		g_set_error_literal (error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("Cannot get POP summary: "));
 		success = FALSE;
 	}
 
 	/* TODO: check every id has a uid & commands returned OK too? */
 
-	if (pcl)
+	if (pcl) {
+		if (success && pcl->state == CAMEL_POP3_COMMAND_ERR) {
+			success = FALSE;
+
+			if (pcl->error_str)
+				g_set_error_literal (error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, pcl->error_str);
+			else
+				g_set_error_literal (error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("Cannot get POP summary: "));
+		}
+
 		camel_pop3_engine_command_free (pop3_store->engine, pcl);
+	}
 
 	if (pcu) {
+		if (success && pcu->state == CAMEL_POP3_COMMAND_ERR) {
+			success = FALSE;
+
+			if (pcu->error_str)
+				g_set_error_literal (error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, pcu->error_str);
+			else
+				g_set_error_literal (error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("Cannot get POP summary: "));
+		}
+
 		camel_pop3_engine_command_free (pop3_store->engine, pcu);
 	} else {
 		for (i = 0; i < pop3_folder->uids->len; i++) {
 			CamelPOP3FolderInfo *fi = pop3_folder->uids->pdata[i];
 			if (fi->cmd) {
+				if (success && fi->cmd->state == CAMEL_POP3_COMMAND_ERR) {
+					success = FALSE;
+
+					if (fi->cmd->error_str)
+						g_set_error_literal (error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, fi->cmd->error_str);
+					else
+						g_set_error_literal (error, CAMEL_ERROR, CAMEL_ERROR_GENERIC, _("Cannot get POP summary: "));
+				}
+
 				camel_pop3_engine_command_free (pop3_store->engine, fi->cmd);
 				fi->cmd = NULL;
 			}
diff --git a/camel/providers/pop3/camel-pop3-store.c b/camel/providers/pop3/camel-pop3-store.c
index f721668..187d2e5 100644
--- a/camel/providers/pop3/camel-pop3-store.c
+++ b/camel/providers/pop3/camel-pop3-store.c
@@ -102,6 +102,7 @@ connect_to_server (CamelService *service,
 	gchar *host;
 	guint32 flags = 0;
 	gint ret;
+	GError *local_error = NULL;
 
 	settings = camel_service_ref_settings (service);
 
@@ -133,11 +134,15 @@ connect_to_server (CamelService *service,
 	if (disable_extensions)
 		flags |= CAMEL_POP3_ENGINE_DISABLE_EXTENSIONS;
 
-	if (!(store->engine = camel_pop3_engine_new (tcp_stream, flags, cancellable))) {
-		g_set_error (
-			error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
-			_("Failed to read a valid greeting from POP server %s"),
-			host);
+	if (!(store->engine = camel_pop3_engine_new (tcp_stream, flags, cancellable, &local_error)) ||
+	    local_error != NULL) {
+		if (local_error)
+			g_propagate_error (error, local_error);
+		else
+			g_set_error (
+				error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
+				_("Failed to read a valid greeting from POP server %s"),
+				host);
 		g_object_unref (tcp_stream);
 		success = FALSE;
 		goto exit;
@@ -195,7 +200,8 @@ connect_to_server (CamelService *service,
 
 	/* rfc2595, section 4 states that after a successful STLS
 	 * command, the client MUST discard prior CAPA responses */
-	camel_pop3_engine_reget_capabilities (store->engine, cancellable);
+	if (!camel_pop3_engine_reget_capabilities (store->engine, cancellable, error))
+		goto exception;
 
 	goto exit;
 
@@ -212,6 +218,7 @@ stls_exception:
 		camel_pop3_engine_command_free (store->engine, pc);
 	}*/
 
+ exception:
 	g_object_unref (store->engine);
 	g_object_unref (tcp_stream);
 	store->engine = NULL;
@@ -446,7 +453,8 @@ pop3_store_connect_sync (CamelService *service,
 	/* Now that we are in the TRANSACTION state,
 	 * try regetting the capabilities */
 	store->engine->state = CAMEL_POP3_ENGINE_TRANSACTION;
-	camel_pop3_engine_reget_capabilities (store->engine, cancellable);
+	if (!camel_pop3_engine_reget_capabilities (store->engine, cancellable, error))
+		success = FALSE;
 
 exit:
 	g_free (mechanism);



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