1 /*
2 * e-mail-autoconfig.c
3 *
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.
7 *
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
11 * for more details.
12 *
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/>.
15 *
16 */
17
18 /* XXX Thoughts on RFC 6186: Use of SRV Records for Locating Email
19 * Submission/Access Services
20 *
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.
25 *
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.
32 *
33 * I'm uncomfortable with this for a number of reasons:
34 *
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.
38 *
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).
45 *
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.
52 *
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.
60 *
61 * Recording my thoughts here for posterity. -- mbarnes
62 */
63
64 #include "evolution-config.h"
65
66 #include <string.h>
67 #include <glib/gi18n-lib.h>
68
69 /* For error codes. */
70 #include <libsoup/soup.h>
71
72 #include "e-mail-autoconfig.h"
73
74 #define E_MAIL_AUTOCONFIG_GET_PRIVATE(obj) \
75 (G_TYPE_INSTANCE_GET_PRIVATE \
76 ((obj), E_TYPE_MAIL_AUTOCONFIG, EMailAutoconfigPrivate))
77
78 #define AUTOCONFIG_BASE_URI "https://autoconfig.thunderbird.net/v1.1/"
79
80 #define FAKE_EVOLUTION_USER_STRING "EVOLUTIONUSER"
81
82 #define ERROR_IS_NOT_FOUND(error) \
83 (g_error_matches ((error), SOUP_HTTP_ERROR, SOUP_STATUS_NOT_FOUND))
84
85 typedef struct _EMailAutoconfigResult EMailAutoconfigResult;
86 typedef struct _ParserClosure ParserClosure;
87
88 struct _EMailAutoconfigResult {
89 gboolean set;
90 gchar *user;
91 gchar *host;
92 guint16 port;
93 gchar *auth_mechanism;
94 CamelNetworkSecurityMethod security_method;
95 };
96
97 struct _EMailAutoconfigPrivate {
98 ESourceRegistry *registry;
99 gchar *email_address;
100 gchar *email_local_part;
101 gchar *email_domain_part;
102 gchar *use_domain;
103 EMailAutoconfigResult imap_result;
104 EMailAutoconfigResult pop3_result;
105 EMailAutoconfigResult smtp_result;
106 };
107
108 struct _ParserClosure {
109 EMailAutoconfig *autoconfig;
110 EMailAutoconfigResult *result;
111 };
112
113 enum {
114 PROP_0,
115 PROP_EMAIL_ADDRESS,
116 PROP_REGISTRY,
117 PROP_USE_DOMAIN
118 };
119
120 /* Forward Declarations */
121 static void e_mail_autoconfig_initable_init (GInitableIface *iface);
122
123 /* By default, the GAsyncInitable interface calls GInitable.init()
124 * from a separate thread, so we only have to override GInitable. */
G_DEFINE_TYPE_WITH_CODE(EMailAutoconfig,e_mail_autoconfig,G_TYPE_OBJECT,G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,e_mail_autoconfig_initable_init)G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE,NULL))125 G_DEFINE_TYPE_WITH_CODE (
126 EMailAutoconfig,
127 e_mail_autoconfig,
128 G_TYPE_OBJECT,
129 G_IMPLEMENT_INTERFACE (
130 G_TYPE_INITABLE, e_mail_autoconfig_initable_init)
131 G_IMPLEMENT_INTERFACE (
132 G_TYPE_ASYNC_INITABLE, NULL))
133
134 static void
135 mail_autoconfig_parse_start_element (GMarkupParseContext *context,
136 const gchar *element_name,
137 const gchar **attribute_names,
138 const gchar **attribute_values,
139 gpointer user_data,
140 GError **error)
141 {
142 ParserClosure *closure = user_data;
143 EMailAutoconfigPrivate *priv;
144 gboolean is_incoming_server;
145 gboolean is_outgoing_server;
146
147 priv = closure->autoconfig->priv;
148
149 is_incoming_server = g_str_equal (element_name, "incomingServer");
150 is_outgoing_server = g_str_equal (element_name, "outgoingServer");
151
152 if (is_incoming_server || is_outgoing_server) {
153 const gchar *type = NULL;
154
155 g_markup_collect_attributes (
156 element_name,
157 attribute_names,
158 attribute_values,
159 error,
160 G_MARKUP_COLLECT_STRING,
161 "type", &type,
162 G_MARKUP_COLLECT_INVALID);
163
164 if (g_strcmp0 (type, "imap") == 0)
165 closure->result = &priv->imap_result;
166 if (g_strcmp0 (type, "pop3") == 0)
167 closure->result = &priv->pop3_result;
168 if (g_strcmp0 (type, "smtp") == 0)
169 closure->result = &priv->smtp_result;
170 }
171 }
172
173 static void
mail_autoconfig_parse_end_element(GMarkupParseContext * context,const gchar * element_name,gpointer user_data,GError ** error)174 mail_autoconfig_parse_end_element (GMarkupParseContext *context,
175 const gchar *element_name,
176 gpointer user_data,
177 GError **error)
178 {
179 ParserClosure *closure = user_data;
180 gboolean is_incoming_server;
181 gboolean is_outgoing_server;
182
183 is_incoming_server = g_str_equal (element_name, "incomingServer");
184 is_outgoing_server = g_str_equal (element_name, "outgoingServer");
185
186 if (is_incoming_server || is_outgoing_server)
187 closure->result = NULL;
188 }
189
190 /* Returns NULL when not being there */
191 static gchar *
mail_autoconfig_replace_case_insensitive(const gchar * text,const gchar * before,const gchar * after)192 mail_autoconfig_replace_case_insensitive (const gchar *text,
193 const gchar *before,
194 const gchar *after)
195 {
196 const gchar *p, *next;
197 GString *str;
198 gint find_len;
199
200 if (!text)
201 return NULL;
202
203 find_len = strlen (before);
204 str = g_string_new ("");
205
206 p = text;
207 while (next = camel_strstrcase (p, before), next) {
208 if (p < next)
209 g_string_append_len (str, p, next - p);
210
211 if (after && *after)
212 g_string_append (str, after);
213
214 p = next + find_len;
215 }
216
217 if (p == text) {
218 g_string_free (str, TRUE);
219 return NULL;
220 }
221
222 g_string_append (str, p);
223
224 return g_string_free (str, FALSE);
225 }
226
227 static void
mail_autoconfig_parse_text(GMarkupParseContext * context,const gchar * in_text,gsize in_text_length,gpointer user_data,GError ** error)228 mail_autoconfig_parse_text (GMarkupParseContext *context,
229 const gchar *in_text,
230 gsize in_text_length,
231 gpointer user_data,
232 GError **error)
233 {
234 ParserClosure *closure = user_data;
235 EMailAutoconfigPrivate *priv;
236 const gchar *element_name, *text;
237 gchar *to_free;
238 GString *string;
239
240 priv = closure->autoconfig->priv;
241
242 if (closure->result == NULL)
243 return;
244
245 to_free = mail_autoconfig_replace_case_insensitive (in_text, FAKE_EVOLUTION_USER_STRING, priv->email_local_part);
246 text = to_free ? to_free : in_text;
247
248 /* Perform the following text substitutions:
249 *
250 * %EMAILADDRESS% : closure->email_address
251 * %EMAILLOCALPART% : closure->email_local_part
252 * %EMAILDOMAIN% : closure->email_domain_part
253 */
254 if (strchr (text, '%') == NULL)
255 string = g_string_new (text);
256 else {
257 const gchar *cp = text;
258
259 string = g_string_sized_new (256);
260 while (*cp != '\0') {
261 const gchar *variable;
262 const gchar *substitute;
263
264 if (*cp != '%') {
265 g_string_append_c (string, *cp++);
266 continue;
267 }
268
269 variable = "%EMAILADDRESS%";
270 substitute = priv->email_address;
271
272 if (strncmp (cp, variable, strlen (variable)) == 0) {
273 g_string_append (string, substitute);
274 cp += strlen (variable);
275 continue;
276 }
277
278 variable = "%EMAILLOCALPART%";
279 substitute = priv->email_local_part;
280
281 if (strncmp (cp, variable, strlen (variable)) == 0) {
282 g_string_append (string, substitute);
283 cp += strlen (variable);
284 continue;
285 }
286
287 variable = "%EMAILDOMAIN%";
288 substitute = priv->use_domain;
289
290 if (strncmp (cp, variable, strlen (variable)) == 0) {
291 g_string_append (string, substitute);
292 cp += strlen (variable);
293 continue;
294 }
295
296 g_string_append_c (string, *cp++);
297 }
298 }
299
300 element_name = g_markup_parse_context_get_element (context);
301
302 if (g_str_equal (element_name, "hostname")) {
303 closure->result->host = g_strdup (string->str);
304 closure->result->set = TRUE;
305
306 } else if (g_str_equal (element_name, "username")) {
307 closure->result->user = g_strdup (string->str);
308 closure->result->set = TRUE;
309
310 } else if (g_str_equal (element_name, "port")) {
311 glong port = strtol (string->str, NULL, 10);
312 if (port == CLAMP (port, 1, G_MAXUINT16)) {
313 closure->result->port = (guint16) port;
314 closure->result->set = TRUE;
315 }
316
317 } else if (g_str_equal (element_name, "socketType")) {
318 if (g_str_equal (string->str, "plain")) {
319 closure->result->security_method =
320 CAMEL_NETWORK_SECURITY_METHOD_NONE;
321 closure->result->set = TRUE;
322 } else if (g_str_equal (string->str, "SSL")) {
323 closure->result->security_method =
324 CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT;
325 closure->result->set = TRUE;
326 } else if (g_str_equal (string->str, "STARTTLS")) {
327 closure->result->security_method =
328 CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT;
329 closure->result->set = TRUE;
330 }
331
332 } else if (g_str_equal (element_name, "authentication")) {
333 gboolean use_plain_auth = FALSE;
334
335 /* "password-cleartext" and "plain" are synonymous. */
336
337 if (g_str_equal (string->str, "password-cleartext"))
338 use_plain_auth = TRUE;
339
340 if (g_str_equal (string->str, "plain"))
341 use_plain_auth = TRUE;
342
343 if (use_plain_auth) {
344 gchar *auth_mechanism = NULL;
345
346 /* The exact auth name depends on the protocol. */
347
348 /* Leave this NULL for IMAP so Camel
349 * will issue an IMAP LOGIN command. */
350 if (closure->result == &priv->imap_result)
351 auth_mechanism = NULL;
352
353 /* Leave this NULL for POP3 so Camel
354 * will issue POP3 USER/PASS commands. */
355 if (closure->result == &priv->pop3_result)
356 auth_mechanism = NULL;
357
358 if (closure->result == &priv->smtp_result)
359 auth_mechanism = g_strdup ("LOGIN");
360
361 closure->result->auth_mechanism = auth_mechanism;
362 closure->result->set = TRUE;
363 }
364
365 /* "password-encrypted" apparently maps to CRAM-MD5,
366 * or at least that's how Thunderbird interprets it. */
367
368 if (g_str_equal (string->str, "password-encrypted")) {
369 closure->result->auth_mechanism = g_strdup ("CRAM-MD5");
370 closure->result->set = TRUE;
371 }
372
373 /* XXX Other <authentication> values not handled,
374 * but they are corner cases for the most part. */
375 }
376
377 g_string_free (string, TRUE);
378 g_free (to_free);
379 }
380
381 static GMarkupParser mail_autoconfig_parser = {
382 mail_autoconfig_parse_start_element,
383 mail_autoconfig_parse_end_element,
384 mail_autoconfig_parse_text
385 };
386
387 static gchar *
mail_autoconfig_resolve_name_server(const gchar * domain,GCancellable * cancellable,GError ** error)388 mail_autoconfig_resolve_name_server (const gchar *domain,
389 GCancellable *cancellable,
390 GError **error)
391 {
392 GResolver *resolver;
393 GList *records;
394 gchar *name_server = NULL;
395
396 resolver = g_resolver_get_default ();
397
398 records = g_resolver_lookup_records (
399 resolver, domain, G_RESOLVER_RECORD_NS, cancellable, error);
400
401 /* This list is sorted per RFC 2782, so use the first item. */
402 if (records != NULL) {
403 GVariant *variant = records->data;
404 g_variant_get_child (variant, 0, "s", &name_server);
405 }
406
407 g_list_free_full (records, (GDestroyNotify) g_variant_unref);
408
409 g_object_unref (resolver);
410
411 return name_server;
412 }
413
414 static void
mail_autoconfig_abort_soup_session_cb(GCancellable * cancellable,SoupSession * soup_session)415 mail_autoconfig_abort_soup_session_cb (GCancellable *cancellable,
416 SoupSession *soup_session)
417 {
418 soup_session_abort (soup_session);
419 }
420
421 static gboolean
mail_autoconfig_lookup_uri_sync(EMailAutoconfig * autoconfig,const gchar * uri,SoupSession * soup_session,GCancellable * cancellable,GError ** error)422 mail_autoconfig_lookup_uri_sync (EMailAutoconfig *autoconfig,
423 const gchar *uri,
424 SoupSession *soup_session,
425 GCancellable *cancellable,
426 GError **error)
427 {
428 SoupMessage *soup_message;
429 gboolean success;
430 guint status;
431
432 soup_message = soup_message_new (SOUP_METHOD_GET, uri);
433
434 if (!soup_message) {
435 g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
436 _("Invalid URI: “%s”"), uri);
437 return FALSE;
438 }
439
440 soup_message_headers_append (
441 soup_message->request_headers,
442 "User-Agent", "Evolution/" VERSION VERSION_SUBSTRING " " VERSION_COMMENT);
443
444 status = soup_session_send_message (soup_session, soup_message);
445
446 success = SOUP_STATUS_IS_SUCCESSFUL (status);
447
448 if (success) {
449 GMarkupParseContext *context;
450 ParserClosure closure;
451
452 closure.autoconfig = autoconfig;
453 closure.result = NULL;
454
455 context = g_markup_parse_context_new (
456 &mail_autoconfig_parser, 0,
457 &closure, (GDestroyNotify) NULL);
458
459 success = g_markup_parse_context_parse (
460 context,
461 soup_message->response_body->data,
462 soup_message->response_body->length,
463 error);
464
465 if (success)
466 success = g_markup_parse_context_end_parse (context, error);
467
468 g_markup_parse_context_free (context);
469 } else {
470 g_set_error_literal (
471 error, SOUP_HTTP_ERROR,
472 soup_message->status_code,
473 soup_message->reason_phrase);
474 }
475
476 g_object_unref (soup_message);
477
478 return success;
479 }
480
481 static gboolean
mail_autoconfig_lookup(EMailAutoconfig * autoconfig,const gchar * domain,const gchar * emailmd5,GCancellable * cancellable,GError ** error)482 mail_autoconfig_lookup (EMailAutoconfig *autoconfig,
483 const gchar *domain,
484 const gchar *emailmd5,
485 GCancellable *cancellable,
486 GError **error)
487 {
488 ESourceRegistry *registry;
489 ESource *proxy_source;
490 SoupSession *soup_session;
491 gulong cancel_id = 0;
492 gchar *uri;
493 gboolean success = FALSE;
494
495 registry = e_mail_autoconfig_get_registry (autoconfig);
496 proxy_source = e_source_registry_ref_builtin_proxy (registry);
497
498 soup_session = soup_session_new_with_options (
499 SOUP_SESSION_PROXY_RESOLVER, G_PROXY_RESOLVER (proxy_source),
500 SOUP_SESSION_TIMEOUT, 15,
501 NULL);
502
503 g_object_unref (proxy_source);
504
505 if (G_IS_CANCELLABLE (cancellable))
506 cancel_id = g_cancellable_connect (
507 cancellable,
508 G_CALLBACK (mail_autoconfig_abort_soup_session_cb),
509 g_object_ref (soup_session),
510 (GDestroyNotify) g_object_unref);
511
512 /* First try user configuration in autoconfig.$DOMAIN URL and ignore error */
513 if (!success && ((error && !*error && !g_cancellable_set_error_if_cancelled (cancellable, error)) || !g_cancellable_is_cancelled (cancellable))) {
514 uri = g_strconcat ("https://autoconfig.", domain, "/mail/config-v1.1.xml?emailaddress=" FAKE_EVOLUTION_USER_STRING "%40", domain, "&emailmd5=", emailmd5, NULL);
515 success = mail_autoconfig_lookup_uri_sync (autoconfig, uri, soup_session, cancellable, NULL);
516 g_free (uri);
517 }
518
519 if (!success && ((error && !*error && !g_cancellable_set_error_if_cancelled (cancellable, error)) || !g_cancellable_is_cancelled (cancellable))) {
520 uri = g_strconcat ("http://autoconfig.", domain, "/mail/config-v1.1.xml?emailaddress=" FAKE_EVOLUTION_USER_STRING "%40", domain, "&emailmd5=", emailmd5, NULL);
521 success = mail_autoconfig_lookup_uri_sync (autoconfig, uri, soup_session, cancellable, NULL);
522 g_free (uri);
523 }
524
525 /* Then with $DOMAIN/.well-known/autoconfig/ and ignore error */
526 if (!success && ((error && !*error && !g_cancellable_set_error_if_cancelled (cancellable, error)) || !g_cancellable_is_cancelled (cancellable))) {
527 uri = g_strconcat ("https://", domain, "/.well-known/autoconfig/mail/config-v1.1.xml?emailaddress=" FAKE_EVOLUTION_USER_STRING "%40", domain, "&emailmd5=", emailmd5, NULL);
528 success = mail_autoconfig_lookup_uri_sync (autoconfig, uri, soup_session, cancellable, NULL);
529 g_free (uri);
530 }
531
532 if (!success && ((error && !*error && !g_cancellable_set_error_if_cancelled (cancellable, error)) || !g_cancellable_is_cancelled (cancellable))) {
533 uri = g_strconcat ("http://", domain, "/.well-known/autoconfig/mail/config-v1.1.xml?emailaddress=" FAKE_EVOLUTION_USER_STRING "%40", domain, "&emailmd5=", emailmd5, NULL);
534 success = mail_autoconfig_lookup_uri_sync (autoconfig, uri, soup_session, cancellable, NULL);
535 g_free (uri);
536 }
537
538 /* Final, try the upstream ISPDB and propagate error */
539 if (!success && ((error && !*error && !g_cancellable_set_error_if_cancelled (cancellable, error)) || !g_cancellable_is_cancelled (cancellable))) {
540 uri = g_strconcat (AUTOCONFIG_BASE_URI, domain, NULL);
541 success = mail_autoconfig_lookup_uri_sync (autoconfig, uri, soup_session, cancellable, error);
542 g_free (uri);
543 }
544
545 if (cancel_id > 0)
546 g_cancellable_disconnect (cancellable, cancel_id);
547
548 g_object_unref (soup_session);
549
550 return success;
551 }
552
553 static gboolean
mail_autoconfig_set_details(ESourceRegistry * registry,EMailAutoconfigResult * result,ESource * source,const gchar * extension_name,const gchar * default_backend_name)554 mail_autoconfig_set_details (ESourceRegistry *registry,
555 EMailAutoconfigResult *result,
556 ESource *source,
557 const gchar *extension_name,
558 const gchar *default_backend_name)
559 {
560 ESourceCamel *camel_ext;
561 ESourceBackend *backend_ext;
562 CamelSettings *settings;
563 const gchar *backend_name;
564
565 g_return_val_if_fail (result != NULL, FALSE);
566
567 if (!result->set)
568 return FALSE;
569
570 if (!e_source_has_extension (source, extension_name))
571 return FALSE;
572
573 backend_ext = e_source_get_extension (source, extension_name);
574 backend_name = e_source_backend_get_backend_name (backend_ext);
575 if (!backend_name || !*backend_name) {
576 e_source_backend_set_backend_name (backend_ext, default_backend_name);
577 backend_name = default_backend_name;
578 }
579
580 if (!backend_name)
581 return FALSE;
582
583 extension_name = e_source_camel_get_extension_name (backend_name);
584 camel_ext = e_source_get_extension (source, extension_name);
585
586 settings = e_source_camel_get_settings (camel_ext);
587 g_return_val_if_fail (CAMEL_IS_NETWORK_SETTINGS (settings), FALSE);
588
589 /* Set the security method before the port, to not have it overwritten
590 in New Mail Account wizard (binding callback). */
591 g_object_set (settings,
592 "auth-mechanism", result->auth_mechanism,
593 "security-method", result->security_method,
594 "user", result->user,
595 "host", result->host,
596 "port", result->port,
597 NULL);
598
599 if (result->host && registry) {
600 EOAuth2Service *oauth2_service;
601
602 /* Prefer OAuth2, if available */
603 oauth2_service = e_oauth2_services_find (e_source_registry_get_oauth2_services (registry), source);
604 if (!oauth2_service) {
605 oauth2_service = e_oauth2_services_guess (e_source_registry_get_oauth2_services (registry),
606 backend_name, result->host);
607 }
608
609 if (oauth2_service) {
610 g_object_set (settings,
611 "auth-mechanism", e_oauth2_service_get_name (oauth2_service),
612 NULL);
613 }
614
615 g_clear_object (&oauth2_service);
616 }
617
618 return TRUE;
619 }
620
621 #define E_TYPE_MAIL_CONFIG_LOOKUP_RESULT \
622 (e_mail_config_lookup_result_get_type ())
623 #define E_MAIL_CONFIG_LOOKUP_RESULT(obj) \
624 (G_TYPE_CHECK_INSTANCE_CAST \
625 ((obj), E_TYPE_MAIL_CONFIG_LOOKUP_RESULT, EMailConfigLookupResult))
626 #define E_IS_MAIL_CONFIG_LOOKUP_RESULT(obj) \
627 (G_TYPE_CHECK_INSTANCE_TYPE \
628 ((obj), E_TYPE_MAIL_CONFIG_LOOKUP_RESULT))
629
630 typedef struct _EMailConfigLookupResult EMailConfigLookupResult;
631 typedef struct _EMailConfigLookupResultClass EMailConfigLookupResultClass;
632
633 struct _EMailConfigLookupResult {
634 /*< private >*/
635 EConfigLookupResultSimple parent;
636
637 EMailAutoconfigResult result;
638 gchar *extension_name;
639 };
640
641 struct _EMailConfigLookupResultClass {
642 /*< private >*/
643 EConfigLookupResultSimpleClass parent_class;
644 };
645
646 GType e_mail_config_lookup_result_get_type (void) G_GNUC_CONST;
647
G_DEFINE_TYPE(EMailConfigLookupResult,e_mail_config_lookup_result,E_TYPE_CONFIG_LOOKUP_RESULT_SIMPLE)648 G_DEFINE_TYPE (EMailConfigLookupResult, e_mail_config_lookup_result, E_TYPE_CONFIG_LOOKUP_RESULT_SIMPLE)
649
650 static gboolean
651 mail_config_lookup_result_configure_source (EConfigLookupResult *lookup_result,
652 EConfigLookup *config_lookup,
653 ESource *source)
654 {
655 EMailConfigLookupResult *mail_result;
656
657 g_return_val_if_fail (E_IS_MAIL_CONFIG_LOOKUP_RESULT (lookup_result), FALSE);
658
659 mail_result = E_MAIL_CONFIG_LOOKUP_RESULT (lookup_result);
660
661 /* No chain up to parent method, not needed here, because not used */
662 return mail_autoconfig_set_details (
663 e_config_lookup_get_registry (config_lookup),
664 &mail_result->result, source,
665 mail_result->extension_name,
666 e_config_lookup_result_get_protocol (lookup_result));
667 }
668
669 static void
mail_config_lookup_result_finalize(GObject * object)670 mail_config_lookup_result_finalize (GObject *object)
671 {
672 EMailConfigLookupResult *mail_result = E_MAIL_CONFIG_LOOKUP_RESULT (object);
673
674 g_free (mail_result->result.user);
675 g_free (mail_result->result.host);
676 g_free (mail_result->result.auth_mechanism);
677 g_free (mail_result->extension_name);
678
679 /* Chain up to parent's method. */
680 G_OBJECT_CLASS (e_mail_config_lookup_result_parent_class)->finalize (object);
681 }
682
683 static void
e_mail_config_lookup_result_class_init(EMailConfigLookupResultClass * klass)684 e_mail_config_lookup_result_class_init (EMailConfigLookupResultClass *klass)
685 {
686 EConfigLookupResultSimpleClass *simple_result_class;
687 GObjectClass *object_class;
688
689 object_class = G_OBJECT_CLASS (klass);
690 object_class->finalize = mail_config_lookup_result_finalize;
691
692 simple_result_class = E_CONFIG_LOOKUP_RESULT_SIMPLE_CLASS (klass);
693 simple_result_class->configure_source = mail_config_lookup_result_configure_source;
694 }
695
696 static void
e_mail_config_lookup_result_init(EMailConfigLookupResult * mail_result)697 e_mail_config_lookup_result_init (EMailConfigLookupResult *mail_result)
698 {
699 }
700
701 static EConfigLookupResult *
e_mail_config_lookup_result_new(EConfigLookupResultKind kind,gint priority,const gchar * protocol,const gchar * display_name,const gchar * description,const EMailAutoconfigResult * result,const gchar * extension_name)702 e_mail_config_lookup_result_new (EConfigLookupResultKind kind,
703 gint priority,
704 const gchar *protocol,
705 const gchar *display_name,
706 const gchar *description,
707 const EMailAutoconfigResult *result,
708 const gchar *extension_name)
709 {
710 EMailConfigLookupResult *mail_result;
711
712 g_return_val_if_fail (protocol != NULL, NULL);
713 g_return_val_if_fail (display_name != NULL, NULL);
714 g_return_val_if_fail (description != NULL, NULL);
715 g_return_val_if_fail (result != NULL, NULL);
716 g_return_val_if_fail (extension_name != NULL, NULL);
717
718 mail_result = g_object_new (E_TYPE_MAIL_CONFIG_LOOKUP_RESULT,
719 "kind", kind,
720 "priority", priority,
721 "is-complete", TRUE,
722 "protocol", protocol,
723 "display-name", display_name,
724 "description", description,
725 "password", NULL,
726 NULL);
727
728 mail_result->result.set = result->set;
729 mail_result->result.user = g_strdup (result->user);
730 mail_result->result.host = g_strdup (result->host);
731 mail_result->result.port = result->port;
732 mail_result->result.auth_mechanism = g_strdup (result->auth_mechanism);
733 mail_result->result.security_method = result->security_method;
734 mail_result->extension_name = g_strdup (extension_name);
735
736 return E_CONFIG_LOOKUP_RESULT (mail_result);
737 }
738
739 static void
mail_autoconfig_result_to_config_lookup(EMailAutoconfig * mail_autoconfig,EConfigLookup * config_lookup,EMailAutoconfigResult * result,gint priority,const gchar * protocol,const gchar * display_name,const gchar * extension_name)740 mail_autoconfig_result_to_config_lookup (EMailAutoconfig *mail_autoconfig,
741 EConfigLookup *config_lookup,
742 EMailAutoconfigResult *result,
743 gint priority,
744 const gchar *protocol,
745 const gchar *display_name,
746 const gchar *extension_name)
747 {
748 EConfigLookupResult *lookup_result;
749 EConfigLookupResultKind kind;
750 GString *description;
751
752 g_return_if_fail (E_IS_MAIL_AUTOCONFIG (mail_autoconfig));
753 g_return_if_fail (E_IS_CONFIG_LOOKUP (config_lookup));
754 g_return_if_fail (result != NULL);
755 g_return_if_fail (protocol != NULL);
756 g_return_if_fail (display_name != NULL);
757 g_return_if_fail (extension_name != NULL);
758
759 if (!result->set)
760 return;
761
762 kind = E_CONFIG_LOOKUP_RESULT_MAIL_RECEIVE;
763 if (g_strcmp0 (extension_name, E_SOURCE_EXTENSION_MAIL_TRANSPORT) == 0)
764 kind = E_CONFIG_LOOKUP_RESULT_MAIL_SEND;
765
766 description = g_string_new ("");
767
768 g_string_append_printf (description, _("Host: %s:%d"), result->host, result->port);
769
770 if (result->user && *result->user) {
771 g_string_append_c (description, '\n');
772 g_string_append_printf (description, _("User: %s"), result->user);
773 }
774
775 g_string_append_c (description, '\n');
776 g_string_append_printf (description, _("Security method: %s"),
777 result->security_method == CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT ? _("TLS") :
778 result->security_method == CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT ? _("STARTTLS") : _("None"));
779
780 if (result->auth_mechanism && *result->auth_mechanism) {
781 g_string_append_c (description, '\n');
782 g_string_append_printf (description, _("Authentication mechanism: %s"), result->auth_mechanism);
783 }
784
785 lookup_result = e_mail_config_lookup_result_new (kind, priority, protocol, display_name, description->str, result, extension_name);
786 e_config_lookup_add_result (config_lookup, lookup_result);
787
788 g_string_free (description, TRUE);
789 }
790
791 static gchar *
mail_autoconfig_calc_emailmd5(const gchar * email_address)792 mail_autoconfig_calc_emailmd5 (const gchar *email_address)
793 {
794 gchar *lowercase, *emailmd5;
795
796 if (!email_address)
797 return NULL;
798
799 lowercase = g_ascii_strdown (email_address, -1);
800 if (!lowercase || !*lowercase) {
801 g_free (lowercase);
802 return NULL;
803 }
804
805 emailmd5 = g_compute_checksum_for_string (G_CHECKSUM_MD5, lowercase, -1);
806
807 g_free (lowercase);
808
809 return emailmd5;
810 }
811
812 static void
mail_autoconfig_set_email_address(EMailAutoconfig * autoconfig,const gchar * email_address)813 mail_autoconfig_set_email_address (EMailAutoconfig *autoconfig,
814 const gchar *email_address)
815 {
816 g_return_if_fail (email_address != NULL);
817 g_return_if_fail (autoconfig->priv->email_address == NULL);
818
819 autoconfig->priv->email_address = g_strdup (email_address);
820 }
821
822 static void
mail_autoconfig_set_use_domain(EMailAutoconfig * autoconfig,const gchar * use_domain)823 mail_autoconfig_set_use_domain (EMailAutoconfig *autoconfig,
824 const gchar *use_domain)
825 {
826 if (g_strcmp0 (autoconfig->priv->use_domain, use_domain) != 0) {
827 g_free (autoconfig->priv->use_domain);
828 autoconfig->priv->use_domain = g_strdup (use_domain);
829 }
830 }
831
832 static void
mail_autoconfig_set_registry(EMailAutoconfig * autoconfig,ESourceRegistry * registry)833 mail_autoconfig_set_registry (EMailAutoconfig *autoconfig,
834 ESourceRegistry *registry)
835 {
836 g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
837 g_return_if_fail (autoconfig->priv->registry == NULL);
838
839 autoconfig->priv->registry = g_object_ref (registry);
840 }
841
842 static void
mail_autoconfig_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)843 mail_autoconfig_set_property (GObject *object,
844 guint property_id,
845 const GValue *value,
846 GParamSpec *pspec)
847 {
848 switch (property_id) {
849 case PROP_EMAIL_ADDRESS:
850 mail_autoconfig_set_email_address (
851 E_MAIL_AUTOCONFIG (object),
852 g_value_get_string (value));
853 return;
854
855 case PROP_REGISTRY:
856 mail_autoconfig_set_registry (
857 E_MAIL_AUTOCONFIG (object),
858 g_value_get_object (value));
859 return;
860
861 case PROP_USE_DOMAIN:
862 mail_autoconfig_set_use_domain (
863 E_MAIL_AUTOCONFIG (object),
864 g_value_get_string (value));
865 return;
866 }
867
868 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
869 }
870
871 static void
mail_autoconfig_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)872 mail_autoconfig_get_property (GObject *object,
873 guint property_id,
874 GValue *value,
875 GParamSpec *pspec)
876 {
877 switch (property_id) {
878 case PROP_EMAIL_ADDRESS:
879 g_value_set_string (
880 value,
881 e_mail_autoconfig_get_email_address (
882 E_MAIL_AUTOCONFIG (object)));
883 return;
884
885 case PROP_REGISTRY:
886 g_value_set_object (
887 value,
888 e_mail_autoconfig_get_registry (
889 E_MAIL_AUTOCONFIG (object)));
890 return;
891
892 case PROP_USE_DOMAIN:
893 g_value_set_string (
894 value,
895 e_mail_autoconfig_get_use_domain (
896 E_MAIL_AUTOCONFIG (object)));
897 return;
898 }
899
900 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
901 }
902
903 static void
mail_autoconfig_dispose(GObject * object)904 mail_autoconfig_dispose (GObject *object)
905 {
906 EMailAutoconfigPrivate *priv;
907
908 priv = E_MAIL_AUTOCONFIG_GET_PRIVATE (object);
909
910 g_clear_object (&priv->registry);
911
912 /* Chain up to parent's dispose() method. */
913 G_OBJECT_CLASS (e_mail_autoconfig_parent_class)->dispose (object);
914 }
915
916 static void
mail_autoconfig_finalize(GObject * object)917 mail_autoconfig_finalize (GObject *object)
918 {
919 EMailAutoconfigPrivate *priv;
920
921 priv = E_MAIL_AUTOCONFIG_GET_PRIVATE (object);
922
923 g_free (priv->email_address);
924 g_free (priv->email_local_part);
925 g_free (priv->email_domain_part);
926 g_free (priv->use_domain);
927
928 g_free (priv->imap_result.user);
929 g_free (priv->imap_result.host);
930 g_free (priv->imap_result.auth_mechanism);
931 g_free (priv->pop3_result.user);
932 g_free (priv->pop3_result.host);
933 g_free (priv->pop3_result.auth_mechanism);
934 g_free (priv->smtp_result.user);
935 g_free (priv->smtp_result.host);
936 g_free (priv->smtp_result.auth_mechanism);
937
938 /* Chain up to parent's finalize() method. */
939 G_OBJECT_CLASS (e_mail_autoconfig_parent_class)->finalize (object);
940 }
941
942 static gboolean
mail_autoconfig_initable_init(GInitable * initable,GCancellable * cancellable,GError ** error)943 mail_autoconfig_initable_init (GInitable *initable,
944 GCancellable *cancellable,
945 GError **error)
946 {
947 EMailAutoconfig *autoconfig;
948 const gchar *email_address;
949 const gchar *domain;
950 const gchar *cp;
951 gchar *name_server, *emailmd5;
952 gboolean success = FALSE;
953 GError *local_error = NULL;
954
955 autoconfig = E_MAIL_AUTOCONFIG (initable);
956 email_address = e_mail_autoconfig_get_email_address (autoconfig);
957
958 if (email_address == NULL) {
959 g_set_error_literal (
960 error, G_IO_ERROR,
961 G_IO_ERROR_INVALID_ARGUMENT,
962 _("No email address provided"));
963 return FALSE;
964 }
965
966 cp = strchr (email_address, '@');
967 if (cp == NULL) {
968 g_set_error_literal (
969 error, G_IO_ERROR,
970 G_IO_ERROR_INVALID_ARGUMENT,
971 _("Missing domain in email address"));
972 return FALSE;
973 }
974
975 domain = cp + 1;
976
977 autoconfig->priv->email_local_part =
978 g_strndup (email_address, cp - email_address);
979 autoconfig->priv->email_domain_part = g_strdup (domain);
980
981 if (autoconfig->priv->use_domain && *autoconfig->priv->use_domain)
982 domain = autoconfig->priv->use_domain;
983
984 emailmd5 = mail_autoconfig_calc_emailmd5 (email_address);
985
986 /* First try the email address domain verbatim. */
987 success = mail_autoconfig_lookup (
988 autoconfig, domain, emailmd5, cancellable, &local_error);
989
990 g_warn_if_fail (
991 (success && local_error == NULL) ||
992 (!success && local_error != NULL));
993
994 if (success) {
995 g_free (emailmd5);
996 return TRUE;
997 }
998
999 /* "404 Not Found" errors are non-fatal this time around. */
1000 if (ERROR_IS_NOT_FOUND (local_error)) {
1001 g_clear_error (&local_error);
1002 } else {
1003 g_propagate_error (error, local_error);
1004 g_free (emailmd5);
1005 return FALSE;
1006 }
1007
1008 /* Look up an authoritative name server for the email address
1009 * domain according to its "name server" (NS) DNS record. */
1010 name_server = mail_autoconfig_resolve_name_server (
1011 domain, cancellable, error);
1012
1013 if (!name_server) {
1014 g_free (emailmd5);
1015 return FALSE;
1016 }
1017
1018 /* Widdle away segments of the name server domain until
1019 * we find a match, or until we widdle down to nothing. */
1020
1021 cp = name_server;
1022 while (cp != NULL && strchr (cp, '.') != NULL) {
1023 g_clear_error (&local_error);
1024
1025 success = mail_autoconfig_lookup (
1026 autoconfig, cp, emailmd5, cancellable, &local_error);
1027
1028 g_warn_if_fail (
1029 (success && local_error == NULL) ||
1030 (!success && local_error != NULL));
1031
1032 if (success || !ERROR_IS_NOT_FOUND (local_error))
1033 break;
1034
1035 cp = strchr (cp, '.');
1036 if (cp != NULL)
1037 cp++;
1038 }
1039
1040 if (!success && !local_error)
1041 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Unknown error"));
1042 else if (local_error)
1043 g_propagate_error (error, local_error);
1044
1045 g_free (name_server);
1046 g_free (emailmd5);
1047
1048 return success;
1049 }
1050
1051 static void
e_mail_autoconfig_class_init(EMailAutoconfigClass * class)1052 e_mail_autoconfig_class_init (EMailAutoconfigClass *class)
1053 {
1054 GObjectClass *object_class;
1055
1056 g_type_class_add_private (class, sizeof (EMailAutoconfigPrivate));
1057
1058 object_class = G_OBJECT_CLASS (class);
1059 object_class->set_property = mail_autoconfig_set_property;
1060 object_class->get_property = mail_autoconfig_get_property;
1061 object_class->dispose = mail_autoconfig_dispose;
1062 object_class->finalize = mail_autoconfig_finalize;
1063
1064 g_object_class_install_property (
1065 object_class,
1066 PROP_EMAIL_ADDRESS,
1067 g_param_spec_string (
1068 "email-address",
1069 "Email Address",
1070 "The address from which to query config data",
1071 NULL,
1072 G_PARAM_READWRITE |
1073 G_PARAM_CONSTRUCT_ONLY |
1074 G_PARAM_STATIC_STRINGS));
1075
1076 g_object_class_install_property (
1077 object_class,
1078 PROP_REGISTRY,
1079 g_param_spec_object (
1080 "registry",
1081 "Registry",
1082 "Data source registry",
1083 E_TYPE_SOURCE_REGISTRY,
1084 G_PARAM_READWRITE |
1085 G_PARAM_CONSTRUCT_ONLY |
1086 G_PARAM_STATIC_STRINGS));
1087
1088 g_object_class_install_property (
1089 object_class,
1090 PROP_USE_DOMAIN,
1091 g_param_spec_string (
1092 "use-domain",
1093 "Use Domain",
1094 "A domain to use, instead of the one from email-address",
1095 NULL,
1096 G_PARAM_READWRITE |
1097 G_PARAM_CONSTRUCT_ONLY |
1098 G_PARAM_STATIC_STRINGS));
1099 }
1100
1101 static void
e_mail_autoconfig_initable_init(GInitableIface * iface)1102 e_mail_autoconfig_initable_init (GInitableIface *iface)
1103 {
1104 iface->init = mail_autoconfig_initable_init;
1105 }
1106
1107 static void
e_mail_autoconfig_init(EMailAutoconfig * autoconfig)1108 e_mail_autoconfig_init (EMailAutoconfig *autoconfig)
1109 {
1110 autoconfig->priv = E_MAIL_AUTOCONFIG_GET_PRIVATE (autoconfig);
1111 }
1112
1113 EMailAutoconfig *
e_mail_autoconfig_new_sync(ESourceRegistry * registry,const gchar * email_address,const gchar * use_domain,GCancellable * cancellable,GError ** error)1114 e_mail_autoconfig_new_sync (ESourceRegistry *registry,
1115 const gchar *email_address,
1116 const gchar *use_domain,
1117 GCancellable *cancellable,
1118 GError **error)
1119 {
1120 g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
1121 g_return_val_if_fail (email_address != NULL, NULL);
1122
1123 return g_initable_new (
1124 E_TYPE_MAIL_AUTOCONFIG,
1125 cancellable, error,
1126 "registry", registry,
1127 "email-address", email_address,
1128 "use-domain", use_domain,
1129 NULL);
1130 }
1131
1132 void
e_mail_autoconfig_new(ESourceRegistry * registry,const gchar * email_address,const gchar * use_domain,gint io_priority,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1133 e_mail_autoconfig_new (ESourceRegistry *registry,
1134 const gchar *email_address,
1135 const gchar *use_domain,
1136 gint io_priority,
1137 GCancellable *cancellable,
1138 GAsyncReadyCallback callback,
1139 gpointer user_data)
1140 {
1141 g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
1142 g_return_if_fail (email_address != NULL);
1143
1144 g_async_initable_new_async (
1145 E_TYPE_MAIL_AUTOCONFIG,
1146 io_priority, cancellable,
1147 callback, user_data,
1148 "registry", registry,
1149 "email-address", email_address,
1150 "use-domain", use_domain,
1151 NULL);
1152 }
1153
1154 EMailAutoconfig *
e_mail_autoconfig_finish(GAsyncResult * result,GError ** error)1155 e_mail_autoconfig_finish (GAsyncResult *result,
1156 GError **error)
1157 {
1158 GObject *source_object;
1159 GObject *autoconfig;
1160
1161 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
1162
1163 source_object = g_async_result_get_source_object (result);
1164 g_return_val_if_fail (source_object != NULL, NULL);
1165
1166 autoconfig = g_async_initable_new_finish (
1167 G_ASYNC_INITABLE (source_object), result, error);
1168
1169 g_object_unref (source_object);
1170
1171 if (autoconfig == NULL)
1172 return NULL;
1173
1174 return E_MAIL_AUTOCONFIG (autoconfig);
1175 }
1176
1177 /**
1178 * e_mail_autoconfig_get_registry:
1179 * @autoconfig: an #EMailAutoconfig
1180 *
1181 * Returns the #ESourceRegistry passed to e_mail_autoconfig_new() or
1182 * e_mail_autoconfig_new_sync().
1183 *
1184 * Returns: an #ESourceRegistry
1185 **/
1186 ESourceRegistry *
e_mail_autoconfig_get_registry(EMailAutoconfig * autoconfig)1187 e_mail_autoconfig_get_registry (EMailAutoconfig *autoconfig)
1188 {
1189 g_return_val_if_fail (E_IS_MAIL_AUTOCONFIG (autoconfig), NULL);
1190
1191 return autoconfig->priv->registry;
1192 }
1193
1194 const gchar *
e_mail_autoconfig_get_email_address(EMailAutoconfig * autoconfig)1195 e_mail_autoconfig_get_email_address (EMailAutoconfig *autoconfig)
1196 {
1197 g_return_val_if_fail (E_IS_MAIL_AUTOCONFIG (autoconfig), NULL);
1198
1199 return autoconfig->priv->email_address;
1200 }
1201
1202 const gchar *
e_mail_autoconfig_get_use_domain(EMailAutoconfig * autoconfig)1203 e_mail_autoconfig_get_use_domain (EMailAutoconfig *autoconfig)
1204 {
1205 g_return_val_if_fail (E_IS_MAIL_AUTOCONFIG (autoconfig), NULL);
1206
1207 return autoconfig->priv->use_domain;
1208 }
1209
1210 gboolean
e_mail_autoconfig_set_imap_details(EMailAutoconfig * autoconfig,ESource * imap_source)1211 e_mail_autoconfig_set_imap_details (EMailAutoconfig *autoconfig,
1212 ESource *imap_source)
1213 {
1214 g_return_val_if_fail (E_IS_MAIL_AUTOCONFIG (autoconfig), FALSE);
1215 g_return_val_if_fail (E_IS_SOURCE (imap_source), FALSE);
1216
1217 return mail_autoconfig_set_details (
1218 autoconfig->priv->registry,
1219 &autoconfig->priv->imap_result,
1220 imap_source, E_SOURCE_EXTENSION_MAIL_ACCOUNT, "imapx");
1221 }
1222
1223 gboolean
e_mail_autoconfig_set_pop3_details(EMailAutoconfig * autoconfig,ESource * pop3_source)1224 e_mail_autoconfig_set_pop3_details (EMailAutoconfig *autoconfig,
1225 ESource *pop3_source)
1226 {
1227 g_return_val_if_fail (E_IS_MAIL_AUTOCONFIG (autoconfig), FALSE);
1228 g_return_val_if_fail (E_IS_SOURCE (pop3_source), FALSE);
1229
1230 return mail_autoconfig_set_details (
1231 autoconfig->priv->registry,
1232 &autoconfig->priv->pop3_result,
1233 pop3_source, E_SOURCE_EXTENSION_MAIL_ACCOUNT, "pop3");
1234 }
1235
1236 gboolean
e_mail_autoconfig_set_smtp_details(EMailAutoconfig * autoconfig,ESource * smtp_source)1237 e_mail_autoconfig_set_smtp_details (EMailAutoconfig *autoconfig,
1238 ESource *smtp_source)
1239 {
1240 g_return_val_if_fail (E_IS_MAIL_AUTOCONFIG (autoconfig), FALSE);
1241 g_return_val_if_fail (E_IS_SOURCE (smtp_source), FALSE);
1242
1243 return mail_autoconfig_set_details (
1244 autoconfig->priv->registry,
1245 &autoconfig->priv->smtp_result,
1246 smtp_source, E_SOURCE_EXTENSION_MAIL_TRANSPORT, "smtp");
1247 }
1248
1249 void
e_mail_autoconfig_dump_results(EMailAutoconfig * autoconfig)1250 e_mail_autoconfig_dump_results (EMailAutoconfig *autoconfig)
1251 {
1252 const gchar *email_address;
1253 gboolean have_results;
1254
1255 g_return_if_fail (E_IS_MAIL_AUTOCONFIG (autoconfig));
1256
1257 email_address = autoconfig->priv->email_address;
1258
1259 have_results =
1260 autoconfig->priv->imap_result.set ||
1261 autoconfig->priv->pop3_result.set ||
1262 autoconfig->priv->smtp_result.set;
1263
1264 if (have_results) {
1265 if (autoconfig->priv->use_domain && *autoconfig->priv->use_domain)
1266 g_print ("Results for <%s> and domain '%s'\n", email_address, autoconfig->priv->use_domain);
1267 else
1268 g_print ("Results for <%s>\n", email_address);
1269
1270 if (autoconfig->priv->imap_result.set) {
1271 g_print (
1272 "IMAP: %s@%s:%u\n",
1273 autoconfig->priv->imap_result.user,
1274 autoconfig->priv->imap_result.host,
1275 autoconfig->priv->imap_result.port);
1276 }
1277
1278 if (autoconfig->priv->pop3_result.set) {
1279 g_print (
1280 "POP3: %s@%s:%u\n",
1281 autoconfig->priv->pop3_result.user,
1282 autoconfig->priv->pop3_result.host,
1283 autoconfig->priv->pop3_result.port);
1284 }
1285
1286 if (autoconfig->priv->smtp_result.set) {
1287 g_print (
1288 "SMTP: %s@%s:%u\n",
1289 autoconfig->priv->smtp_result.user,
1290 autoconfig->priv->smtp_result.host,
1291 autoconfig->priv->smtp_result.port);
1292 }
1293
1294 } else if (autoconfig->priv->use_domain && *autoconfig->priv->use_domain) {
1295 g_print ("No results for <%s> and domain '%s'\n", email_address, autoconfig->priv->use_domain);
1296 } else {
1297 g_print ("No results for <%s>\n", email_address);
1298 }
1299 }
1300
1301 /**
1302 * e_mail_autoconfig_copy_results_to_config_lookup:
1303 * @mail_autoconfig: an #EMailAutoconfig
1304 * @config_lookup: an #EConfigLookup
1305 *
1306 * Copies any valid result from @mail_autoconfig to @config_lookup.
1307 *
1308 * Since: 3.26
1309 **/
1310 void
e_mail_autoconfig_copy_results_to_config_lookup(EMailAutoconfig * mail_autoconfig,EConfigLookup * config_lookup)1311 e_mail_autoconfig_copy_results_to_config_lookup (EMailAutoconfig *mail_autoconfig,
1312 EConfigLookup *config_lookup)
1313 {
1314 g_return_if_fail (E_IS_MAIL_AUTOCONFIG (mail_autoconfig));
1315 g_return_if_fail (E_IS_CONFIG_LOOKUP (config_lookup));
1316
1317 mail_autoconfig_result_to_config_lookup (mail_autoconfig, config_lookup,
1318 &mail_autoconfig->priv->imap_result,
1319 E_CONFIG_LOOKUP_RESULT_PRIORITY_IMAP,
1320 "imapx",
1321 _("IMAP server"),
1322 E_SOURCE_EXTENSION_MAIL_ACCOUNT);
1323
1324 mail_autoconfig_result_to_config_lookup (mail_autoconfig, config_lookup,
1325 &mail_autoconfig->priv->pop3_result,
1326 E_CONFIG_LOOKUP_RESULT_PRIORITY_POP3,
1327 "pop",
1328 _("POP3 server"),
1329 E_SOURCE_EXTENSION_MAIL_ACCOUNT);
1330
1331 mail_autoconfig_result_to_config_lookup (mail_autoconfig, config_lookup,
1332 &mail_autoconfig->priv->smtp_result,
1333 E_CONFIG_LOOKUP_RESULT_PRIORITY_SMTP,
1334 "smtp",
1335 _("SMTP server"),
1336 E_SOURCE_EXTENSION_MAIL_TRANSPORT);
1337 }
1338