No issues found
Tool | Failure ID | Location | Function | Message | Data |
---|---|---|---|---|---|
clang-analyzer | no-output-found | e-mail-config-assistant.c | Message(text='Unable to locate XML output from invoke-clang-analyzer') | None | |
clang-analyzer | no-output-found | e-mail-config-assistant.c | Message(text='Unable to locate XML output from invoke-clang-analyzer') | None |
1 /*
2 * e-mail-config-assistant.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-config-assistant.h"
20
21 #include <config.h>
22 #include <glib/gi18n-lib.h>
23
24 #include <libebackend/libebackend.h>
25
26 #include <libevolution-utils/e-alert-sink.h>
27
28 #include <mail/e-mail-config-confirm-page.h>
29 #include <mail/e-mail-config-identity-page.h>
30 #include <mail/e-mail-config-lookup-page.h>
31 #include <mail/e-mail-config-provider-page.h>
32 #include <mail/e-mail-config-receiving-page.h>
33 #include <mail/e-mail-config-sending-page.h>
34 #include <mail/e-mail-config-summary-page.h>
35 #include <mail/e-mail-config-welcome-page.h>
36
37 #define E_MAIL_CONFIG_ASSISTANT_GET_PRIVATE(obj) \
38 (G_TYPE_INSTANCE_GET_PRIVATE \
39 ((obj), E_TYPE_MAIL_CONFIG_ASSISTANT, EMailConfigAssistantPrivate))
40
41 struct _EMailConfigAssistantPrivate {
42 EMailSession *session;
43 ESource *identity_source;
44 GPtrArray *account_sources;
45 GPtrArray *transport_sources;
46 EMailConfigServicePage *receiving_page;
47 EMailConfigServicePage *sending_page;
48 EMailConfigSummaryPage *summary_page;
49 EMailConfigPage *lookup_page;
50 GHashTable *visited_pages;
51 gboolean auto_configure_done;
52 };
53
54 enum {
55 PROP_0,
56 PROP_ACCOUNT_BACKEND,
57 PROP_ACCOUNT_SOURCE,
58 PROP_IDENTITY_SOURCE,
59 PROP_SESSION,
60 PROP_TRANSPORT_BACKEND,
61 PROP_TRANSPORT_SOURCE
62 };
63
64 /* XXX We implement EAlertSink but don't implement a custom submit_alert()
65 * method. So any alert results in a pop-up message dialog, which is a
66 * fashion faux pas these days. But it's only used when submitting the
67 * the newly-configured account fails, so should rarely be seen. */
68
69 G_DEFINE_TYPE_WITH_CODE (
70 EMailConfigAssistant,
71 e_mail_config_assistant,
72 GTK_TYPE_ASSISTANT,
73 G_IMPLEMENT_INTERFACE (
74 E_TYPE_ALERT_SINK, NULL)
75 G_IMPLEMENT_INTERFACE (
76 E_TYPE_EXTENSIBLE, NULL))
77
78 static gint
79 mail_config_assistant_provider_compare (gconstpointer data1,
80 gconstpointer data2)
81 {
82 const CamelProvider *provider1 = data1;
83 const CamelProvider *provider2 = data2;
84
85 /* The "none" provider comes first. */
86 if (g_strcmp0 (provider1->protocol, "none") == 0)
87 return -1;
88 if (g_strcmp0 (provider2->protocol, "none") == 0)
89 return 1;
90
91 /* Then sort remote providers before local providers. */
92 if (provider1->flags & CAMEL_PROVIDER_IS_REMOTE) {
93 if (provider2->flags & CAMEL_PROVIDER_IS_REMOTE)
94 return 0;
95 else
96 return -1;
97 } else {
98 if (provider2->flags & CAMEL_PROVIDER_IS_REMOTE)
99 return 1;
100 else
101 return 0;
102 }
103 }
104
105 static GList *
106 mail_config_assistant_list_providers (void)
107 {
108 GList *list, *link;
109 GQueue trash = G_QUEUE_INIT;
110
111 list = camel_provider_list (TRUE);
112 list = g_list_sort (list, mail_config_assistant_provider_compare);
113
114 /* Keep only providers with a "mail" or "news" domain. */
115
116 for (link = list; link != NULL; link = g_list_next (link)) {
117 CamelProvider *provider = link->data;
118 gboolean mail_or_news_domain;
119
120 mail_or_news_domain =
121 (g_strcmp0 (provider->domain, "mail") == 0) ||
122 (g_strcmp0 (provider->domain, "news") == 0);
123
124 if (mail_or_news_domain)
125 continue;
126
127 g_queue_push_tail (&trash, link);
128 }
129
130 while ((link = g_queue_pop_head (&trash)) != NULL)
131 list = g_list_remove_link (list, link);
132
133 return list;
134 }
135
136 static void
137 mail_config_assistant_notify_account_backend (EMailConfigServicePage *page,
138 GParamSpec *pspec,
139 EMailConfigAssistant *assistant)
140 {
141 EMailConfigServiceBackend *backend;
142 EMailConfigServicePage *sending_page;
143 EMailConfigServicePageClass *page_class;
144 CamelProvider *provider;
145
146 backend = e_mail_config_service_page_get_active_backend (page);
147
148 /* The Receiving Page combo box may not have an active item. */
149 if (backend == NULL)
150 goto notify;
151
152 /* The Sending Page may not have been created yet. */
153 if (assistant->priv->sending_page == NULL)
154 goto notify;
155
156 provider = e_mail_config_service_backend_get_provider (backend);
157
158 /* XXX This should never fail, but the Camel macro below does
159 * not check for NULL so better to malfunction than crash. */
160 g_return_if_fail (provider != NULL);
161
162 sending_page = assistant->priv->sending_page;
163 page_class = E_MAIL_CONFIG_SERVICE_PAGE_GET_CLASS (sending_page);
164
165 /* The Sending Page is invisible when the CamelProvider for the
166 * receiving type defines both a storage and transport service.
167 * This is common in CamelProviders for groupware products like
168 * Microsoft Exchange and Novell GroupWise. */
169 if (CAMEL_PROVIDER_IS_STORE_AND_TRANSPORT (provider)) {
170 backend = e_mail_config_service_page_lookup_backend (
171 sending_page, provider->protocol);
172 gtk_widget_hide (GTK_WIDGET (sending_page));
173 } else {
174 backend = e_mail_config_service_page_lookup_backend (
175 sending_page, page_class->default_backend_name);
176 gtk_widget_show (GTK_WIDGET (sending_page));
177 }
178
179 e_mail_config_service_page_set_active_backend (sending_page, backend);
180
181 notify:
182 g_object_freeze_notify (G_OBJECT (assistant));
183
184 g_object_notify (G_OBJECT (assistant), "account-backend");
185 g_object_notify (G_OBJECT (assistant), "account-source");
186
187 g_object_thaw_notify (G_OBJECT (assistant));
188 }
189
190 static void
191 mail_config_assistant_notify_transport_backend (EMailConfigServicePage *page,
192 GParamSpec *pspec,
193 EMailConfigAssistant *assistant)
194 {
195 g_object_freeze_notify (G_OBJECT (assistant));
196
197 g_object_notify (G_OBJECT (assistant), "transport-backend");
198 g_object_notify (G_OBJECT (assistant), "transport-source");
199
200 g_object_thaw_notify (G_OBJECT (assistant));
201 }
202
203 static void
204 mail_config_assistant_page_changed (EMailConfigPage *page,
205 EMailConfigAssistant *assistant)
206 {
207 gtk_assistant_set_page_complete (
208 GTK_ASSISTANT (assistant), GTK_WIDGET (page),
209 e_mail_config_page_check_complete (page));
210 }
211
212 static void
213 mail_config_assistant_autoconfigure_cb (GObject *source_object,
214 GAsyncResult *result,
215 gpointer user_data)
216 {
217 EMailConfigAssistantPrivate *priv;
218 GtkAssistant *assistant;
219 EMailAutoconfig *autoconfig;
220 const gchar *email_address;
221 gint n_pages, ii;
222 GError *error = NULL;
223
224 assistant = GTK_ASSISTANT (user_data);
225 priv = E_MAIL_CONFIG_ASSISTANT_GET_PRIVATE (assistant);
226
227 /* Whether it works or not, we only do this once. */
228 priv->auto_configure_done = TRUE;
229
230 autoconfig = e_mail_autoconfig_finish (result, &error);
231
232 /* We don't really care about errors, we only capture the GError
233 * as a debugging aid. If this doesn't work we simply proceed to
234 * the Receiving Email page. */
235 if (error != NULL) {
236 gtk_assistant_next_page (assistant);
237 g_error_free (error);
238 goto exit;
239 }
240
241 g_return_if_fail (E_IS_MAIL_AUTOCONFIG (autoconfig));
242
243 /* Autoconfiguration worked! Feed the results to the
244 * service pages and then skip to the Summary page. */
245
246 e_mail_config_service_page_auto_configure (
247 priv->receiving_page, autoconfig);
248
249 e_mail_config_service_page_auto_configure (
250 priv->sending_page, autoconfig);
251
252 /* Add these pages to the visited pages hash table to
253 * prevent calling e_mail_config_page_setup_defaults(). */
254
255 g_hash_table_add (priv->visited_pages, priv->receiving_page);
256 g_hash_table_add (priv->visited_pages, priv->sending_page);
257
258 /* Also set the initial display name to the email address
259 * given so the user can just click past the Summary page. */
260 email_address = e_mail_autoconfig_get_email_address (autoconfig);
261 e_source_set_display_name (priv->identity_source, email_address);
262
263 /* Go to the next page (Receiving Email) before skipping to the
264 * Summary Page to get it into GtkAssistant visited page history.
265 * We want the back button to return to Receiving Email. */
266 gtk_assistant_next_page (assistant);
267
268 /* XXX Can't find a better way to learn the page number of
269 * the summary page. Oh my god this API is horrible. */
270 n_pages = gtk_assistant_get_n_pages (assistant);
271 for (ii = 0; ii < n_pages; ii++) {
272 GtkWidget *nth_page;
273
274 nth_page = gtk_assistant_get_nth_page (assistant, ii);
275 if (E_IS_MAIL_CONFIG_SUMMARY_PAGE (nth_page))
276 break;
277 }
278
279 g_warn_if_fail (ii < n_pages);
280 gtk_assistant_set_current_page (assistant, ii);
281
282 exit:
283 /* Set the page invisible so we never revisit it. */
284 gtk_widget_set_visible (GTK_WIDGET (priv->lookup_page), FALSE);
285
286 g_object_unref (assistant);
287 }
288
289 static gboolean
290 mail_config_assistant_provider_page_visible (GBinding *binding,
291 const GValue *source_value,
292 GValue *target_value,
293 gpointer unused)
294 {
295 EMailConfigServiceBackend *active_backend;
296 EMailConfigServiceBackend *page_backend;
297 EMailConfigProviderPage *page;
298 GObject *target_object;
299 gboolean visible;
300
301 target_object = g_binding_get_target (binding);
302 page = E_MAIL_CONFIG_PROVIDER_PAGE (target_object);
303 page_backend = e_mail_config_provider_page_get_backend (page);
304
305 active_backend = g_value_get_object (source_value);
306 visible = (page_backend == active_backend);
307 g_value_set_boolean (target_value, visible);
308
309 return TRUE;
310 }
311
312 static void
313 mail_config_assistant_close_cb (GObject *object,
314 GAsyncResult *result,
315 gpointer user_data)
316 {
317 EMailConfigAssistant *assistant;
318 GdkWindow *gdk_window;
319 GError *error = NULL;
320
321 assistant = E_MAIL_CONFIG_ASSISTANT (object);
322
323 /* Set the cursor back to normal. */
324 gdk_window = gtk_widget_get_window (GTK_WIDGET (assistant));
325 gdk_window_set_cursor (gdk_window, NULL);
326
327 /* Allow user interaction with window content. */
328 gtk_widget_set_sensitive (GTK_WIDGET (assistant), TRUE);
329
330 e_mail_config_assistant_commit_finish (assistant, result, &error);
331
332 /* Ignore cancellations. */
333 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
334 g_error_free (error);
335
336 } else if (error != NULL) {
337 e_alert_submit (
338 E_ALERT_SINK (assistant),
339 "system:simple-error",
340 error->message, NULL);
341 g_error_free (error);
342
343 } else {
344 gtk_widget_destroy (GTK_WIDGET (assistant));
345 }
346 }
347
348 static void
349 mail_config_assistant_set_session (EMailConfigAssistant *assistant,
350 EMailSession *session)
351 {
352 g_return_if_fail (E_IS_MAIL_SESSION (session));
353 g_return_if_fail (assistant->priv->session == NULL);
354
355 assistant->priv->session = g_object_ref (session);
356 }
357
358 static void
359 mail_config_assistant_set_property (GObject *object,
360 guint property_id,
361 const GValue *value,
362 GParamSpec *pspec)
363 {
364 switch (property_id) {
365 case PROP_SESSION:
366 mail_config_assistant_set_session (
367 E_MAIL_CONFIG_ASSISTANT (object),
368 g_value_get_object (value));
369 return;
370 }
371
372 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
373 }
374
375 static void
376 mail_config_assistant_get_property (GObject *object,
377 guint property_id,
378 GValue *value,
379 GParamSpec *pspec)
380 {
381 switch (property_id) {
382 case PROP_ACCOUNT_BACKEND:
383 g_value_set_object (
384 value,
385 e_mail_config_assistant_get_account_backend (
386 E_MAIL_CONFIG_ASSISTANT (object)));
387 return;
388
389 case PROP_ACCOUNT_SOURCE:
390 g_value_set_object (
391 value,
392 e_mail_config_assistant_get_account_source (
393 E_MAIL_CONFIG_ASSISTANT (object)));
394 return;
395
396 case PROP_IDENTITY_SOURCE:
397 g_value_set_object (
398 value,
399 e_mail_config_assistant_get_identity_source (
400 E_MAIL_CONFIG_ASSISTANT (object)));
401 return;
402
403 case PROP_SESSION:
404 g_value_set_object (
405 value,
406 e_mail_config_assistant_get_session (
407 E_MAIL_CONFIG_ASSISTANT (object)));
408 return;
409
410 case PROP_TRANSPORT_BACKEND:
411 g_value_set_object (
412 value,
413 e_mail_config_assistant_get_transport_backend (
414 E_MAIL_CONFIG_ASSISTANT (object)));
415 return;
416
417 case PROP_TRANSPORT_SOURCE:
418 g_value_set_object (
419 value,
420 e_mail_config_assistant_get_transport_source (
421 E_MAIL_CONFIG_ASSISTANT (object)));
422 return;
423 }
424
425 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
426 }
427
428 static void
429 mail_config_assistant_dispose (GObject *object)
430 {
431 EMailConfigAssistantPrivate *priv;
432
433 priv = E_MAIL_CONFIG_ASSISTANT_GET_PRIVATE (object);
434
435 if (priv->session != NULL) {
436 g_object_unref (priv->session);
437 priv->session = NULL;
438 }
439
440 if (priv->identity_source != NULL) {
441 g_object_unref (priv->identity_source);
442 priv->identity_source = NULL;
443 }
444
445 if (priv->receiving_page != NULL) {
446 g_object_unref (priv->receiving_page);
447 priv->receiving_page = NULL;
448 }
449
450 if (priv->sending_page != NULL) {
451 g_object_unref (priv->sending_page);
452 priv->sending_page = NULL;
453 }
454
455 if (priv->summary_page != NULL) {
456 g_object_unref (priv->summary_page);
457 priv->summary_page = NULL;
458 }
459
460 if (priv->lookup_page != NULL) {
461 g_object_unref (priv->lookup_page);
462 priv->lookup_page = NULL;
463 }
464
465 g_ptr_array_set_size (priv->account_sources, 0);
466 g_ptr_array_set_size (priv->transport_sources, 0);
467
468 /* Chain up to parent's dispose() method. */
469 G_OBJECT_CLASS (e_mail_config_assistant_parent_class)->
470 dispose (object);
471 }
472
473 static void
474 mail_config_assistant_finalize (GObject *object)
475 {
476 EMailConfigAssistantPrivate *priv;
477
478 priv = E_MAIL_CONFIG_ASSISTANT_GET_PRIVATE (object);
479
480 g_ptr_array_free (priv->account_sources, TRUE);
481 g_ptr_array_free (priv->transport_sources, TRUE);
482
483 g_hash_table_destroy (priv->visited_pages);
484
485 /* Chain up to parent's finalize() method. */
486 G_OBJECT_CLASS (e_mail_config_assistant_parent_class)->
487 finalize (object);
488 }
489
490 static void
491 mail_config_assistant_constructed (GObject *object)
492 {
493 EMailConfigAssistant *assistant;
494 ESource *identity_source;
495 ESourceRegistry *registry;
496 ESourceExtension *extension;
497 ESourceMailComposition *mail_composition_extension;
498 ESourceMailIdentity *mail_identity_extension;
499 ESourceMailSubmission *mail_submission_extension;
500 EMailSession *session;
501 EMailConfigPage *page;
502 GList *list, *link;
503 const gchar *extension_name;
504 const gchar *title;
505
506 assistant = E_MAIL_CONFIG_ASSISTANT (object);
507
508 /* Chain up to parent's constructed() method. */
509 G_OBJECT_CLASS (e_mail_config_assistant_parent_class)->
510 constructed (object);
511
512 title = _("Evolution Account Assistant");
513 gtk_window_set_title (GTK_WINDOW (assistant), title);
514 gtk_window_set_position (GTK_WINDOW (assistant), GTK_WIN_POS_CENTER);
515
516 session = e_mail_config_assistant_get_session (assistant);
517 registry = e_mail_session_get_registry (session);
518
519 /* Configure a new identity source. */
520
521 identity_source = e_source_new (NULL, NULL, NULL);
522 assistant->priv->identity_source = identity_source;
523 session = e_mail_config_assistant_get_session (assistant);
524
525 extension_name = E_SOURCE_EXTENSION_MAIL_COMPOSITION;
526 extension = e_source_get_extension (identity_source, extension_name);
527 mail_composition_extension = E_SOURCE_MAIL_COMPOSITION (extension);
528
529 extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY;
530 extension = e_source_get_extension (identity_source, extension_name);
531 mail_identity_extension = E_SOURCE_MAIL_IDENTITY (extension);
532
533 extension_name = E_SOURCE_EXTENSION_MAIL_SUBMISSION;
534 extension = e_source_get_extension (identity_source, extension_name);
535 mail_submission_extension = E_SOURCE_MAIL_SUBMISSION (extension);
536
537 e_source_mail_composition_set_drafts_folder (
538 mail_composition_extension,
539 e_mail_session_get_local_folder_uri (
540 session, E_MAIL_LOCAL_FOLDER_DRAFTS));
541
542 e_source_mail_composition_set_templates_folder (
543 mail_composition_extension,
544 e_mail_session_get_local_folder_uri (
545 session, E_MAIL_LOCAL_FOLDER_TEMPLATES));
546
547 e_source_mail_submission_set_sent_folder (
548 mail_submission_extension,
549 e_mail_session_get_local_folder_uri (
550 session, E_MAIL_LOCAL_FOLDER_SENT));
551
552 /*** Welcome Page ***/
553
554 page = e_mail_config_welcome_page_new ();
555 e_mail_config_assistant_add_page (assistant, page);
556
557 /*** Identity Page ***/
558
559 page = e_mail_config_identity_page_new (registry, identity_source);
560 e_mail_config_identity_page_set_show_account_info (
561 E_MAIL_CONFIG_IDENTITY_PAGE (page), FALSE);
562 e_mail_config_identity_page_set_show_signatures (
563 E_MAIL_CONFIG_IDENTITY_PAGE (page), FALSE);
564 e_mail_config_assistant_add_page (assistant, page);
565
566 /*** Lookup Page ***/
567
568 page = e_mail_config_lookup_page_new ();
569 e_mail_config_assistant_add_page (assistant, page);
570 assistant->priv->lookup_page = g_object_ref (page);
571
572 /*** Receiving Page ***/
573
574 page = e_mail_config_receiving_page_new (registry);
575 e_mail_config_assistant_add_page (assistant, page);
576 assistant->priv->receiving_page = g_object_ref (page);
577
578 g_object_bind_property (
579 mail_identity_extension, "address",
580 page, "email-address",
581 G_BINDING_SYNC_CREATE);
582
583 g_signal_connect (
584 page, "notify::active-backend",
585 G_CALLBACK (mail_config_assistant_notify_account_backend),
586 assistant);
587
588 /*** Receiving Options (multiple) ***/
589
590 /* Populate the Receiving Email page while at the same time
591 * adding a Receiving Options page for each account type. */
592
593 list = mail_config_assistant_list_providers ();
594
595 for (link = list; link != NULL; link = g_list_next (link)) {
596 EMailConfigServiceBackend *backend;
597 CamelProvider *provider = link->data;
598 ESourceBackend *backend_extension;
599 ESource *scratch_source;
600 const gchar *backend_name;
601
602 if (provider->object_types[CAMEL_PROVIDER_STORE] == 0)
603 continue;
604
605 /* ESource uses "backend_name" and CamelProvider
606 * uses "protocol", but the terms are synonymous. */
607 backend_name = provider->protocol;
608
609 scratch_source = e_source_new (NULL, NULL, NULL);
610 backend_extension = e_source_get_extension (
611 scratch_source, E_SOURCE_EXTENSION_MAIL_ACCOUNT);
612 e_source_backend_set_backend_name (
613 backend_extension, backend_name);
614
615 /* Keep display names synchronized. */
616 g_object_bind_property (
617 identity_source, "display-name",
618 scratch_source, "display-name",
619 G_BINDING_BIDIRECTIONAL |
620 G_BINDING_SYNC_CREATE);
621
622 /* We always pass NULL for the collection argument.
623 * The backend generates its own scratch collection
624 * source if implements the new_collection() method. */
625 backend = e_mail_config_service_page_add_scratch_source (
626 assistant->priv->receiving_page, scratch_source, NULL);
627
628 g_object_unref (scratch_source);
629
630 page = e_mail_config_provider_page_new (backend);
631
632 /* Note: We exclude this page if it has no options,
633 * but we don't know that until we create it. */
634 if (e_mail_config_provider_page_is_empty (
635 E_MAIL_CONFIG_PROVIDER_PAGE (page))) {
636 g_object_unref (g_object_ref_sink (page));
637 continue;
638 } else {
639 e_mail_config_assistant_add_page (assistant, page);
640 }
641
642 /* Each Receiving Options page is only visible when its
643 * service backend is active on the Receiving Email page. */
644 g_object_bind_property_full (
645 assistant->priv->receiving_page, "active-backend",
646 page, "visible",
647 G_BINDING_SYNC_CREATE,
648 mail_config_assistant_provider_page_visible,
649 NULL,
650 NULL, (GDestroyNotify) NULL);
651 }
652
653 g_list_free (list);
654
655 /*** Sending Page ***/
656
657 page = e_mail_config_sending_page_new (registry);
658 e_mail_config_assistant_add_page (assistant, page);
659 assistant->priv->sending_page = g_object_ref (page);
660
661 g_object_bind_property (
662 mail_identity_extension, "address",
663 page, "email-address",
664 G_BINDING_SYNC_CREATE);
665
666 g_signal_connect (
667 page, "notify::active-backend",
668 G_CALLBACK (mail_config_assistant_notify_transport_backend),
669 assistant);
670
671 list = mail_config_assistant_list_providers ();
672
673 for (link = list; link != NULL; link = g_list_next (link)) {
674 CamelProvider *provider = link->data;
675 ESourceBackend *backend_extension;
676 ESource *scratch_source;
677 const gchar *backend_name;
678
679 if (provider->object_types[CAMEL_PROVIDER_TRANSPORT] == 0)
680 continue;
681
682 /* ESource uses "backend_name" and CamelProvider
683 * uses "protocol", but the terms are synonymous. */
684 backend_name = provider->protocol;
685
686 scratch_source = e_source_new (NULL, NULL, NULL);
687 backend_extension = e_source_get_extension (
688 scratch_source, E_SOURCE_EXTENSION_MAIL_TRANSPORT);
689 e_source_backend_set_backend_name (
690 backend_extension, backend_name);
691
692 /* Keep display names synchronized. */
693 g_object_bind_property (
694 identity_source, "display-name",
695 scratch_source, "display-name",
696 G_BINDING_BIDIRECTIONAL |
697 G_BINDING_SYNC_CREATE);
698
699 /* We always pass NULL for the collection argument.
700 * The backend generates its own scratch collection
701 * source if implements the new_collection() method. */
702 e_mail_config_service_page_add_scratch_source (
703 assistant->priv->sending_page, scratch_source, NULL);
704
705 g_object_unref (scratch_source);
706 }
707
708 g_list_free (list);
709
710 /*** Summary Page ***/
711
712 page = e_mail_config_summary_page_new ();
713 e_mail_config_assistant_add_page (assistant, page);
714 assistant->priv->summary_page = g_object_ref (page);
715
716 g_object_bind_property (
717 assistant, "account-backend",
718 page, "account-backend",
719 G_BINDING_SYNC_CREATE);
720
721 g_object_bind_property (
722 assistant, "identity-source",
723 page, "identity-source",
724 G_BINDING_SYNC_CREATE);
725
726 g_object_bind_property (
727 assistant, "transport-backend",
728 page, "transport-backend",
729 G_BINDING_SYNC_CREATE);
730
731 /*** Confirm Page ***/
732
733 page = e_mail_config_confirm_page_new ();
734 e_mail_config_assistant_add_page (assistant, page);
735
736 e_extensible_load_extensions (E_EXTENSIBLE (assistant));
737 }
738
739 static void
740 mail_config_assistant_remove (GtkContainer *container,
741 GtkWidget *widget)
742 {
743 if (E_IS_MAIL_CONFIG_PAGE (widget))
744 g_signal_handlers_disconnect_by_func (
745 widget, mail_config_assistant_page_changed,
746 E_MAIL_CONFIG_ASSISTANT (container));
747
748 /* Chain up to parent's remove() method. */
749 GTK_CONTAINER_CLASS (e_mail_config_assistant_parent_class)->
750 remove (container, widget);
751 }
752
753 static void
754 mail_config_assistant_prepare (GtkAssistant *assistant,
755 GtkWidget *page)
756 {
757 EMailConfigAssistantPrivate *priv;
758 gboolean first_visit = FALSE;
759
760 priv = E_MAIL_CONFIG_ASSISTANT_GET_PRIVATE (assistant);
761
762 /* Only setup defaults the first time a page is visited. */
763 if (!g_hash_table_contains (priv->visited_pages, page)) {
764 if (E_IS_MAIL_CONFIG_PAGE (page))
765 e_mail_config_page_setup_defaults (
766 E_MAIL_CONFIG_PAGE (page));
767 g_hash_table_add (priv->visited_pages, page);
768 first_visit = TRUE;
769 }
770
771 if (E_IS_MAIL_CONFIG_LOOKUP_PAGE (page)) {
772 ESource *source;
773 ESourceMailIdentity *extension;
774 const gchar *email_address;
775 const gchar *extension_name;
776
777 source = priv->identity_source;
778 extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY;
779 extension = e_source_get_extension (source, extension_name);
780 email_address = e_source_mail_identity_get_address (extension);
781
782 /* XXX This operation is not cancellable. */
783 e_mail_autoconfig_new (
784 email_address, G_PRIORITY_DEFAULT, NULL,
785 mail_config_assistant_autoconfigure_cb,
786 g_object_ref (assistant));
787 }
788
789 if (E_IS_MAIL_CONFIG_RECEIVING_PAGE (page) && first_visit) {
790 ESource *source;
791 ESourceMailIdentity *extension;
792 const gchar *email_address;
793 const gchar *extension_name;
794
795 /* Use the email address from the Identity Page as
796 * the initial display name, so in case we have to
797 * query a remote mail server, the password prompt
798 * will have a more meaningful description. */
799
800 source = priv->identity_source;
801 extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY;
802 extension = e_source_get_extension (source, extension_name);
803 email_address = e_source_mail_identity_get_address (extension);
804 e_source_set_display_name (source, email_address);
805 }
806 }
807
808 static void
809 mail_config_assistant_close (GtkAssistant *assistant)
810 {
811 GdkCursor *gdk_cursor;
812 GdkWindow *gdk_window;
813
814 /* Do not chain up. GtkAssistant does not implement this method. */
815
816 /* Make the cursor appear busy. */
817 gdk_cursor = gdk_cursor_new (GDK_WATCH);
818 gdk_window = gtk_widget_get_window (GTK_WIDGET (assistant));
819 gdk_window_set_cursor (gdk_window, gdk_cursor);
820 g_object_unref (gdk_cursor);
821
822 /* Prevent user interaction with window content. */
823 gtk_widget_set_sensitive (GTK_WIDGET (assistant), FALSE);
824
825 /* XXX This operation is not cancellable. */
826 e_mail_config_assistant_commit (
827 E_MAIL_CONFIG_ASSISTANT (assistant),
828 NULL, mail_config_assistant_close_cb, NULL);
829 }
830
831 static void
832 mail_config_assistant_cancel (GtkAssistant *assistant)
833 {
834 /* Do not chain up. GtkAssistant does not implement this method. */
835
836 gtk_widget_destroy (GTK_WIDGET (assistant));
837 }
838
839 static void
840 e_mail_config_assistant_class_init (EMailConfigAssistantClass *class)
841 {
842 GObjectClass *object_class;
843 GtkContainerClass *container_class;
844 GtkAssistantClass *assistant_class;
845
846 g_type_class_add_private (class, sizeof (EMailConfigAssistantPrivate));
847
848 object_class = G_OBJECT_CLASS (class);
849 object_class->set_property = mail_config_assistant_set_property;
850 object_class->get_property = mail_config_assistant_get_property;
851 object_class->dispose = mail_config_assistant_dispose;
852 object_class->finalize = mail_config_assistant_finalize;
853 object_class->constructed = mail_config_assistant_constructed;
854
855 container_class = GTK_CONTAINER_CLASS (class);
856 container_class->remove = mail_config_assistant_remove;
857
858 assistant_class = GTK_ASSISTANT_CLASS (class);
859 assistant_class->prepare = mail_config_assistant_prepare;
860 assistant_class->close = mail_config_assistant_close;
861 assistant_class->cancel = mail_config_assistant_cancel;
862
863 g_object_class_install_property (
864 object_class,
865 PROP_ACCOUNT_BACKEND,
866 g_param_spec_object (
867 "account-backend",
868 "Account Backend",
869 "Active mail account service backend",
870 E_TYPE_MAIL_CONFIG_SERVICE_BACKEND,
871 G_PARAM_READABLE |
872 G_PARAM_STATIC_STRINGS));
873
874 g_object_class_install_property (
875 object_class,
876 PROP_ACCOUNT_SOURCE,
877 g_param_spec_object (
878 "account-source",
879 "Account Source",
880 "Mail account source being edited",
881 E_TYPE_SOURCE,
882 G_PARAM_READABLE |
883 G_PARAM_STATIC_STRINGS));
884
885 g_object_class_install_property (
886 object_class,
887 PROP_IDENTITY_SOURCE,
888 g_param_spec_object (
889 "identity-source",
890 "Identity Source",
891 "Mail identity source being edited",
892 E_TYPE_SOURCE,
893 G_PARAM_READABLE |
894 G_PARAM_STATIC_STRINGS));
895
896 g_object_class_install_property (
897 object_class,
898 PROP_SESSION,
899 g_param_spec_object (
900 "session",
901 "Session",
902 "Mail session",
903 E_TYPE_MAIL_SESSION,
904 G_PARAM_READWRITE |
905 G_PARAM_CONSTRUCT_ONLY |
906 G_PARAM_STATIC_STRINGS));
907
908 g_object_class_install_property (
909 object_class,
910 PROP_TRANSPORT_BACKEND,
911 g_param_spec_object (
912 "transport-backend",
913 "Transport Backend",
914 "Active mail transport service backend",
915 E_TYPE_MAIL_CONFIG_SERVICE_BACKEND,
916 G_PARAM_READABLE |
917 G_PARAM_STATIC_STRINGS));
918
919 g_object_class_install_property (
920 object_class,
921 PROP_TRANSPORT_SOURCE,
922 g_param_spec_object (
923 "transport-source",
924 "Transport Source",
925 "Mail transport source being edited",
926 E_TYPE_SOURCE,
927 G_PARAM_READABLE |
928 G_PARAM_STATIC_STRINGS));
929 }
930
931 static void
932 e_mail_config_assistant_init (EMailConfigAssistant *assistant)
933 {
934 assistant->priv = E_MAIL_CONFIG_ASSISTANT_GET_PRIVATE (assistant);
935
936 assistant->priv->account_sources =
937 g_ptr_array_new_with_free_func (
938 (GDestroyNotify) g_object_unref);
939
940 assistant->priv->transport_sources =
941 g_ptr_array_new_with_free_func (
942 (GDestroyNotify) g_object_unref);
943
944 assistant->priv->visited_pages = g_hash_table_new (NULL, NULL);
945 }
946
947 GtkWidget *
948 e_mail_config_assistant_new (EMailSession *session)
949 {
950 g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL);
951
952 return g_object_new (
953 E_TYPE_MAIL_CONFIG_ASSISTANT,
954 "session", session, NULL);
955 }
956
957 EMailSession *
958 e_mail_config_assistant_get_session (EMailConfigAssistant *assistant)
959 {
960 g_return_val_if_fail (E_IS_MAIL_CONFIG_ASSISTANT (assistant), NULL);
961
962 return assistant->priv->session;
963 }
964
965 EMailConfigServiceBackend *
966 e_mail_config_assistant_get_account_backend (EMailConfigAssistant *assistant)
967 {
968 EMailConfigServicePage *page;
969
970 g_return_val_if_fail (E_IS_MAIL_CONFIG_ASSISTANT (assistant), NULL);
971
972 page = assistant->priv->receiving_page;
973
974 return e_mail_config_service_page_get_active_backend (page);
975 }
976
977 ESource *
978 e_mail_config_assistant_get_account_source (EMailConfigAssistant *assistant)
979 {
980 EMailConfigServiceBackend *backend;
981 ESource *source = NULL;
982
983 g_return_val_if_fail (E_IS_MAIL_CONFIG_ASSISTANT (assistant), NULL);
984
985 backend = e_mail_config_assistant_get_account_backend (assistant);
986
987 if (backend != NULL)
988 source = e_mail_config_service_backend_get_source (backend);
989
990 return source;
991 }
992
993 ESource *
994 e_mail_config_assistant_get_identity_source (EMailConfigAssistant *assistant)
995 {
996 g_return_val_if_fail (E_IS_MAIL_CONFIG_ASSISTANT (assistant), NULL);
997
998 return assistant->priv->identity_source;
999 }
1000
1001 EMailConfigServiceBackend *
1002 e_mail_config_assistant_get_transport_backend (EMailConfigAssistant *assistant)
1003 {
1004 EMailConfigServicePage *page;
1005
1006 g_return_val_if_fail (E_IS_MAIL_CONFIG_ASSISTANT (assistant), NULL);
1007
1008 page = assistant->priv->sending_page;
1009
1010 return e_mail_config_service_page_get_active_backend (page);
1011 }
1012
1013 ESource *
1014 e_mail_config_assistant_get_transport_source (EMailConfigAssistant *assistant)
1015 {
1016 EMailConfigServiceBackend *backend;
1017 ESource *source = NULL;
1018
1019 g_return_val_if_fail (E_IS_MAIL_CONFIG_ASSISTANT (assistant), NULL);
1020
1021 backend = e_mail_config_assistant_get_transport_backend (assistant);
1022
1023 if (backend != NULL)
1024 source = e_mail_config_service_backend_get_source (backend);
1025
1026 return source;
1027 }
1028
1029 void
1030 e_mail_config_assistant_add_page (EMailConfigAssistant *assistant,
1031 EMailConfigPage *page)
1032 {
1033 EMailConfigPageInterface *page_interface;
1034 GtkAssistantPageType page_type;
1035 GtkWidget *page_widget;
1036 gint n_pages, position;
1037 const gchar *page_title;
1038 gboolean complete;
1039
1040 g_return_if_fail (E_IS_MAIL_CONFIG_ASSISTANT (assistant));
1041 g_return_if_fail (E_IS_MAIL_CONFIG_PAGE (page));
1042
1043 page_widget = GTK_WIDGET (page);
1044 page_interface = E_MAIL_CONFIG_PAGE_GET_INTERFACE (page);
1045 page_type = page_interface->page_type;
1046 page_title = page_interface->title;
1047
1048 /* Determine the position to insert the page. */
1049 n_pages = gtk_assistant_get_n_pages (GTK_ASSISTANT (assistant));
1050 for (position = 0; position < n_pages; position++) {
1051 GtkWidget *nth_page;
1052
1053 nth_page = gtk_assistant_get_nth_page (
1054 GTK_ASSISTANT (assistant), position);
1055 if (e_mail_config_page_compare (page_widget, nth_page) < 0)
1056 break;
1057 }
1058
1059 gtk_widget_show (page_widget);
1060
1061 /* Some pages can be clicked through unchanged. */
1062 complete = e_mail_config_page_check_complete (page);
1063
1064 gtk_assistant_insert_page (
1065 GTK_ASSISTANT (assistant), page_widget, position);
1066 gtk_assistant_set_page_type (
1067 GTK_ASSISTANT (assistant), page_widget, page_type);
1068 gtk_assistant_set_page_title (
1069 GTK_ASSISTANT (assistant), page_widget, page_title);
1070 gtk_assistant_set_page_complete (
1071 GTK_ASSISTANT (assistant), page_widget, complete);
1072
1073 /* XXX GtkAssistant has no equivalent to GtkNotebook's
1074 * "page-added" and "page-removed" signals. Fortunately
1075 * removing a page does trigger GtkContainer::remove, so
1076 * we can override that method and disconnect our signal
1077 * handler before chaining up. But I don't see any way
1078 * for a subclass to intercept GtkAssistant pages being
1079 * added, so we have to connect our signal handler here.
1080 * Not really an issue, I'm just being pedantic. */
1081
1082 g_signal_connect (
1083 page, "changed",
1084 G_CALLBACK (mail_config_assistant_page_changed),
1085 assistant);
1086 }
1087
1088 /********************* e_mail_config_assistant_commit() **********************/
1089
1090 static void
1091 mail_config_assistant_commit_cb (GObject *object,
1092 GAsyncResult *result,
1093 gpointer user_data)
1094 {
1095 GSimpleAsyncResult *simple;
1096 GError *error = NULL;
1097
1098 simple = G_SIMPLE_ASYNC_RESULT (user_data);
1099
1100 e_source_registry_create_sources_finish (
1101 E_SOURCE_REGISTRY (object), result, &error);
1102
1103 if (error != NULL)
1104 g_simple_async_result_take_error (simple, error);
1105
1106 g_simple_async_result_complete (simple);
1107
1108 g_object_unref (simple);
1109 }
1110
1111 void
1112 e_mail_config_assistant_commit (EMailConfigAssistant *assistant,
1113 GCancellable *cancellable,
1114 GAsyncReadyCallback callback,
1115 gpointer user_data)
1116 {
1117 EMailConfigServiceBackend *backend;
1118 GSimpleAsyncResult *simple;
1119 ESourceRegistry *registry;
1120 EMailSession *session;
1121 ESource *source;
1122 GQueue *queue;
1123 gint n_pages, ii;
1124
1125 g_return_if_fail (E_IS_MAIL_CONFIG_ASSISTANT (assistant));
1126
1127 session = e_mail_config_assistant_get_session (assistant);
1128 registry = e_mail_session_get_registry (session);
1129
1130 queue = g_queue_new ();
1131
1132 /* Queue the collection data source if one is defined. */
1133 backend = e_mail_config_assistant_get_account_backend (assistant);
1134 source = e_mail_config_service_backend_get_collection (backend);
1135 if (source != NULL)
1136 g_queue_push_tail (queue, g_object_ref (source));
1137
1138 /* Queue the mail-related data sources for the account. */
1139 source = e_mail_config_assistant_get_account_source (assistant);
1140 if (source != NULL)
1141 g_queue_push_tail (queue, g_object_ref (source));
1142 source = e_mail_config_assistant_get_identity_source (assistant);
1143 if (source != NULL)
1144 g_queue_push_tail (queue, g_object_ref (source));
1145 source = e_mail_config_assistant_get_transport_source (assistant);
1146 if (source != NULL)
1147 g_queue_push_tail (queue, g_object_ref (source));
1148
1149 n_pages = gtk_assistant_get_n_pages (GTK_ASSISTANT (assistant));
1150
1151 /* Tell all EMailConfigPages to commit their UI state to their
1152 * scratch ESources and push any additional data sources on to
1153 * the given source queue, such as calendars or address books
1154 * to be bundled with the mail account. */
1155 for (ii = 0; ii < n_pages; ii++) {
1156 GtkWidget *widget;
1157
1158 widget = gtk_assistant_get_nth_page (
1159 GTK_ASSISTANT (assistant), ii);
1160
1161 if (E_IS_MAIL_CONFIG_PAGE (widget)) {
1162 EMailConfigPage *page;
1163 page = E_MAIL_CONFIG_PAGE (widget);
1164 e_mail_config_page_commit_changes (page, queue);
1165 }
1166 }
1167
1168 simple = g_simple_async_result_new (
1169 G_OBJECT (assistant), callback, user_data,
1170 e_mail_config_assistant_commit);
1171
1172 e_source_registry_create_sources (
1173 registry, g_queue_peek_head_link (queue),
1174 cancellable, mail_config_assistant_commit_cb, simple);
1175
1176 g_queue_free_full (queue, (GDestroyNotify) g_object_unref);
1177 }
1178
1179 gboolean
1180 e_mail_config_assistant_commit_finish (EMailConfigAssistant *assistant,
1181 GAsyncResult *result,
1182 GError **error)
1183 {
1184 GSimpleAsyncResult *simple;
1185
1186 g_return_val_if_fail (
1187 g_simple_async_result_is_valid (
1188 result, G_OBJECT (assistant),
1189 e_mail_config_assistant_commit), FALSE);
1190
1191 simple = G_SIMPLE_ASYNC_RESULT (result);
1192
1193 /* Assume success unless a GError is set. */
1194 return !g_simple_async_result_propagate_error (simple, error);
1195 }