No issues found
Tool | Failure ID | Location | Function | Message | Data |
---|---|---|---|---|---|
clang-analyzer | no-output-found | e-mail-autoconfig.c | Message(text='Unable to locate XML output from invoke-clang-analyzer') | None | |
clang-analyzer | no-output-found | e-mail-autoconfig.c | Message(text='Unable to locate XML output from invoke-clang-analyzer') | None | |
clang-analyzer | no-output-found | e-mail-autoconfig.c | Message(text='Unable to locate XML output from invoke-clang-analyzer') | None |
1 /*
2 * e-mail-autoconfig.c
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with the program; if not, see <http://www.gnu.org/licenses/>
16 *
17 */
18
19 #include "e-mail-autoconfig.h"
20
21 #include <config.h>
22 #include <string.h>
23 #include <glib/gi18n-lib.h>
24
25 /* Stuff for DNS querying and message parsing. */
26 #include <netdb.h>
27 #include <netinet/in.h>
28 #include <resolv.h>
29 #include <arpa/nameser.h>
30 #if defined(HAVE_ARPA_NAMESER_COMPAT_H) && !defined(GETSHORT)
31 #include <arpa/nameser_compat.h>
32 #endif
33
34 /* For error codes. */
35 #include <libsoup/soup.h>
36
37 #define E_MAIL_AUTOCONFIG_GET_PRIVATE(obj) \
38 (G_TYPE_INSTANCE_GET_PRIVATE \
39 ((obj), E_TYPE_MAIL_AUTOCONFIG, EMailAutoconfigPrivate))
40
41 #define AUTOCONFIG_BASE_URI \
42 "http://api.gnome.org/evolution/autoconfig/1.1/"
43
44 /* XXX g_file_load_contents() on an "http://" URI returns error codes
45 * in the SOUP_HTTP_ERROR domain instead of the G_IO_ERROR domain.
46 * That is both undocumented and unexpected. */
47 #define ERROR_IS_NOT_FOUND(error) \
48 (g_error_matches ((error), SOUP_HTTP_ERROR, SOUP_STATUS_NOT_FOUND))
49
50 typedef struct _ParserClosure ParserClosure;
51 typedef struct _ResolverClosure ResolverClosure;
52
53 struct _EMailAutoconfigPrivate {
54 gchar *email_address;
55 gchar *email_local_part;
56 gchar *email_domain_part;
57 gchar *markup_content;
58 };
59
60 struct _ParserClosure {
61 CamelNetworkSettings *network_settings;
62 const gchar *expected_type;
63 const gchar *email_address;
64 const gchar *email_local_part;
65 const gchar *email_domain_part;
66 gboolean in_server_element;
67 gboolean settings_modified;
68 };
69
70 struct _ResolverClosure {
71 volatile gint ref_count;
72 GMainContext *main_context;
73 GMainLoop *main_loop;
74 gchar *domain_name;
75 gchar *name_server;
76 GError *error;
77 };
78
79 enum {
80 PROP_0,
81 PROP_EMAIL_ADDRESS
82 };
83
84 /* Forward Declarations */
85 static void e_mail_autoconfig_initable_init (GInitableIface *interface);
86
87 /* By default, the GAsyncInitable interface calls GInitable.init()
88 * from a separate thread, so we only have to override GInitable. */
89 G_DEFINE_TYPE_WITH_CODE (
90 EMailAutoconfig,
91 e_mail_autoconfig,
92 G_TYPE_OBJECT,
93 G_IMPLEMENT_INTERFACE (
94 G_TYPE_INITABLE, e_mail_autoconfig_initable_init)
95 G_IMPLEMENT_INTERFACE (
96 G_TYPE_ASYNC_INITABLE, NULL))
97
98 static ResolverClosure *
99 resolver_closure_new (const gchar *domain_name)
100 {
101 ResolverClosure *closure;
102
103 closure = g_slice_new0 (ResolverClosure);
104 closure->domain_name = g_strdup (domain_name);
105 closure->main_context = g_main_context_new ();
106 closure->main_loop = g_main_loop_new (closure->main_context, FALSE);
107 closure->ref_count = 1;
108
109 return closure;
110 }
111
112 static ResolverClosure *
113 resolver_closure_ref (ResolverClosure *closure)
114 {
115 g_return_val_if_fail (closure != NULL, NULL);
116 g_return_val_if_fail (closure->ref_count > 0, NULL);
117
118 g_atomic_int_inc (&closure->ref_count);
119
120 return closure;
121 }
122
123 static void
124 resolver_closure_unref (ResolverClosure *closure)
125 {
126 g_return_if_fail (closure != NULL);
127 g_return_if_fail (closure->ref_count > 0);
128
129 if (g_atomic_int_dec_and_test (&closure->ref_count)) {
130 g_main_context_unref (closure->main_context);
131 g_main_loop_unref (closure->main_loop);
132 g_free (closure->domain_name);
133 g_free (closure->name_server);
134 g_clear_error (&closure->error);
135 g_slice_free (ResolverClosure, closure);
136 }
137 }
138
139 static gboolean
140 mail_autoconfig_resolver_idle_quit (gpointer user_data)
141 {
142 GMainLoop *main_loop = user_data;
143
144 g_main_loop_quit (main_loop);
145
146 return FALSE;
147 }
148
149 static void
150 mail_autoconfig_resolver_cancelled (GCancellable *cancellable,
151 ResolverClosure *closure)
152 {
153 GSource *source;
154
155 source = g_idle_source_new ();
156 g_source_set_callback (
157 source,
158 mail_autoconfig_resolver_idle_quit,
159 g_main_loop_ref (closure->main_loop),
160 (GDestroyNotify) g_main_loop_unref);
161 g_source_attach (source, closure->main_context);
162 g_source_unref (source);
163 }
164
165 static gpointer
166 mail_autoconfig_resolver_thread (gpointer user_data)
167 {
168 ResolverClosure *closure = user_data;
169 HEADER *header;
170 guchar answer[1024];
171 gchar namebuf[1024];
172 guchar *end, *cp;
173 gint count;
174 gint length;
175 gint herr;
176
177 /* Query DNS for the MX record for the domain name given in the
178 * email address. We need an authoritative name server for it. */
179
180 length = res_query (
181 closure->domain_name, C_IN, T_MX,
182 answer, sizeof (answer));
183 herr = h_errno; /* h_errno is defined in <netdb.h> */
184
185 /* Based heavily on _g_resolver_targets_from_res_query().
186 * The binary DNS message format is described in RFC 1035. */
187
188 if (length <= 0) {
189 if (length == 0 || herr == HOST_NOT_FOUND || herr == NO_DATA)
190 g_set_error (
191 &closure->error,
192 G_RESOLVER_ERROR,
193 G_RESOLVER_ERROR_NOT_FOUND,
194 _("No mail exchanger record for '%s'"),
195 closure->domain_name);
196 else if (herr == TRY_AGAIN)
197 g_set_error (
198 &closure->error,
199 G_RESOLVER_ERROR,
200 G_RESOLVER_ERROR_TEMPORARY_FAILURE,
201 _("Temporarily unable to resolve '%s'"),
202 closure->domain_name);
203 else
204 g_set_error (
205 &closure->error,
206 G_RESOLVER_ERROR,
207 G_RESOLVER_ERROR_INTERNAL,
208 _("Error resolving '%s'"),
209 closure->domain_name);
210 goto exit;
211 }
212
213 header = (HEADER *) answer;
214 cp = answer + sizeof (HEADER);
215 end = answer + length;
216
217 /* Skip the 'question' section. */
218 count = ntohs (header->qdcount);
219 while (count-- && cp < end) {
220 cp += dn_expand (answer, end, cp, namebuf, sizeof (namebuf));
221 cp += 2; /* skip QTYPE */
222 cp += 2; /* skip QCLASS */
223 }
224
225 /* Skip the 'answers' section. */
226 count = ntohs (header->ancount);
227 while (count-- && cp < end) {
228 guint16 rdlength;
229 cp += dn_expand (answer, end, cp, namebuf, sizeof (namebuf));
230 cp += 2; /* skip TYPE */
231 cp += 2; /* skip CLASS */
232 cp += 4; /* skip TTL */
233 GETSHORT (rdlength, cp); /* read RDLENGTH */
234 cp += rdlength; /* skip RDATA */
235 }
236
237 /* Read the 'authority' section. */
238 count = ntohs (header->nscount);
239 while (count-- && cp < end) {
240 guint16 type, qclass, rdlength;
241 cp += dn_expand (answer, end, cp, namebuf, sizeof (namebuf));
242 GETSHORT (type, cp);
243 GETSHORT (qclass, cp);
244 cp += 4; /* skip TTL */
245 GETSHORT (rdlength, cp);
246
247 if (type != T_NS || qclass != C_IN) {
248 cp += rdlength;
249 continue;
250 }
251
252 cp += dn_expand (answer, end, cp, namebuf, sizeof (namebuf));
253
254 /* Pick the first T_NS record we find. */
255 closure->name_server = g_strdup (namebuf);
256 break;
257 }
258
259 if (closure->name_server == NULL)
260 g_set_error (
261 &closure->error,
262 G_RESOLVER_ERROR,
263 G_RESOLVER_ERROR_NOT_FOUND,
264 _("No authoritative name server for '%s'"),
265 closure->domain_name);
266
267 exit:
268 g_main_loop_quit (closure->main_loop);
269 resolver_closure_unref (closure);
270
271 return NULL; /* return value is not used */
272 }
273
274 static gchar *
275 mail_autoconfig_resolve_authority (const gchar *domain,
276 GCancellable *cancellable,
277 GError **error)
278 {
279 ResolverClosure *closure;
280 GThread *resolver_thread;
281 gchar *name_server = NULL;
282 gulong cancel_id = 0;
283
284 closure = resolver_closure_new (domain);
285
286 /* DNS record lookup is not cancellable, so we run it in a
287 * separate thread. We don't join with the thread, however,
288 * because if we get cancelled we want to return immediately.
289 * So use a reference count on the thread closure and always
290 * let the thread run to completion even if we're not around
291 * any longer to pick up the result. */
292 resolver_thread = g_thread_create (
293 mail_autoconfig_resolver_thread,
294 resolver_closure_ref (closure),
295 FALSE /* not joinable */, error);
296
297 if (resolver_thread == NULL)
298 return FALSE;
299
300 if (G_IS_CANCELLABLE (cancellable))
301 cancel_id = g_cancellable_connect (
302 cancellable,
303 G_CALLBACK (mail_autoconfig_resolver_cancelled),
304 resolver_closure_ref (closure),
305 (GDestroyNotify) resolver_closure_unref);
306
307 g_main_loop_run (closure->main_loop);
308
309 if (cancel_id > 0)
310 g_cancellable_disconnect (cancellable, cancel_id);
311
312 if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
313 /* do nothing */
314
315 } else if (closure->error != NULL) {
316 g_warn_if_fail (closure->name_server == NULL);
317 g_propagate_error (error, closure->error);
318 closure->error = NULL;
319
320 } else {
321 g_warn_if_fail (closure->name_server != NULL);
322 name_server = closure->name_server;
323 closure->name_server = NULL;
324 }
325
326 resolver_closure_unref (closure);
327
328 return name_server;
329 }
330
331 static gboolean
332 mail_autoconfig_lookup (EMailAutoconfig *autoconfig,
333 const gchar *domain,
334 GCancellable *cancellable,
335 GError **error)
336 {
337 GFile *file;
338 gchar *uri;
339 gboolean success;
340
341 uri = g_strconcat (AUTOCONFIG_BASE_URI, domain, NULL);
342 file = g_file_new_for_uri (uri);
343 g_free (uri);
344
345 /* Just to make sure we don't leak. */
346 g_free (autoconfig->priv->markup_content);
347 autoconfig->priv->markup_content = NULL;
348
349 success = g_file_load_contents (
350 file, cancellable,
351 &autoconfig->priv->markup_content,
352 NULL, NULL, error);
353
354 g_object_unref (file);
355
356 return success;
357 }
358
359 static void
360 mail_autoconfig_parse_start_element (GMarkupParseContext *context,
361 const gchar *element_name,
362 const gchar **attribute_names,
363 const gchar **attribute_values,
364 gpointer user_data,
365 GError **error)
366 {
367 ParserClosure *closure = user_data;
368 gboolean is_incoming_server;
369 gboolean is_outgoing_server;
370
371 is_incoming_server = g_str_equal (element_name, "incomingServer");
372 is_outgoing_server = g_str_equal (element_name, "outgoingServer");
373
374 if (is_incoming_server || is_outgoing_server) {
375 const gchar *type = NULL;
376
377 g_markup_collect_attributes (
378 element_name,
379 attribute_names,
380 attribute_values,
381 error,
382 G_MARKUP_COLLECT_STRING,
383 "type", &type,
384 G_MARKUP_COLLECT_INVALID);
385
386 closure->in_server_element =
387 (g_strcmp0 (type, closure->expected_type) == 0);
388 }
389 }
390
391 static void
392 mail_autoconfig_parse_end_element (GMarkupParseContext *context,
393 const gchar *element_name,
394 gpointer user_data,
395 GError **error)
396 {
397 ParserClosure *closure = user_data;
398 gboolean is_incoming_server;
399 gboolean is_outgoing_server;
400
401 is_incoming_server = g_str_equal (element_name, "incomingServer");
402 is_outgoing_server = g_str_equal (element_name, "outgoingServer");
403
404 if (is_incoming_server || is_outgoing_server)
405 closure->in_server_element = FALSE;
406 }
407
408 static void
409 mail_autoconfig_parse_text (GMarkupParseContext *context,
410 const gchar *text,
411 gsize text_length,
412 gpointer user_data,
413 GError **error)
414 {
415 ParserClosure *closure = user_data;
416 const gchar *element_name;
417 GString *string;
418
419 if (!closure->in_server_element)
420 return;
421
422 /* Perform the following text substitutions:
423 *
424 * %EMAILADDRESS% : closure->email_address
425 * %EMAILLOCALPART% : closure->email_local_part
426 * %EMAILDOMAIN% : closure->email_domain_part
427 */
428 if (strchr (text, '%') == NULL)
429 string = g_string_new (text);
430 else {
431 const gchar *cp = text;
432
433 string = g_string_sized_new (256);
434 while (*cp != '\0') {
435 const gchar *variable;
436 const gchar *substitute;
437
438 if (*cp != '%') {
439 g_string_append_c (string, *cp++);
440 continue;
441 }
442
443 variable = "%EMAILADDRESS%";
444 substitute = closure->email_address;
445
446 if (strncmp (cp, variable, strlen (variable)) == 0) {
447 g_string_append (string, substitute);
448 cp += strlen (variable);
449 continue;
450 }
451
452 variable = "%EMAILLOCALPART%";
453 substitute = closure->email_local_part;
454
455 if (strncmp (cp, variable, strlen (variable)) == 0) {
456 g_string_append (string, substitute);
457 cp += strlen (variable);
458 continue;
459 }
460
461 variable = "%EMAILDOMAIN%";
462 substitute = closure->email_domain_part;
463
464 if (strncmp (cp, variable, strlen (variable)) == 0) {
465 g_string_append (string, substitute);
466 cp += strlen (variable);
467 continue;
468 }
469
470 g_string_append_c (string, *cp++);
471 }
472 }
473
474 element_name = g_markup_parse_context_get_element (context);
475
476 if (g_str_equal (element_name, "hostname")) {
477 camel_network_settings_set_host (
478 closure->network_settings, string->str);
479 closure->settings_modified = TRUE;
480
481 } else if (g_str_equal (element_name, "username")) {
482 camel_network_settings_set_user (
483 closure->network_settings, string->str);
484 closure->settings_modified = TRUE;
485
486 } else if (g_str_equal (element_name, "port")) {
487 glong port = strtol (string->str, NULL, 10);
488 if (port == CLAMP (port, 1, G_MAXUINT16)) {
489 camel_network_settings_set_port (
490 closure->network_settings, (guint16) port);
491 closure->settings_modified = TRUE;
492 }
493
494 } else if (g_str_equal (element_name, "socketType")) {
495 if (g_str_equal (string->str, "plain")) {
496 camel_network_settings_set_security_method (
497 closure->network_settings,
498 CAMEL_NETWORK_SECURITY_METHOD_NONE);
499 closure->settings_modified = TRUE;
500 } else if (g_str_equal (string->str, "SSL")) {
501 camel_network_settings_set_security_method (
502 closure->network_settings,
503 CAMEL_NETWORK_SECURITY_METHOD_SSL_ON_ALTERNATE_PORT);
504 closure->settings_modified = TRUE;
505 } else if (g_str_equal (string->str, "STARTTLS")) {
506 camel_network_settings_set_security_method (
507 closure->network_settings,
508 CAMEL_NETWORK_SECURITY_METHOD_STARTTLS_ON_STANDARD_PORT);
509 closure->settings_modified = TRUE;
510 }
511 }
512
513 /* FIXME Not handling <authentication> elements.
514 * Unclear how some map to SASL mechanisms. */
515
516 g_string_free (string, TRUE);
517 }
518
519 static GMarkupParser mail_autoconfig_parser = {
520 mail_autoconfig_parse_start_element,
521 mail_autoconfig_parse_end_element,
522 mail_autoconfig_parse_text
523 };
524
525 static gboolean
526 mail_autoconfig_set_details (EMailAutoconfig *autoconfig,
527 const gchar *expected_type,
528 ESource *source,
529 const gchar *extension_name)
530 {
531 GMarkupParseContext *context;
532 ESourceCamel *camel_ext;
533 ESourceBackend *backend_ext;
534 CamelSettings *settings;
535 ParserClosure closure;
536 const gchar *backend_name;
537 const gchar *markup_content;
538 gboolean success;
539
540 if (!e_source_has_extension (source, extension_name))
541 return FALSE;
542
543 backend_ext = e_source_get_extension (source, extension_name);
544 backend_name = e_source_backend_get_backend_name (backend_ext);
545 extension_name = e_source_camel_get_extension_name (backend_name);
546 camel_ext = e_source_get_extension (source, extension_name);
547
548 settings = e_source_camel_get_settings (camel_ext);
549 g_return_val_if_fail (CAMEL_IS_NETWORK_SETTINGS (settings), FALSE);
550
551 markup_content = e_mail_autoconfig_get_markup_content (autoconfig);
552 g_return_val_if_fail (markup_content != NULL, FALSE);
553
554 closure.network_settings = CAMEL_NETWORK_SETTINGS (settings);
555 closure.expected_type = expected_type;
556 closure.in_server_element = FALSE;
557 closure.settings_modified = FALSE;
558
559 /* These are used for text substitutions. */
560 closure.email_address = autoconfig->priv->email_address;
561 closure.email_local_part = autoconfig->priv->email_local_part;
562 closure.email_domain_part = autoconfig->priv->email_domain_part;
563
564 context = g_markup_parse_context_new (
565 &mail_autoconfig_parser, 0, &closure, (GDestroyNotify) NULL);
566
567 success = g_markup_parse_context_parse (
568 context, markup_content, strlen (markup_content), NULL);
569
570 success &= g_markup_parse_context_end_parse (context, NULL);
571
572 /* Did we actually configure anything? */
573 success &= closure.settings_modified;
574
575 g_markup_parse_context_free (context);
576
577 return success;
578 }
579
580 static void
581 mail_autoconfig_set_email_address (EMailAutoconfig *autoconfig,
582 const gchar *email_address)
583 {
584 g_return_if_fail (email_address != NULL);
585 g_return_if_fail (autoconfig->priv->email_address == NULL);
586
587 autoconfig->priv->email_address = g_strdup (email_address);
588 }
589
590 static void
591 mail_autoconfig_set_property (GObject *object,
592 guint property_id,
593 const GValue *value,
594 GParamSpec *pspec)
595 {
596 switch (property_id) {
597 case PROP_EMAIL_ADDRESS:
598 mail_autoconfig_set_email_address (
599 E_MAIL_AUTOCONFIG (object),
600 g_value_get_string (value));
601 return;
602 }
603
604 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
605 }
606
607 static void
608 mail_autoconfig_get_property (GObject *object,
609 guint property_id,
610 GValue *value,
611 GParamSpec *pspec)
612 {
613 switch (property_id) {
614 case PROP_EMAIL_ADDRESS:
615 g_value_set_string (
616 value,
617 e_mail_autoconfig_get_email_address (
618 E_MAIL_AUTOCONFIG (object)));
619 return;
620 }
621
622 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
623 }
624
625 static void
626 mail_autoconfig_finalize (GObject *object)
627 {
628 EMailAutoconfigPrivate *priv;
629
630 priv = E_MAIL_AUTOCONFIG_GET_PRIVATE (object);
631
632 g_free (priv->email_address);
633 g_free (priv->email_local_part);
634 g_free (priv->email_domain_part);
635 g_free (priv->markup_content);
636
637 /* Chain up to parent's finalize() method. */
638 G_OBJECT_CLASS (e_mail_autoconfig_parent_class)->finalize (object);
639 }
640
641 static gboolean
642 mail_autoconfig_initable_init (GInitable *initable,
643 GCancellable *cancellable,
644 GError **error)
645 {
646 EMailAutoconfig *autoconfig;
647 const gchar *email_address;
648 const gchar *domain;
649 const gchar *cp;
650 gchar *name_server;
651 gboolean success = FALSE;
652 GError *local_error = NULL;
653
654 autoconfig = E_MAIL_AUTOCONFIG (initable);
655 email_address = e_mail_autoconfig_get_email_address (autoconfig);
656
657 if (email_address == NULL) {
658 g_set_error_literal (
659 error, G_IO_ERROR,
660 G_IO_ERROR_INVALID_ARGUMENT,
661 _("No email address provided"));
662 return FALSE;
663 }
664
665 cp = strchr (email_address, '@');
666 if (cp == NULL) {
667 g_set_error_literal (
668 error, G_IO_ERROR,
669 G_IO_ERROR_INVALID_ARGUMENT,
670 _("Missing domain in email address"));
671 return FALSE;
672 }
673
674 domain = cp + 1;
675
676 autoconfig->priv->email_local_part =
677 g_strndup (email_address, cp - email_address);
678 autoconfig->priv->email_domain_part = g_strdup (domain);
679
680 /* First try the email address domain verbatim. */
681 success = mail_autoconfig_lookup (
682 autoconfig, domain, cancellable, &local_error);
683
684 g_warn_if_fail (
685 (success && local_error == NULL) ||
686 (!success && local_error != NULL));
687
688 if (success)
689 return TRUE;
690
691 /* "404 Not Found" errors are non-fatal this time around. */
692 if (ERROR_IS_NOT_FOUND (local_error)) {
693 g_clear_error (&local_error);
694 } else {
695 g_propagate_error (error, local_error);
696 return FALSE;
697 }
698
699 /* Look up an authoritative name server for the email address
700 * domain according to its "mail exchanger" (MX) DNS record. */
701 name_server = mail_autoconfig_resolve_authority (
702 domain, cancellable, error);
703
704 if (name_server == NULL)
705 return FALSE;
706
707 /* Widdle away segments of the name server domain until
708 * we find a match, or until we widdle down to nothing. */
709
710 cp = name_server;
711 while (cp != NULL && strchr (cp, '.') != NULL) {
712 g_clear_error (&local_error);
713
714 success = mail_autoconfig_lookup (
715 autoconfig, cp, cancellable, &local_error);
716
717 g_warn_if_fail (
718 (success && local_error == NULL) ||
719 (!success && local_error != NULL));
720
721 if (success || !ERROR_IS_NOT_FOUND (local_error))
722 break;
723
724 cp = strchr (cp, '.');
725 if (cp != NULL)
726 cp++;
727 }
728
729 if (local_error != NULL)
730 g_propagate_error (error, local_error);
731
732 g_free (name_server);
733
734 return success;
735 }
736
737 static void
738 e_mail_autoconfig_class_init (EMailAutoconfigClass *class)
739 {
740 GObjectClass *object_class;
741
742 g_type_class_add_private (class, sizeof (EMailAutoconfigPrivate));
743
744 object_class = G_OBJECT_CLASS (class);
745 object_class->set_property = mail_autoconfig_set_property;
746 object_class->get_property = mail_autoconfig_get_property;
747 object_class->finalize = mail_autoconfig_finalize;
748
749 g_object_class_install_property (
750 object_class,
751 PROP_EMAIL_ADDRESS,
752 g_param_spec_string (
753 "email-address",
754 "Email Address",
755 "The address from which to query config data",
756 NULL,
757 G_PARAM_READWRITE |
758 G_PARAM_CONSTRUCT_ONLY |
759 G_PARAM_STATIC_STRINGS));
760 }
761
762 static void
763 e_mail_autoconfig_initable_init (GInitableIface *interface)
764 {
765 interface->init = mail_autoconfig_initable_init;
766 }
767
768 static void
769 e_mail_autoconfig_init (EMailAutoconfig *autoconfig)
770 {
771 autoconfig->priv = E_MAIL_AUTOCONFIG_GET_PRIVATE (autoconfig);
772 }
773
774 EMailAutoconfig *
775 e_mail_autoconfig_new_sync (const gchar *email_address,
776 GCancellable *cancellable,
777 GError **error)
778 {
779 g_return_val_if_fail (email_address != NULL, NULL);
780
781 return g_initable_new (
782 E_TYPE_MAIL_AUTOCONFIG,
783 cancellable, error,
784 "email-address", email_address,
785 NULL);
786 }
787
788 void
789 e_mail_autoconfig_new (const gchar *email_address,
790 gint io_priority,
791 GCancellable *cancellable,
792 GAsyncReadyCallback callback,
793 gpointer user_data)
794 {
795 g_return_if_fail (email_address != NULL);
796
797 g_async_initable_new_async (
798 E_TYPE_MAIL_AUTOCONFIG,
799 io_priority, cancellable,
800 callback, user_data,
801 "email-address", email_address,
802 NULL);
803 }
804
805 EMailAutoconfig *
806 e_mail_autoconfig_finish (GAsyncResult *result,
807 GError **error)
808 {
809 GObject *source_object;
810 GObject *autoconfig;
811
812 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
813
814 source_object = g_async_result_get_source_object (result);
815 g_return_val_if_fail (source_object != NULL, NULL);
816
817 autoconfig = g_async_initable_new_finish (
818 G_ASYNC_INITABLE (source_object), result, error);
819
820 g_object_unref (source_object);
821
822 if (autoconfig == NULL)
823 return NULL;
824
825 return E_MAIL_AUTOCONFIG (autoconfig);
826 }
827
828 const gchar *
829 e_mail_autoconfig_get_email_address (EMailAutoconfig *autoconfig)
830 {
831 g_return_val_if_fail (E_IS_MAIL_AUTOCONFIG (autoconfig), NULL);
832
833 return autoconfig->priv->email_address;
834 }
835
836 const gchar *
837 e_mail_autoconfig_get_markup_content (EMailAutoconfig *autoconfig)
838 {
839 g_return_val_if_fail (E_IS_MAIL_AUTOCONFIG (autoconfig), NULL);
840
841 return autoconfig->priv->markup_content;
842 }
843
844 gboolean
845 e_mail_autoconfig_set_imap_details (EMailAutoconfig *autoconfig,
846 ESource *imap_source)
847 {
848 g_return_val_if_fail (E_IS_MAIL_AUTOCONFIG (autoconfig), FALSE);
849 g_return_val_if_fail (E_IS_SOURCE (imap_source), FALSE);
850
851 return mail_autoconfig_set_details (
852 autoconfig, "imap", imap_source,
853 E_SOURCE_EXTENSION_MAIL_ACCOUNT);
854 }
855
856 gboolean
857 e_mail_autoconfig_set_pop3_details (EMailAutoconfig *autoconfig,
858 ESource *pop3_source)
859 {
860 g_return_val_if_fail (E_IS_MAIL_AUTOCONFIG (autoconfig), FALSE);
861 g_return_val_if_fail (E_IS_SOURCE (pop3_source), FALSE);
862
863 return mail_autoconfig_set_details (
864 autoconfig, "pop3", pop3_source,
865 E_SOURCE_EXTENSION_MAIL_ACCOUNT);
866 }
867
868 gboolean
869 e_mail_autoconfig_set_smtp_details (EMailAutoconfig *autoconfig,
870 ESource *smtp_source)
871 {
872 g_return_val_if_fail (E_IS_MAIL_AUTOCONFIG (autoconfig), FALSE);
873 g_return_val_if_fail (E_IS_SOURCE (smtp_source), FALSE);
874
875 return mail_autoconfig_set_details (
876 autoconfig, "smtp", smtp_source,
877 E_SOURCE_EXTENSION_MAIL_TRANSPORT);
878 }