[evolution] EMailAutoconfig: Restructure XML parsing.



commit 6de9a0e56e9a6800e39a43cb04bc5e0045ff8790
Author: Matthew Barnes <mbarnes redhat com>
Date:   Thu Nov 8 12:53:09 2012 -0500

    EMailAutoconfig: Restructure XML parsing.
    
    If we get a hit from the online database, parse the XML immediately and
    store the results in generic internal structs.  Then when we're given an
    ESource to populate we can feed it the stored results instead of parsing
    the XML on demand (and repeatedly).
    
    What this is really doing is making room for other auto-configuration
    methods besides the online database lookup.

 mail/e-mail-autoconfig.c    |  388 ++++++++++++++++++++++++------------------
 mail/e-mail-autoconfig.h    |    3 +-
 mail/test-mail-autoconfig.c |    2 +-
 3 files changed, 224 insertions(+), 169 deletions(-)
---
diff --git a/mail/e-mail-autoconfig.c b/mail/e-mail-autoconfig.c
index aeebb0f..a9e9773 100644
--- a/mail/e-mail-autoconfig.c
+++ b/mail/e-mail-autoconfig.c
@@ -35,23 +35,29 @@
 #define ERROR_IS_NOT_FOUND(error) \
 	(g_error_matches ((error), SOUP_HTTP_ERROR, SOUP_STATUS_NOT_FOUND))
 
+typedef struct _EMailAutoconfigResult EMailAutoconfigResult;
 typedef struct _ParserClosure ParserClosure;
 
+struct _EMailAutoconfigResult {
+	gboolean set;
+	gchar *user;
+	gchar *host;
+	guint16 port;
+	CamelNetworkSecurityMethod security_method;
+};
+
 struct _EMailAutoconfigPrivate {
 	gchar *email_address;
 	gchar *email_local_part;
 	gchar *email_domain_part;
-	gchar *markup_content;
+	EMailAutoconfigResult imap_result;
+	EMailAutoconfigResult pop3_result;
+	EMailAutoconfigResult smtp_result;
 };
 
 struct _ParserClosure {
-	CamelNetworkSettings *network_settings;
-	const gchar *expected_type;
-	const gchar *email_address;
-	const gchar *email_local_part;
-	const gchar *email_domain_part;
-	gboolean in_server_element;
-	gboolean settings_modified;
+	EMailAutoconfig *autoconfig;
+	EMailAutoconfigResult *result;
 };
 
 enum {
@@ -73,90 +79,6 @@ G_DEFINE_TYPE_WITH_CODE (
 	G_IMPLEMENT_INTERFACE (
 		G_TYPE_ASYNC_INITABLE, NULL))
 
-static gchar *
-mail_autoconfig_resolve_name_server (const gchar *domain,
-                                     GCancellable *cancellable,
-                                     GError **error)
-{
-	GResolver *resolver;
-	GList *records;
-	gchar *name_server = NULL;
-
-	resolver = g_resolver_get_default ();
-
-	records = g_resolver_lookup_records (
-		resolver, domain, G_RESOLVER_RECORD_NS, cancellable, error);
-
-	/* This list is sorted per RFC 2782, so use the first item. */
-	if (records != NULL) {
-		GVariant *variant = records->data;
-		g_variant_get_child (variant, 0, "s", &name_server);
-	}
-
-	g_list_free_full (records, (GDestroyNotify) g_variant_unref);
-
-	g_object_unref (resolver);
-
-	return name_server;
-}
-
-static void
-mail_autoconfig_abort_soup_session_cb (GCancellable *cancellable,
-                                       SoupSession *soup_session)
-{
-	soup_session_abort (soup_session);
-}
-
-static gboolean
-mail_autoconfig_lookup (EMailAutoconfig *autoconfig,
-                        const gchar *domain,
-                        GCancellable *cancellable,
-                        GError **error)
-{
-	SoupMessage *soup_message;
-	SoupSession *soup_session;
-	gulong cancel_id = 0;
-	guint status;
-	gchar *uri;
-
-	soup_session = soup_session_sync_new ();
-
-	uri = g_strconcat (AUTOCONFIG_BASE_URI, domain, NULL);
-	soup_message = soup_message_new (SOUP_METHOD_GET, uri);
-	g_free (uri);
-
-	if (G_IS_CANCELLABLE (cancellable))
-		cancel_id = g_cancellable_connect (
-			cancellable,
-			G_CALLBACK (mail_autoconfig_abort_soup_session_cb),
-			g_object_ref (soup_session),
-			(GDestroyNotify) g_object_unref);
-
-	status = soup_session_send_message (soup_session, soup_message);
-
-	if (cancel_id > 0)
-		g_cancellable_disconnect (cancellable, cancel_id);
-
-	if (SOUP_STATUS_IS_SUCCESSFUL (status)) {
-
-		/* Just to make sure we don't leak. */
-		g_free (autoconfig->priv->markup_content);
-
-		autoconfig->priv->markup_content =
-			g_strdup (soup_message->response_body->data);
-	} else {
-		g_set_error_literal (
-			error, SOUP_HTTP_ERROR,
-			soup_message->status_code,
-			soup_message->reason_phrase);
-	}
-
-	g_object_unref (soup_message);
-	g_object_unref (soup_session);
-
-	return SOUP_STATUS_IS_SUCCESSFUL (status);
-}
-
 static void
 mail_autoconfig_parse_start_element (GMarkupParseContext *context,
                                      const gchar *element_name,
@@ -166,9 +88,12 @@ mail_autoconfig_parse_start_element (GMarkupParseContext *context,
                                      GError **error)
 {
 	ParserClosure *closure = user_data;
+	EMailAutoconfigPrivate *priv;
 	gboolean is_incoming_server;
 	gboolean is_outgoing_server;
 
+	priv = closure->autoconfig->priv;
+
 	is_incoming_server = g_str_equal (element_name, "incomingServer");
 	is_outgoing_server = g_str_equal (element_name, "outgoingServer");
 
@@ -184,8 +109,12 @@ mail_autoconfig_parse_start_element (GMarkupParseContext *context,
 			"type", &type,
 			G_MARKUP_COLLECT_INVALID);
 
-		closure->in_server_element =
-			(g_strcmp0 (type, closure->expected_type) == 0);
+		if (g_strcmp0 (type, "imap") == 0)
+			closure->result = &priv->imap_result;
+		if (g_strcmp0 (type, "pop3") == 0)
+			closure->result = &priv->pop3_result;
+		if (g_strcmp0 (type, "smtp") == 0)
+			closure->result = &priv->smtp_result;
 	}
 }
 
@@ -203,7 +132,7 @@ mail_autoconfig_parse_end_element (GMarkupParseContext *context,
 	is_outgoing_server = g_str_equal (element_name, "outgoingServer");
 
 	if (is_incoming_server || is_outgoing_server)
-		closure->in_server_element = FALSE;
+		closure->result = NULL;
 }
 
 static void
@@ -214,10 +143,13 @@ mail_autoconfig_parse_text (GMarkupParseContext *context,
                             GError **error)
 {
 	ParserClosure *closure = user_data;
+	EMailAutoconfigPrivate *priv;
 	const gchar *element_name;
 	GString *string;
 
-	if (!closure->in_server_element)
+	priv = closure->autoconfig->priv;
+
+	if (closure->result == NULL)
 		return;
 
 	/* Perform the following text substitutions:
@@ -242,7 +174,7 @@ mail_autoconfig_parse_text (GMarkupParseContext *context,
 			}
 
 			variable = "%EMAILADDRESS%";
-			substitute = closure->email_address;
+			substitute = priv->email_address;
 
 			if (strncmp (cp, variable, strlen (variable)) == 0) {
 				g_string_append (string, substitute);
@@ -251,7 +183,7 @@ mail_autoconfig_parse_text (GMarkupParseContext *context,
 			}
 
 			variable = "%EMAILLOCALPART%";
-			substitute = closure->email_local_part;
+			substitute = priv->email_local_part;
 
 			if (strncmp (cp, variable, strlen (variable)) == 0) {
 				g_string_append (string, substitute);
@@ -260,7 +192,7 @@ mail_autoconfig_parse_text (GMarkupParseContext *context,
 			}
 
 			variable = "%EMAILDOMAIN%";
-			substitute = closure->email_domain_part;
+			substitute = priv->email_domain_part;
 
 			if (strncmp (cp, variable, strlen (variable)) == 0) {
 				g_string_append (string, substitute);
@@ -275,39 +207,33 @@ mail_autoconfig_parse_text (GMarkupParseContext *context,
 	element_name = g_markup_parse_context_get_element (context);
 
 	if (g_str_equal (element_name, "hostname")) {
-		camel_network_settings_set_host (
-			closure->network_settings, string->str);
-		closure->settings_modified = TRUE;
+		closure->result->host = g_strdup (string->str);
+		closure->result->set = TRUE;
 
 	} else if (g_str_equal (element_name, "username")) {
-		camel_network_settings_set_user (
-			closure->network_settings, string->str);
-		closure->settings_modified = TRUE;
+		closure->result->user = g_strdup (string->str);
+		closure->result->set = TRUE;
 
 	} else if (g_str_equal (element_name, "port")) {
 		glong port = strtol (string->str, NULL, 10);
 		if (port == CLAMP (port, 1, G_MAXUINT16)) {
-			camel_network_settings_set_port (
-				closure->network_settings, (guint16) port);
-			closure->settings_modified = TRUE;
+			closure->result->port = (guint16) port;
+			closure->result->set = TRUE;
 		}
 
 	} else if (g_str_equal (element_name, "socketType")) {
 		if (g_str_equal (string->str, "plain")) {
-			camel_network_settings_set_security_method (
-				closure->network_settings,
-				CAMEL_NETWORK_SECURITY_METHOD_NONE);
-			closure->settings_modified = TRUE;
+			closure->result->security_method =
+				CAMEL_NETWORK_SECURITY_METHOD_NONE;
+			closure->result->set = TRUE;
 		} else if (g_str_equal (string->str, "SSL")) {
-			camel_network_settings_set_security_method (
-				closure->network_settings,
-				CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT);
-			closure->settings_modified = TRUE;
+			closure->result->security_method =
+				CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT;
+			closure->result->set = TRUE;
 		} else if (g_str_equal (string->str, "STARTTLS")) {
-			camel_network_settings_set_security_method (
-				closure->network_settings,
-				CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT);
-			closure->settings_modified = TRUE;
+			closure->result->security_method =
+				CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT;
+			closure->result->set = TRUE;
 		}
 	}
 
@@ -323,20 +249,123 @@ static GMarkupParser mail_autoconfig_parser = {
 	mail_autoconfig_parse_text
 };
 
+static gchar *
+mail_autoconfig_resolve_name_server (const gchar *domain,
+                                     GCancellable *cancellable,
+                                     GError **error)
+{
+	GResolver *resolver;
+	GList *records;
+	gchar *name_server = NULL;
+
+	resolver = g_resolver_get_default ();
+
+	records = g_resolver_lookup_records (
+		resolver, domain, G_RESOLVER_RECORD_NS, cancellable, error);
+
+	/* This list is sorted per RFC 2782, so use the first item. */
+	if (records != NULL) {
+		GVariant *variant = records->data;
+		g_variant_get_child (variant, 0, "s", &name_server);
+	}
+
+	g_list_free_full (records, (GDestroyNotify) g_variant_unref);
+
+	g_object_unref (resolver);
+
+	return name_server;
+}
+
+static void
+mail_autoconfig_abort_soup_session_cb (GCancellable *cancellable,
+                                       SoupSession *soup_session)
+{
+	soup_session_abort (soup_session);
+}
+
+static gboolean
+mail_autoconfig_lookup (EMailAutoconfig *autoconfig,
+                        const gchar *domain,
+                        GCancellable *cancellable,
+                        GError **error)
+{
+	GMarkupParseContext *context;
+	SoupMessage *soup_message;
+	SoupSession *soup_session;
+	ParserClosure closure;
+	gulong cancel_id = 0;
+	gboolean success;
+	guint status;
+	gchar *uri;
+
+	soup_session = soup_session_sync_new ();
+
+	uri = g_strconcat (AUTOCONFIG_BASE_URI, domain, NULL);
+	soup_message = soup_message_new (SOUP_METHOD_GET, uri);
+	g_free (uri);
+
+	if (G_IS_CANCELLABLE (cancellable))
+		cancel_id = g_cancellable_connect (
+			cancellable,
+			G_CALLBACK (mail_autoconfig_abort_soup_session_cb),
+			g_object_ref (soup_session),
+			(GDestroyNotify) g_object_unref);
+
+	status = soup_session_send_message (soup_session, soup_message);
+
+	if (cancel_id > 0)
+		g_cancellable_disconnect (cancellable, cancel_id);
+
+	success = SOUP_STATUS_IS_SUCCESSFUL (status);
+
+	if (!success) {
+		g_set_error_literal (
+			error, SOUP_HTTP_ERROR,
+			soup_message->status_code,
+			soup_message->reason_phrase);
+		goto exit;
+	}
+
+	closure.autoconfig = autoconfig;
+	closure.result = NULL;
+
+	context = g_markup_parse_context_new (
+		&mail_autoconfig_parser, 0,
+		&closure, (GDestroyNotify) NULL);
+
+	success = g_markup_parse_context_parse (
+		context,
+		soup_message->response_body->data,
+		soup_message->response_body->length,
+		error);
+
+	if (success)
+		success = g_markup_parse_context_end_parse (context, error);
+
+	g_markup_parse_context_free (context);
+
+exit:
+	g_object_unref (soup_message);
+	g_object_unref (soup_session);
+
+	return success;
+}
+
 static gboolean
 mail_autoconfig_set_details (EMailAutoconfig *autoconfig,
-                             const gchar *expected_type,
+                             EMailAutoconfigResult *result,
                              ESource *source,
                              const gchar *extension_name)
 {
-	GMarkupParseContext *context;
 	ESourceCamel *camel_ext;
 	ESourceBackend *backend_ext;
 	CamelSettings *settings;
-	ParserClosure closure;
 	const gchar *backend_name;
-	const gchar *markup_content;
-	gboolean success;
+
+	g_return_val_if_fail (result != NULL, FALSE);
+
+	if (!result->set)
+		return FALSE;
 
 	if (!e_source_has_extension (source, extension_name))
 		return FALSE;
@@ -349,33 +378,15 @@ mail_autoconfig_set_details (EMailAutoconfig *autoconfig,
 	settings = e_source_camel_get_settings (camel_ext);
 	g_return_val_if_fail (CAMEL_IS_NETWORK_SETTINGS (settings), FALSE);
 
-	markup_content = e_mail_autoconfig_get_markup_content (autoconfig);
-	g_return_val_if_fail (markup_content != NULL, FALSE);
-
-	closure.network_settings = CAMEL_NETWORK_SETTINGS (settings);
-	closure.expected_type = expected_type;
-	closure.in_server_element = FALSE;
-	closure.settings_modified = FALSE;
-
-	/* These are used for text substitutions. */
-	closure.email_address = autoconfig->priv->email_address;
-	closure.email_local_part = autoconfig->priv->email_local_part;
-	closure.email_domain_part = autoconfig->priv->email_domain_part;
-
-	context = g_markup_parse_context_new (
-		&mail_autoconfig_parser, 0, &closure, (GDestroyNotify) NULL);
-
-	success = g_markup_parse_context_parse (
-		context, markup_content, strlen (markup_content), NULL);
-
-	success &= g_markup_parse_context_end_parse (context, NULL);
-
-	/* Did we actually configure anything? */
-	success &= closure.settings_modified;
-
-	g_markup_parse_context_free (context);
+	g_object_set (
+		settings,
+		"user", result->user,
+		"host", result->host,
+		"port", result->port,
+		"security-method", result->security_method,
+		NULL);
 
-	return success;
+	return TRUE;
 }
 
 static void
@@ -433,7 +444,13 @@ mail_autoconfig_finalize (GObject *object)
 	g_free (priv->email_address);
 	g_free (priv->email_local_part);
 	g_free (priv->email_domain_part);
-	g_free (priv->markup_content);
+
+	g_free (priv->imap_result.user);
+	g_free (priv->imap_result.host);
+	g_free (priv->pop3_result.user);
+	g_free (priv->pop3_result.host);
+	g_free (priv->smtp_result.user);
+	g_free (priv->smtp_result.host);
 
 	/* Chain up to parent's finalize() method. */
 	G_OBJECT_CLASS (e_mail_autoconfig_parent_class)->finalize (object);
@@ -634,14 +651,6 @@ e_mail_autoconfig_get_email_address (EMailAutoconfig *autoconfig)
 	return autoconfig->priv->email_address;
 }
 
-const gchar *
-e_mail_autoconfig_get_markup_content (EMailAutoconfig *autoconfig)
-{
-	g_return_val_if_fail (E_IS_MAIL_AUTOCONFIG (autoconfig), NULL);
-
-	return autoconfig->priv->markup_content;
-}
-
 gboolean
 e_mail_autoconfig_set_imap_details (EMailAutoconfig *autoconfig,
                                     ESource *imap_source)
@@ -650,8 +659,8 @@ e_mail_autoconfig_set_imap_details (EMailAutoconfig *autoconfig,
 	g_return_val_if_fail (E_IS_SOURCE (imap_source), FALSE);
 
 	return mail_autoconfig_set_details (
-		autoconfig, "imap", imap_source,
-		E_SOURCE_EXTENSION_MAIL_ACCOUNT);
+		autoconfig, &autoconfig->priv->imap_result,
+		imap_source, E_SOURCE_EXTENSION_MAIL_ACCOUNT);
 }
 
 gboolean
@@ -662,8 +671,8 @@ e_mail_autoconfig_set_pop3_details (EMailAutoconfig *autoconfig,
 	g_return_val_if_fail (E_IS_SOURCE (pop3_source), FALSE);
 
 	return mail_autoconfig_set_details (
-		autoconfig, "pop3", pop3_source,
-		E_SOURCE_EXTENSION_MAIL_ACCOUNT);
+		autoconfig, &autoconfig->priv->pop3_result,
+		pop3_source, E_SOURCE_EXTENSION_MAIL_ACCOUNT);
 }
 
 gboolean
@@ -674,7 +683,54 @@ e_mail_autoconfig_set_smtp_details (EMailAutoconfig *autoconfig,
 	g_return_val_if_fail (E_IS_SOURCE (smtp_source), FALSE);
 
 	return mail_autoconfig_set_details (
-		autoconfig, "smtp", smtp_source,
-		E_SOURCE_EXTENSION_MAIL_TRANSPORT);
+		autoconfig, &autoconfig->priv->smtp_result,
+		smtp_source, E_SOURCE_EXTENSION_MAIL_TRANSPORT);
+}
+
+void
+e_mail_autoconfig_dump_results (EMailAutoconfig *autoconfig)
+{
+	const gchar *email_address;
+	gboolean have_results;
+
+	g_return_if_fail (E_IS_MAIL_AUTOCONFIG (autoconfig));
+
+	email_address = autoconfig->priv->email_address;
+
+	have_results =
+		autoconfig->priv->imap_result.set ||
+		autoconfig->priv->pop3_result.set ||
+		autoconfig->priv->smtp_result.set;
+
+	if (have_results) {
+		g_print ("Results for <%s>\n", email_address);
+
+		if (autoconfig->priv->imap_result.set) {
+			g_print (
+				"IMAP: %s %s:%u\n",
+				autoconfig->priv->imap_result.user,
+				autoconfig->priv->imap_result.host,
+				autoconfig->priv->imap_result.port);
+		}
+
+		if (autoconfig->priv->pop3_result.set) {
+			g_print (
+				"POP3: %s %s:%u\n",
+				autoconfig->priv->pop3_result.user,
+				autoconfig->priv->pop3_result.host,
+				autoconfig->priv->pop3_result.port);
+		}
+
+		if (autoconfig->priv->smtp_result.set) {
+			g_print (
+				"SMTP: %s %s:%u\n",
+				autoconfig->priv->smtp_result.user,
+				autoconfig->priv->smtp_result.host,
+				autoconfig->priv->smtp_result.port);
+		}
+
+	} else {
+		g_print ("No results for <%s>\n", email_address);
+	}
 }
 
diff --git a/mail/e-mail-autoconfig.h b/mail/e-mail-autoconfig.h
index b0cfb93..c59897c 100644
--- a/mail/e-mail-autoconfig.h
+++ b/mail/e-mail-autoconfig.h
@@ -70,8 +70,6 @@ EMailAutoconfig *
 						 GError **error);
 const gchar *	e_mail_autoconfig_get_email_address
 						(EMailAutoconfig *autoconfig);
-const gchar *	e_mail_autoconfig_get_markup_content
-						(EMailAutoconfig *autoconfig);
 gboolean	e_mail_autoconfig_set_imap_details
 						(EMailAutoconfig *autoconfig,
 						 ESource *imap_source);
@@ -81,6 +79,7 @@ gboolean	e_mail_autoconfig_set_pop3_details
 gboolean	e_mail_autoconfig_set_smtp_details
 						(EMailAutoconfig *autoconfig,
 						 ESource *smtp_source);
+void		e_mail_autoconfig_dump_results	(EMailAutoconfig *autoconfig);
 
 G_END_DECLS
 
diff --git a/mail/test-mail-autoconfig.c b/mail/test-mail-autoconfig.c
index 10977a1..2ce8cb6 100644
--- a/mail/test-mail-autoconfig.c
+++ b/mail/test-mail-autoconfig.c
@@ -45,7 +45,7 @@ main (gint argc,
 
 	g_assert (E_IS_MAIL_AUTOCONFIG (autoconfig));
 
-	g_print ("%s\n", e_mail_autoconfig_get_markup_content (autoconfig));
+	e_mail_autoconfig_dump_results (autoconfig);
 
 	g_object_unref (autoconfig);
 



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