From 6de9a0e56e9a6800e39a43cb04bc5e0045ff8790 Mon Sep 17 00:00:00 2001 From: Matthew Barnes Date: Thu, 8 Nov 2012 12:53:09 -0500 Subject: 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 aeebb0fa22..a9e9773050 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 b0cfb93b13..c59897c8b0 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 10977a17b2..2ce8cb600a 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); -- cgit