4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 /* XXX Thoughts on RFC 6186: Use of SRV Records for Locating Email
19 * Submission/Access Services
21 * RFC 6186 specifies using SRV DNS lookups to aid in automatic
22 * configuration of mail accounts. While it may be tempting to
23 * implement the RFC here (I was tempted at least), upon closer
24 * examination I find the RFC to be insufficient.
26 * An SRV DNS lookup only provides a host name and port number.
27 * The RFC assumes the account's user name can be derived from
28 * the email address, and suggests probing the mail server for
29 * a valid user name by actually attempting authentication,
30 * first with the user's full email address and then falling
31 * back to only the local part.
33 * I'm uncomfortable with this for a number of reasons:
35 * 1) I would prefer the user have a chance to manually review
36 * the settings before transmitting credentials of any kind,
37 * since DNS responses can be spoofed.
39 * 2) Authentication at this phase would require asking for
40 * a password either before or during auto-configuration.
41 * Asking before assumes a password-based authentication
42 * mechanism is to be used, which is not always the case,
43 * and asking during may raise the user's suspicion about
44 * what's going on behind the scenes (it would mine).
46 * 3) For better or worse, our architecture isn't really built
47 * to handle authentication at this stage. EMailSession is
48 * wired into too many other areas to be reused here without
49 * risking unwanted side-effects, therefore it would require
50 * a custom CamelSession subclass with an authenticate_sync()
51 * implementation similar to EMailSession.
53 * While the technical limitations of (3) could be overcome, my concerns
54 * in (1) and (2) still stand. I think for the time being a better solution
55 * is to have an administrator script on api.gnome.org that compares the host
56 * and port settings in each clientConfig file to the _imap._tcp, _pop3._tcp,
57 * and _submission._tcp SRV records for that service provider (if available)
58 * to help ensure the static XML content remains accurate. It would also be
59 * instructive to track how many service providers even implement RFC 6186.
61 * Recording my thoughts here for posterity. -- mbarnes
64 #include "evolution-config.h"
67 #include <glib/gi18n-lib.h>
69 /* For error codes. */
70 #include <libsoup/soup.h>
72 #include "e-mail-autoconfig.h"
74 #define E_MAIL_AUTOCONFIG_GET_PRIVATE(obj) \
75 (G_TYPE_INSTANCE_GET_PRIVATE \
76 ((obj), E_TYPE_MAIL_AUTOCONFIG, EMailAutoconfigPrivate))
78 #define AUTOCONFIG_BASE_URI \
79 "https://api.gnome.org/evolution/autoconfig/1.1/"
81 #define ERROR_IS_NOT_FOUND(error) \
82 (g_error_matches ((error), SOUP_HTTP_ERROR, SOUP_STATUS_NOT_FOUND))
84 typedef struct _EMailAutoconfigResult EMailAutoconfigResult
;
85 typedef struct _ParserClosure ParserClosure
;
87 struct _EMailAutoconfigResult
{
92 gchar
*auth_mechanism
;
93 CamelNetworkSecurityMethod security_method
;
96 struct _EMailAutoconfigPrivate
{
97 ESourceRegistry
*registry
;
99 gchar
*email_local_part
;
100 gchar
*email_domain_part
;
102 EMailAutoconfigResult imap_result
;
103 EMailAutoconfigResult pop3_result
;
104 EMailAutoconfigResult smtp_result
;
107 struct _ParserClosure
{
108 EMailAutoconfig
*autoconfig
;
109 EMailAutoconfigResult
*result
;
119 /* Forward Declarations */
120 static void e_mail_autoconfig_initable_init (GInitableIface
*iface
);
122 /* By default, the GAsyncInitable interface calls GInitable.init()
123 * from a separate thread, so we only have to override GInitable. */
124 G_DEFINE_TYPE_WITH_CODE (
128 G_IMPLEMENT_INTERFACE (
129 G_TYPE_INITABLE
, e_mail_autoconfig_initable_init
)
130 G_IMPLEMENT_INTERFACE (
131 G_TYPE_ASYNC_INITABLE
, NULL
))
134 mail_autoconfig_parse_start_element (GMarkupParseContext
*context
,
135 const gchar
*element_name
,
136 const gchar
**attribute_names
,
137 const gchar
**attribute_values
,
141 ParserClosure
*closure
= user_data
;
142 EMailAutoconfigPrivate
*priv
;
143 gboolean is_incoming_server
;
144 gboolean is_outgoing_server
;
146 priv
= closure
->autoconfig
->priv
;
148 is_incoming_server
= g_str_equal (element_name
, "incomingServer");
149 is_outgoing_server
= g_str_equal (element_name
, "outgoingServer");
151 if (is_incoming_server
|| is_outgoing_server
) {
152 const gchar
*type
= NULL
;
154 g_markup_collect_attributes (
159 G_MARKUP_COLLECT_STRING
,
161 G_MARKUP_COLLECT_INVALID
);
163 if (g_strcmp0 (type
, "imap") == 0)
164 closure
->result
= &priv
->imap_result
;
165 if (g_strcmp0 (type
, "pop3") == 0)
166 closure
->result
= &priv
->pop3_result
;
167 if (g_strcmp0 (type
, "smtp") == 0)
168 closure
->result
= &priv
->smtp_result
;
173 mail_autoconfig_parse_end_element (GMarkupParseContext
*context
,
174 const gchar
*element_name
,
178 ParserClosure
*closure
= user_data
;
179 gboolean is_incoming_server
;
180 gboolean is_outgoing_server
;
182 is_incoming_server
= g_str_equal (element_name
, "incomingServer");
183 is_outgoing_server
= g_str_equal (element_name
, "outgoingServer");
185 if (is_incoming_server
|| is_outgoing_server
)
186 closure
->result
= NULL
;
190 mail_autoconfig_parse_text (GMarkupParseContext
*context
,
196 ParserClosure
*closure
= user_data
;
197 EMailAutoconfigPrivate
*priv
;
198 const gchar
*element_name
;
201 priv
= closure
->autoconfig
->priv
;
203 if (closure
->result
== NULL
)
206 /* Perform the following text substitutions:
208 * %EMAILADDRESS% : closure->email_address
209 * %EMAILLOCALPART% : closure->email_local_part
210 * %EMAILDOMAIN% : closure->email_domain_part
212 if (strchr (text
, '%') == NULL
)
213 string
= g_string_new (text
);
215 const gchar
*cp
= text
;
217 string
= g_string_sized_new (256);
218 while (*cp
!= '\0') {
219 const gchar
*variable
;
220 const gchar
*substitute
;
223 g_string_append_c (string
, *cp
++);
227 variable
= "%EMAILADDRESS%";
228 substitute
= priv
->email_address
;
230 if (strncmp (cp
, variable
, strlen (variable
)) == 0) {
231 g_string_append (string
, substitute
);
232 cp
+= strlen (variable
);
236 variable
= "%EMAILLOCALPART%";
237 substitute
= priv
->email_local_part
;
239 if (strncmp (cp
, variable
, strlen (variable
)) == 0) {
240 g_string_append (string
, substitute
);
241 cp
+= strlen (variable
);
245 variable
= "%EMAILDOMAIN%";
246 substitute
= priv
->use_domain
;
248 if (strncmp (cp
, variable
, strlen (variable
)) == 0) {
249 g_string_append (string
, substitute
);
250 cp
+= strlen (variable
);
254 g_string_append_c (string
, *cp
++);
258 element_name
= g_markup_parse_context_get_element (context
);
260 if (g_str_equal (element_name
, "hostname")) {
261 closure
->result
->host
= g_strdup (string
->str
);
262 closure
->result
->set
= TRUE
;
264 } else if (g_str_equal (element_name
, "username")) {
265 closure
->result
->user
= g_strdup (string
->str
);
266 closure
->result
->set
= TRUE
;
268 } else if (g_str_equal (element_name
, "port")) {
269 glong port
= strtol (string
->str
, NULL
, 10);
270 if (port
== CLAMP (port
, 1, G_MAXUINT16
)) {
271 closure
->result
->port
= (guint16
) port
;
272 closure
->result
->set
= TRUE
;
275 } else if (g_str_equal (element_name
, "socketType")) {
276 if (g_str_equal (string
->str
, "plain")) {
277 closure
->result
->security_method
=
278 CAMEL_NETWORK_SECURITY_METHOD_NONE
;
279 closure
->result
->set
= TRUE
;
280 } else if (g_str_equal (string
->str
, "SSL")) {
281 closure
->result
->security_method
=
282 CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT
;
283 closure
->result
->set
= TRUE
;
284 } else if (g_str_equal (string
->str
, "STARTTLS")) {
285 closure
->result
->security_method
=
286 CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT
;
287 closure
->result
->set
= TRUE
;
290 } else if (g_str_equal (element_name
, "authentication")) {
291 gboolean use_plain_auth
= FALSE
;
293 /* "password-cleartext" and "plain" are synonymous. */
295 if (g_str_equal (string
->str
, "password-cleartext"))
296 use_plain_auth
= TRUE
;
298 if (g_str_equal (string
->str
, "plain"))
299 use_plain_auth
= TRUE
;
301 if (use_plain_auth
) {
302 gchar
*auth_mechanism
= NULL
;
304 /* The exact auth name depends on the protocol. */
306 /* Leave this NULL for IMAP so Camel
307 * will issue an IMAP LOGIN command. */
308 if (closure
->result
== &priv
->imap_result
)
309 auth_mechanism
= NULL
;
311 /* Leave this NULL for POP3 so Camel
312 * will issue POP3 USER/PASS commands. */
313 if (closure
->result
== &priv
->pop3_result
)
314 auth_mechanism
= NULL
;
316 if (closure
->result
== &priv
->smtp_result
)
317 auth_mechanism
= g_strdup ("LOGIN");
319 closure
->result
->auth_mechanism
= auth_mechanism
;
320 closure
->result
->set
= TRUE
;
323 /* "password-encrypted" apparently maps to CRAM-MD5,
324 * or at least that's how Thunderbird interprets it. */
326 if (g_str_equal (string
->str
, "password-encrypted")) {
327 closure
->result
->auth_mechanism
= g_strdup ("CRAM-MD5");
328 closure
->result
->set
= TRUE
;
331 /* XXX Other <authentication> values not handled,
332 * but they are corner cases for the most part. */
335 g_string_free (string
, TRUE
);
338 static GMarkupParser mail_autoconfig_parser
= {
339 mail_autoconfig_parse_start_element
,
340 mail_autoconfig_parse_end_element
,
341 mail_autoconfig_parse_text
345 mail_autoconfig_resolve_name_server (const gchar
*domain
,
346 GCancellable
*cancellable
,
351 gchar
*name_server
= NULL
;
353 resolver
= g_resolver_get_default ();
355 records
= g_resolver_lookup_records (
356 resolver
, domain
, G_RESOLVER_RECORD_NS
, cancellable
, error
);
358 /* This list is sorted per RFC 2782, so use the first item. */
359 if (records
!= NULL
) {
360 GVariant
*variant
= records
->data
;
361 g_variant_get_child (variant
, 0, "s", &name_server
);
364 g_list_free_full (records
, (GDestroyNotify
) g_variant_unref
);
366 g_object_unref (resolver
);
372 mail_autoconfig_abort_soup_session_cb (GCancellable
*cancellable
,
373 SoupSession
*soup_session
)
375 soup_session_abort (soup_session
);
379 mail_autoconfig_lookup (EMailAutoconfig
*autoconfig
,
381 GCancellable
*cancellable
,
384 GMarkupParseContext
*context
;
385 ESourceRegistry
*registry
;
386 ESource
*proxy_source
;
387 SoupMessage
*soup_message
;
388 SoupSession
*soup_session
;
389 ParserClosure closure
;
390 gulong cancel_id
= 0;
395 registry
= e_mail_autoconfig_get_registry (autoconfig
);
396 proxy_source
= e_source_registry_ref_builtin_proxy (registry
);
398 soup_session
= soup_session_new_with_options (
399 SOUP_SESSION_PROXY_RESOLVER
,
400 G_PROXY_RESOLVER (proxy_source
),
403 g_object_unref (proxy_source
);
405 uri
= g_strconcat (AUTOCONFIG_BASE_URI
, domain
, NULL
);
407 soup_message
= soup_message_new (SOUP_METHOD_GET
, uri
);
410 if (G_IS_CANCELLABLE (cancellable
))
411 cancel_id
= g_cancellable_connect (
413 G_CALLBACK (mail_autoconfig_abort_soup_session_cb
),
414 g_object_ref (soup_session
),
415 (GDestroyNotify
) g_object_unref
);
417 status
= soup_session_send_message (soup_session
, soup_message
);
420 g_cancellable_disconnect (cancellable
, cancel_id
);
422 success
= SOUP_STATUS_IS_SUCCESSFUL (status
);
425 g_set_error_literal (
426 error
, SOUP_HTTP_ERROR
,
427 soup_message
->status_code
,
428 soup_message
->reason_phrase
);
432 closure
.autoconfig
= autoconfig
;
433 closure
.result
= NULL
;
435 context
= g_markup_parse_context_new (
436 &mail_autoconfig_parser
, 0,
437 &closure
, (GDestroyNotify
) NULL
);
439 success
= g_markup_parse_context_parse (
441 soup_message
->response_body
->data
,
442 soup_message
->response_body
->length
,
446 success
= g_markup_parse_context_end_parse (context
, error
);
448 g_markup_parse_context_free (context
);
451 g_object_unref (soup_message
);
452 g_object_unref (soup_session
);
458 mail_autoconfig_set_details (EMailAutoconfigResult
*result
,
460 const gchar
*extension_name
,
461 const gchar
*default_backend_name
)
463 ESourceCamel
*camel_ext
;
464 ESourceBackend
*backend_ext
;
465 CamelSettings
*settings
;
466 const gchar
*backend_name
;
468 g_return_val_if_fail (result
!= NULL
, FALSE
);
473 if (!e_source_has_extension (source
, extension_name
))
476 backend_ext
= e_source_get_extension (source
, extension_name
);
477 backend_name
= e_source_backend_get_backend_name (backend_ext
);
478 if (!backend_name
|| !*backend_name
) {
479 e_source_backend_set_backend_name (backend_ext
, default_backend_name
);
480 backend_name
= default_backend_name
;
486 extension_name
= e_source_camel_get_extension_name (backend_name
);
487 camel_ext
= e_source_get_extension (source
, extension_name
);
489 settings
= e_source_camel_get_settings (camel_ext
);
490 g_return_val_if_fail (CAMEL_IS_NETWORK_SETTINGS (settings
), FALSE
);
494 "user", result
->user
,
495 "host", result
->host
,
496 "port", result
->port
,
497 "auth-mechanism", result
->auth_mechanism
,
498 "security-method", result
->security_method
,
504 #define E_TYPE_MAIL_CONFIG_LOOKUP_RESULT \
505 (e_mail_config_lookup_result_get_type ())
506 #define E_MAIL_CONFIG_LOOKUP_RESULT(obj) \
507 (G_TYPE_CHECK_INSTANCE_CAST \
508 ((obj), E_TYPE_MAIL_CONFIG_LOOKUP_RESULT, EMailConfigLookupResult))
509 #define E_IS_MAIL_CONFIG_LOOKUP_RESULT(obj) \
510 (G_TYPE_CHECK_INSTANCE_TYPE \
511 ((obj), E_TYPE_MAIL_CONFIG_LOOKUP_RESULT))
513 typedef struct _EMailConfigLookupResult EMailConfigLookupResult
;
514 typedef struct _EMailConfigLookupResultClass EMailConfigLookupResultClass
;
516 struct _EMailConfigLookupResult
{
518 EConfigLookupResultSimple parent
;
520 EMailAutoconfigResult result
;
521 gchar
*extension_name
;
524 struct _EMailConfigLookupResultClass
{
526 EConfigLookupResultSimpleClass parent_class
;
529 GType
e_mail_config_lookup_result_get_type (void) G_GNUC_CONST
;
531 G_DEFINE_TYPE (EMailConfigLookupResult
, e_mail_config_lookup_result
, E_TYPE_CONFIG_LOOKUP_RESULT_SIMPLE
)
534 mail_config_lookup_result_configure_source (EConfigLookupResult
*lookup_result
,
535 EConfigLookup
*config_lookup
,
538 EMailConfigLookupResult
*mail_result
;
540 g_return_val_if_fail (E_IS_MAIL_CONFIG_LOOKUP_RESULT (lookup_result
), FALSE
);
542 mail_result
= E_MAIL_CONFIG_LOOKUP_RESULT (lookup_result
);
544 /* No chain up to parent method, not needed here, because not used */
545 return mail_autoconfig_set_details (&mail_result
->result
, source
, mail_result
->extension_name
,
546 e_config_lookup_result_get_protocol (lookup_result
));
550 mail_config_lookup_result_finalize (GObject
*object
)
552 EMailConfigLookupResult
*mail_result
= E_MAIL_CONFIG_LOOKUP_RESULT (object
);
554 g_free (mail_result
->result
.user
);
555 g_free (mail_result
->result
.host
);
556 g_free (mail_result
->result
.auth_mechanism
);
557 g_free (mail_result
->extension_name
);
559 /* Chain up to parent's method. */
560 G_OBJECT_CLASS (e_mail_config_lookup_result_parent_class
)->finalize (object
);
564 e_mail_config_lookup_result_class_init (EMailConfigLookupResultClass
*klass
)
566 EConfigLookupResultSimpleClass
*simple_result_class
;
567 GObjectClass
*object_class
;
569 object_class
= G_OBJECT_CLASS (klass
);
570 object_class
->finalize
= mail_config_lookup_result_finalize
;
572 simple_result_class
= E_CONFIG_LOOKUP_RESULT_SIMPLE_CLASS (klass
);
573 simple_result_class
->configure_source
= mail_config_lookup_result_configure_source
;
577 e_mail_config_lookup_result_init (EMailConfigLookupResult
*mail_result
)
581 static EConfigLookupResult
*
582 e_mail_config_lookup_result_new (EConfigLookupResultKind kind
,
584 const gchar
*protocol
,
585 const gchar
*display_name
,
586 const gchar
*description
,
587 const EMailAutoconfigResult
*result
,
588 const gchar
*extension_name
)
590 EMailConfigLookupResult
*mail_result
;
592 g_return_val_if_fail (protocol
!= NULL
, NULL
);
593 g_return_val_if_fail (display_name
!= NULL
, NULL
);
594 g_return_val_if_fail (description
!= NULL
, NULL
);
595 g_return_val_if_fail (result
!= NULL
, NULL
);
596 g_return_val_if_fail (extension_name
!= NULL
, NULL
);
598 mail_result
= g_object_new (E_TYPE_MAIL_CONFIG_LOOKUP_RESULT
,
600 "priority", priority
,
602 "protocol", protocol
,
603 "display-name", display_name
,
604 "description", description
,
608 mail_result
->result
.set
= result
->set
;
609 mail_result
->result
.user
= g_strdup (result
->user
);
610 mail_result
->result
.host
= g_strdup (result
->host
);
611 mail_result
->result
.port
= result
->port
;
612 mail_result
->result
.auth_mechanism
= g_strdup (result
->auth_mechanism
);
613 mail_result
->result
.security_method
= result
->security_method
;
614 mail_result
->extension_name
= g_strdup (extension_name
);
616 return E_CONFIG_LOOKUP_RESULT (mail_result
);
620 mail_autoconfig_result_to_config_lookup (EMailAutoconfig
*mail_autoconfig
,
621 EConfigLookup
*config_lookup
,
622 EMailAutoconfigResult
*result
,
624 const gchar
*protocol
,
625 const gchar
*display_name
,
626 const gchar
*extension_name
)
628 EConfigLookupResult
*lookup_result
;
629 EConfigLookupResultKind kind
;
630 GString
*description
;
632 g_return_if_fail (E_IS_MAIL_AUTOCONFIG (mail_autoconfig
));
633 g_return_if_fail (E_IS_CONFIG_LOOKUP (config_lookup
));
634 g_return_if_fail (result
!= NULL
);
635 g_return_if_fail (protocol
!= NULL
);
636 g_return_if_fail (display_name
!= NULL
);
637 g_return_if_fail (extension_name
!= NULL
);
642 kind
= E_CONFIG_LOOKUP_RESULT_MAIL_RECEIVE
;
643 if (g_strcmp0 (extension_name
, E_SOURCE_EXTENSION_MAIL_TRANSPORT
) == 0)
644 kind
= E_CONFIG_LOOKUP_RESULT_MAIL_SEND
;
646 description
= g_string_new ("");
648 g_string_append_printf (description
, _("Host: %s:%d"), result
->host
, result
->port
);
650 if (result
->user
&& *result
->user
) {
651 g_string_append_c (description
, '\n');
652 g_string_append_printf (description
, _("User: %s"), result
->user
);
655 g_string_append_c (description
, '\n');
656 g_string_append_printf (description
, _("Security method: %s"),
657 result
->security_method
== CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT
? _("TLS") :
658 result
->security_method
== CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT
? _("STARTTLS") : _("None"));
660 if (result
->auth_mechanism
&& *result
->auth_mechanism
) {
661 g_string_append_c (description
, '\n');
662 g_string_append_printf (description
, _("Authentication mechanism: %s"), result
->auth_mechanism
);
665 lookup_result
= e_mail_config_lookup_result_new (kind
, priority
, protocol
, display_name
, description
->str
, result
, extension_name
);
666 e_config_lookup_add_result (config_lookup
, lookup_result
);
668 g_string_free (description
, TRUE
);
672 mail_autoconfig_set_email_address (EMailAutoconfig
*autoconfig
,
673 const gchar
*email_address
)
675 g_return_if_fail (email_address
!= NULL
);
676 g_return_if_fail (autoconfig
->priv
->email_address
== NULL
);
678 autoconfig
->priv
->email_address
= g_strdup (email_address
);
682 mail_autoconfig_set_use_domain (EMailAutoconfig
*autoconfig
,
683 const gchar
*use_domain
)
685 if (g_strcmp0 (autoconfig
->priv
->use_domain
, use_domain
) != 0) {
686 g_free (autoconfig
->priv
->use_domain
);
687 autoconfig
->priv
->use_domain
= g_strdup (use_domain
);
692 mail_autoconfig_set_registry (EMailAutoconfig
*autoconfig
,
693 ESourceRegistry
*registry
)
695 g_return_if_fail (E_IS_SOURCE_REGISTRY (registry
));
696 g_return_if_fail (autoconfig
->priv
->registry
== NULL
);
698 autoconfig
->priv
->registry
= g_object_ref (registry
);
702 mail_autoconfig_set_property (GObject
*object
,
707 switch (property_id
) {
708 case PROP_EMAIL_ADDRESS
:
709 mail_autoconfig_set_email_address (
710 E_MAIL_AUTOCONFIG (object
),
711 g_value_get_string (value
));
715 mail_autoconfig_set_registry (
716 E_MAIL_AUTOCONFIG (object
),
717 g_value_get_object (value
));
720 case PROP_USE_DOMAIN
:
721 mail_autoconfig_set_use_domain (
722 E_MAIL_AUTOCONFIG (object
),
723 g_value_get_string (value
));
727 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
731 mail_autoconfig_get_property (GObject
*object
,
736 switch (property_id
) {
737 case PROP_EMAIL_ADDRESS
:
740 e_mail_autoconfig_get_email_address (
741 E_MAIL_AUTOCONFIG (object
)));
747 e_mail_autoconfig_get_registry (
748 E_MAIL_AUTOCONFIG (object
)));
751 case PROP_USE_DOMAIN
:
754 e_mail_autoconfig_get_use_domain (
755 E_MAIL_AUTOCONFIG (object
)));
759 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, property_id
, pspec
);
763 mail_autoconfig_dispose (GObject
*object
)
765 EMailAutoconfigPrivate
*priv
;
767 priv
= E_MAIL_AUTOCONFIG_GET_PRIVATE (object
);
769 g_clear_object (&priv
->registry
);
771 /* Chain up to parent's dispose() method. */
772 G_OBJECT_CLASS (e_mail_autoconfig_parent_class
)->dispose (object
);
776 mail_autoconfig_finalize (GObject
*object
)
778 EMailAutoconfigPrivate
*priv
;
780 priv
= E_MAIL_AUTOCONFIG_GET_PRIVATE (object
);
782 g_free (priv
->email_address
);
783 g_free (priv
->email_local_part
);
784 g_free (priv
->email_domain_part
);
785 g_free (priv
->use_domain
);
787 g_free (priv
->imap_result
.user
);
788 g_free (priv
->imap_result
.host
);
789 g_free (priv
->imap_result
.auth_mechanism
);
790 g_free (priv
->pop3_result
.user
);
791 g_free (priv
->pop3_result
.host
);
792 g_free (priv
->pop3_result
.auth_mechanism
);
793 g_free (priv
->smtp_result
.user
);
794 g_free (priv
->smtp_result
.host
);
795 g_free (priv
->smtp_result
.auth_mechanism
);
797 /* Chain up to parent's finalize() method. */
798 G_OBJECT_CLASS (e_mail_autoconfig_parent_class
)->finalize (object
);
802 mail_autoconfig_initable_init (GInitable
*initable
,
803 GCancellable
*cancellable
,
806 EMailAutoconfig
*autoconfig
;
807 const gchar
*email_address
;
811 gboolean success
= FALSE
;
812 GError
*local_error
= NULL
;
814 autoconfig
= E_MAIL_AUTOCONFIG (initable
);
815 email_address
= e_mail_autoconfig_get_email_address (autoconfig
);
817 if (email_address
== NULL
) {
818 g_set_error_literal (
820 G_IO_ERROR_INVALID_ARGUMENT
,
821 _("No email address provided"));
825 cp
= strchr (email_address
, '@');
827 g_set_error_literal (
829 G_IO_ERROR_INVALID_ARGUMENT
,
830 _("Missing domain in email address"));
836 autoconfig
->priv
->email_local_part
=
837 g_strndup (email_address
, cp
- email_address
);
838 autoconfig
->priv
->email_domain_part
= g_strdup (domain
);
840 if (autoconfig
->priv
->use_domain
&& *autoconfig
->priv
->use_domain
)
841 domain
= autoconfig
->priv
->use_domain
;
843 /* First try the email address domain verbatim. */
844 success
= mail_autoconfig_lookup (
845 autoconfig
, domain
, cancellable
, &local_error
);
848 (success
&& local_error
== NULL
) ||
849 (!success
&& local_error
!= NULL
));
854 /* "404 Not Found" errors are non-fatal this time around. */
855 if (ERROR_IS_NOT_FOUND (local_error
)) {
856 g_clear_error (&local_error
);
858 g_propagate_error (error
, local_error
);
862 /* Look up an authoritative name server for the email address
863 * domain according to its "name server" (NS) DNS record. */
864 name_server
= mail_autoconfig_resolve_name_server (
865 domain
, cancellable
, error
);
867 if (name_server
== NULL
)
870 /* Widdle away segments of the name server domain until
871 * we find a match, or until we widdle down to nothing. */
874 while (cp
!= NULL
&& strchr (cp
, '.') != NULL
) {
875 g_clear_error (&local_error
);
877 success
= mail_autoconfig_lookup (
878 autoconfig
, cp
, cancellable
, &local_error
);
881 (success
&& local_error
== NULL
) ||
882 (!success
&& local_error
!= NULL
));
884 if (success
|| !ERROR_IS_NOT_FOUND (local_error
))
887 cp
= strchr (cp
, '.');
892 if (!success
&& !local_error
)
893 g_set_error (error
, G_IO_ERROR
, G_IO_ERROR_FAILED
, _("Unknown error"));
894 else if (local_error
)
895 g_propagate_error (error
, local_error
);
897 g_free (name_server
);
903 e_mail_autoconfig_class_init (EMailAutoconfigClass
*class)
905 GObjectClass
*object_class
;
907 g_type_class_add_private (class, sizeof (EMailAutoconfigPrivate
));
909 object_class
= G_OBJECT_CLASS (class);
910 object_class
->set_property
= mail_autoconfig_set_property
;
911 object_class
->get_property
= mail_autoconfig_get_property
;
912 object_class
->dispose
= mail_autoconfig_dispose
;
913 object_class
->finalize
= mail_autoconfig_finalize
;
915 g_object_class_install_property (
918 g_param_spec_string (
921 "The address from which to query config data",
924 G_PARAM_CONSTRUCT_ONLY
|
925 G_PARAM_STATIC_STRINGS
));
927 g_object_class_install_property (
930 g_param_spec_object (
933 "Data source registry",
934 E_TYPE_SOURCE_REGISTRY
,
936 G_PARAM_CONSTRUCT_ONLY
|
937 G_PARAM_STATIC_STRINGS
));
939 g_object_class_install_property (
942 g_param_spec_string (
945 "A domain to use, instead of the one from email-address",
948 G_PARAM_CONSTRUCT_ONLY
|
949 G_PARAM_STATIC_STRINGS
));
953 e_mail_autoconfig_initable_init (GInitableIface
*iface
)
955 iface
->init
= mail_autoconfig_initable_init
;
959 e_mail_autoconfig_init (EMailAutoconfig
*autoconfig
)
961 autoconfig
->priv
= E_MAIL_AUTOCONFIG_GET_PRIVATE (autoconfig
);
965 e_mail_autoconfig_new_sync (ESourceRegistry
*registry
,
966 const gchar
*email_address
,
967 const gchar
*use_domain
,
968 GCancellable
*cancellable
,
971 g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry
), NULL
);
972 g_return_val_if_fail (email_address
!= NULL
, NULL
);
974 return g_initable_new (
975 E_TYPE_MAIL_AUTOCONFIG
,
977 "registry", registry
,
978 "email-address", email_address
,
979 "use-domain", use_domain
,
984 e_mail_autoconfig_new (ESourceRegistry
*registry
,
985 const gchar
*email_address
,
986 const gchar
*use_domain
,
988 GCancellable
*cancellable
,
989 GAsyncReadyCallback callback
,
992 g_return_if_fail (E_IS_SOURCE_REGISTRY (registry
));
993 g_return_if_fail (email_address
!= NULL
);
995 g_async_initable_new_async (
996 E_TYPE_MAIL_AUTOCONFIG
,
997 io_priority
, cancellable
,
999 "registry", registry
,
1000 "email-address", email_address
,
1001 "use-domain", use_domain
,
1006 e_mail_autoconfig_finish (GAsyncResult
*result
,
1009 GObject
*source_object
;
1010 GObject
*autoconfig
;
1012 g_return_val_if_fail (G_IS_ASYNC_RESULT (result
), NULL
);
1014 source_object
= g_async_result_get_source_object (result
);
1015 g_return_val_if_fail (source_object
!= NULL
, NULL
);
1017 autoconfig
= g_async_initable_new_finish (
1018 G_ASYNC_INITABLE (source_object
), result
, error
);
1020 g_object_unref (source_object
);
1022 if (autoconfig
== NULL
)
1025 return E_MAIL_AUTOCONFIG (autoconfig
);
1029 * e_mail_autoconfig_get_registry:
1030 * @autoconfig: an #EMailAutoconfig
1032 * Returns the #ESourceRegistry passed to e_mail_autoconfig_new() or
1033 * e_mail_autoconfig_new_sync().
1035 * Returns: an #ESourceRegistry
1038 e_mail_autoconfig_get_registry (EMailAutoconfig
*autoconfig
)
1040 g_return_val_if_fail (E_IS_MAIL_AUTOCONFIG (autoconfig
), NULL
);
1042 return autoconfig
->priv
->registry
;
1046 e_mail_autoconfig_get_email_address (EMailAutoconfig
*autoconfig
)
1048 g_return_val_if_fail (E_IS_MAIL_AUTOCONFIG (autoconfig
), NULL
);
1050 return autoconfig
->priv
->email_address
;
1054 e_mail_autoconfig_get_use_domain (EMailAutoconfig
*autoconfig
)
1056 g_return_val_if_fail (E_IS_MAIL_AUTOCONFIG (autoconfig
), NULL
);
1058 return autoconfig
->priv
->use_domain
;
1062 e_mail_autoconfig_set_imap_details (EMailAutoconfig
*autoconfig
,
1063 ESource
*imap_source
)
1065 g_return_val_if_fail (E_IS_MAIL_AUTOCONFIG (autoconfig
), FALSE
);
1066 g_return_val_if_fail (E_IS_SOURCE (imap_source
), FALSE
);
1068 return mail_autoconfig_set_details (
1069 &autoconfig
->priv
->imap_result
,
1070 imap_source
, E_SOURCE_EXTENSION_MAIL_ACCOUNT
, "imapx");
1074 e_mail_autoconfig_set_pop3_details (EMailAutoconfig
*autoconfig
,
1075 ESource
*pop3_source
)
1077 g_return_val_if_fail (E_IS_MAIL_AUTOCONFIG (autoconfig
), FALSE
);
1078 g_return_val_if_fail (E_IS_SOURCE (pop3_source
), FALSE
);
1080 return mail_autoconfig_set_details (
1081 &autoconfig
->priv
->pop3_result
,
1082 pop3_source
, E_SOURCE_EXTENSION_MAIL_ACCOUNT
, "pop3");
1086 e_mail_autoconfig_set_smtp_details (EMailAutoconfig
*autoconfig
,
1087 ESource
*smtp_source
)
1089 g_return_val_if_fail (E_IS_MAIL_AUTOCONFIG (autoconfig
), FALSE
);
1090 g_return_val_if_fail (E_IS_SOURCE (smtp_source
), FALSE
);
1092 return mail_autoconfig_set_details (
1093 &autoconfig
->priv
->smtp_result
,
1094 smtp_source
, E_SOURCE_EXTENSION_MAIL_TRANSPORT
, "smtp");
1098 e_mail_autoconfig_dump_results (EMailAutoconfig
*autoconfig
)
1100 const gchar
*email_address
;
1101 gboolean have_results
;
1103 g_return_if_fail (E_IS_MAIL_AUTOCONFIG (autoconfig
));
1105 email_address
= autoconfig
->priv
->email_address
;
1108 autoconfig
->priv
->imap_result
.set
||
1109 autoconfig
->priv
->pop3_result
.set
||
1110 autoconfig
->priv
->smtp_result
.set
;
1113 if (autoconfig
->priv
->use_domain
&& *autoconfig
->priv
->use_domain
)
1114 g_print ("Results for <%s> and domain '%s'\n", email_address
, autoconfig
->priv
->use_domain
);
1116 g_print ("Results for <%s>\n", email_address
);
1118 if (autoconfig
->priv
->imap_result
.set
) {
1121 autoconfig
->priv
->imap_result
.user
,
1122 autoconfig
->priv
->imap_result
.host
,
1123 autoconfig
->priv
->imap_result
.port
);
1126 if (autoconfig
->priv
->pop3_result
.set
) {
1129 autoconfig
->priv
->pop3_result
.user
,
1130 autoconfig
->priv
->pop3_result
.host
,
1131 autoconfig
->priv
->pop3_result
.port
);
1134 if (autoconfig
->priv
->smtp_result
.set
) {
1137 autoconfig
->priv
->smtp_result
.user
,
1138 autoconfig
->priv
->smtp_result
.host
,
1139 autoconfig
->priv
->smtp_result
.port
);
1142 } else if (autoconfig
->priv
->use_domain
&& *autoconfig
->priv
->use_domain
) {
1143 g_print ("No results for <%s> and domain '%s'\n", email_address
, autoconfig
->priv
->use_domain
);
1145 g_print ("No results for <%s>\n", email_address
);
1150 * e_mail_autoconfig_copy_results_to_config_lookup:
1151 * @mail_autoconfig: an #EMailAutoconfig
1152 * @config_lookup: an #EConfigLookup
1154 * Copies any valid result from @mail_autoconfig to @config_lookup.
1159 e_mail_autoconfig_copy_results_to_config_lookup (EMailAutoconfig
*mail_autoconfig
,
1160 EConfigLookup
*config_lookup
)
1162 g_return_if_fail (E_IS_MAIL_AUTOCONFIG (mail_autoconfig
));
1163 g_return_if_fail (E_IS_CONFIG_LOOKUP (config_lookup
));
1165 mail_autoconfig_result_to_config_lookup (mail_autoconfig
, config_lookup
,
1166 &mail_autoconfig
->priv
->imap_result
,
1167 E_CONFIG_LOOKUP_RESULT_PRIORITY_IMAP
,
1170 E_SOURCE_EXTENSION_MAIL_ACCOUNT
);
1172 mail_autoconfig_result_to_config_lookup (mail_autoconfig
, config_lookup
,
1173 &mail_autoconfig
->priv
->pop3_result
,
1174 E_CONFIG_LOOKUP_RESULT_PRIORITY_POP3
,
1177 E_SOURCE_EXTENSION_MAIL_ACCOUNT
);
1179 mail_autoconfig_result_to_config_lookup (mail_autoconfig
, config_lookup
,
1180 &mail_autoconfig
->priv
->smtp_result
,
1181 E_CONFIG_LOOKUP_RESULT_PRIORITY_SMTP
,
1184 E_SOURCE_EXTENSION_MAIL_TRANSPORT
);