1 /*
2 * e-mail-config-assistant.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 #include "evolution-config.h"
19
20 #include <glib/gi18n-lib.h>
21
22 #include <libebackend/libebackend.h>
23
24 #include <e-util/e-util.h>
25 #include <shell/e-shell.h>
26 #include <shell/e-shell-window.h>
27 #include <shell/e-shell-view.h>
28 #include <shell/e-shell-sidebar.h>
29
30 #include "e-mail-config-confirm-page.h"
31 #include "e-mail-config-identity-page.h"
32 #include "e-mail-config-lookup-page.h"
33 #include "e-mail-config-provider-page.h"
34 #include "e-mail-config-receiving-page.h"
35 #include "e-mail-config-sending-page.h"
36 #include "e-mail-config-summary-page.h"
37 #include "e-mail-config-welcome-page.h"
38
39 #include "em-folder-tree.h"
40
41 #include "e-mail-config-assistant.h"
42
43 #define E_MAIL_CONFIG_ASSISTANT_GET_PRIVATE(obj) \
44 (G_TYPE_INSTANCE_GET_PRIVATE \
45 ((obj), E_TYPE_MAIL_CONFIG_ASSISTANT, EMailConfigAssistantPrivate))
46
47 /* GtkAssistant's back button label. */
48 #define BACK_BUTTON_LABEL N_("Go _Back")
49
50 typedef struct _ConfigLookupContext ConfigLookupContext;
51
52 struct _EMailConfigAssistantPrivate {
53 EMailSession *session;
54 ESource *identity_source;
55 GPtrArray *account_sources;
56 GPtrArray *transport_sources;
57 EMailConfigServicePage *receiving_page;
58 EMailConfigServicePage *sending_page;
59 EMailConfigSummaryPage *summary_page;
60 EMailConfigPage *identity_page;
61 EMailConfigPage *lookup_page;
62 GHashTable *visited_pages;
63 gboolean auto_configured;
64
65 /* GtkAssistant owns this. */
66 GtkButton *back_button; /* not referenced */
67 };
68
69 struct _ConfigLookupContext {
70 GtkAssistant *assistant;
71 GCancellable *cancellable;
72 GtkWidget *skip_button; /* not referenced */
73 EConfigLookup *config_lookup;
74 gchar *email_address;
75 };
76
77 enum {
78 PROP_0,
79 PROP_ACCOUNT_BACKEND,
80 PROP_ACCOUNT_SOURCE,
81 PROP_IDENTITY_SOURCE,
82 PROP_SESSION,
83 PROP_TRANSPORT_BACKEND,
84 PROP_TRANSPORT_SOURCE
85 };
86
87 enum {
88 NEW_SOURCE,
89 LAST_SIGNAL
90 };
91
92 static gulong signals[LAST_SIGNAL];
93
94 /* XXX We implement EAlertSink but don't implement a custom submit_alert()
95 * method. So any alert results in a pop-up message dialog, which is a
96 * fashion faux pas these days. But it's only used when submitting the
97 * the newly-configured account fails, so should rarely be seen. */
98
G_DEFINE_TYPE_WITH_CODE(EMailConfigAssistant,e_mail_config_assistant,GTK_TYPE_ASSISTANT,G_IMPLEMENT_INTERFACE (E_TYPE_ALERT_SINK,NULL)G_IMPLEMENT_INTERFACE (E_TYPE_EXTENSIBLE,NULL))99 G_DEFINE_TYPE_WITH_CODE (
100 EMailConfigAssistant,
101 e_mail_config_assistant,
102 GTK_TYPE_ASSISTANT,
103 G_IMPLEMENT_INTERFACE (
104 E_TYPE_ALERT_SINK, NULL)
105 G_IMPLEMENT_INTERFACE (
106 E_TYPE_EXTENSIBLE, NULL))
107
108 static void
109 config_lookup_skip_button_clicked_cb (GtkButton *button,
110 GCancellable *cancellable)
111 {
112 g_cancellable_cancel (cancellable);
113 }
114
115 static ConfigLookupContext *
config_lookup_context_new(GtkAssistant * assistant,ESourceRegistry * registry,const gchar * email_address)116 config_lookup_context_new (GtkAssistant *assistant,
117 ESourceRegistry *registry,
118 const gchar *email_address)
119 {
120 ConfigLookupContext *context;
121 const gchar *text;
122
123 context = g_slice_new0 (ConfigLookupContext);
124 context->assistant = g_object_ref (assistant);
125 context->cancellable = g_cancellable_new ();
126 context->config_lookup = e_config_lookup_new (registry);
127 context->email_address = g_strdup (email_address);
128
129 /* GtkAssistant sinks the floating button reference. */
130 text = _("_Skip Lookup");
131 context->skip_button = gtk_button_new_with_mnemonic (text);
132 gtk_assistant_add_action_widget (
133 context->assistant, context->skip_button);
134 gtk_widget_show (context->skip_button);
135
136 g_signal_connect_object (
137 context->skip_button, "clicked",
138 G_CALLBACK (config_lookup_skip_button_clicked_cb),
139 context->cancellable, 0);
140
141 return context;
142 }
143
144 static void
config_lookup_context_free(ConfigLookupContext * context)145 config_lookup_context_free (ConfigLookupContext *context)
146 {
147 gtk_assistant_remove_action_widget (
148 context->assistant, context->skip_button);
149
150 g_object_unref (context->assistant);
151 g_object_unref (context->cancellable);
152 g_object_unref (context->config_lookup);
153 g_free (context->email_address);
154
155 g_slice_free (ConfigLookupContext, context);
156 }
157
158 static gint
mail_config_assistant_provider_compare(gconstpointer data1,gconstpointer data2)159 mail_config_assistant_provider_compare (gconstpointer data1,
160 gconstpointer data2)
161 {
162 const CamelProvider *provider1 = data1;
163 const CamelProvider *provider2 = data2;
164
165 /* The "none" provider comes first. */
166 if (g_strcmp0 (provider1->protocol, "none") == 0)
167 return -1;
168 if (g_strcmp0 (provider2->protocol, "none") == 0)
169 return 1;
170
171 /* Then sort remote providers before local providers. */
172 if (provider1->flags & CAMEL_PROVIDER_IS_REMOTE) {
173 if (provider2->flags & CAMEL_PROVIDER_IS_REMOTE)
174 return 0;
175 else
176 return -1;
177 } else {
178 if (provider2->flags & CAMEL_PROVIDER_IS_REMOTE)
179 return 1;
180 else
181 return 0;
182 }
183 }
184
185 static GList *
mail_config_assistant_list_providers(void)186 mail_config_assistant_list_providers (void)
187 {
188 GList *list, *link;
189 GQueue trash = G_QUEUE_INIT;
190
191 list = camel_provider_list (TRUE);
192 list = g_list_sort (list, mail_config_assistant_provider_compare);
193
194 /* Keep only providers with a "mail" or "news" domain. */
195
196 for (link = list; link != NULL; link = g_list_next (link)) {
197 CamelProvider *provider = link->data;
198 gboolean mail_or_news_domain;
199
200 mail_or_news_domain =
201 (g_strcmp0 (provider->domain, "mail") == 0) ||
202 (g_strcmp0 (provider->domain, "news") == 0);
203
204 if (mail_or_news_domain)
205 continue;
206
207 g_queue_push_tail (&trash, link);
208 }
209
210 while ((link = g_queue_pop_head (&trash)) != NULL)
211 list = g_list_delete_link (list, link);
212
213 return list;
214 }
215
216 static void
mail_config_assistant_notify_account_backend(EMailConfigServicePage * page,GParamSpec * pspec,EMailConfigAssistant * assistant)217 mail_config_assistant_notify_account_backend (EMailConfigServicePage *page,
218 GParamSpec *pspec,
219 EMailConfigAssistant *assistant)
220 {
221 EMailConfigServiceBackend *backend;
222 EMailConfigServicePage *sending_page;
223 EMailConfigServicePageClass *page_class;
224 CamelProvider *provider;
225
226 backend = e_mail_config_service_page_get_active_backend (page);
227
228 /* The Receiving Page combo box may not have an active item. */
229 if (backend == NULL)
230 goto notify;
231
232 /* The Sending Page may not have been created yet. */
233 if (assistant->priv->sending_page == NULL)
234 goto notify;
235
236 provider = e_mail_config_service_backend_get_provider (backend);
237
238 /* XXX This should never fail, but the Camel macro below does
239 * not check for NULL so better to malfunction than crash. */
240 g_return_if_fail (provider != NULL);
241
242 sending_page = assistant->priv->sending_page;
243 page_class = E_MAIL_CONFIG_SERVICE_PAGE_GET_CLASS (sending_page);
244
245 /* The Sending Page is invisible when the CamelProvider for the
246 * receiving type defines both a storage and transport service.
247 * This is common in CamelProviders for groupware products like
248 * Microsoft Exchange and Novell GroupWise. */
249 if (CAMEL_PROVIDER_IS_STORE_AND_TRANSPORT (provider) &&
250 g_strcmp0 (provider->protocol, "none") != 0) {
251 backend = e_mail_config_service_page_lookup_backend (
252 sending_page, provider->protocol);
253 gtk_widget_hide (GTK_WIDGET (sending_page));
254 } else {
255 backend = e_mail_config_service_page_lookup_backend (
256 sending_page, page_class->default_backend_name);
257 gtk_widget_show (GTK_WIDGET (sending_page));
258 }
259
260 e_mail_config_service_page_set_active_backend (sending_page, backend);
261
262 notify:
263 g_object_freeze_notify (G_OBJECT (assistant));
264
265 g_object_notify (G_OBJECT (assistant), "account-backend");
266 g_object_notify (G_OBJECT (assistant), "account-source");
267
268 g_object_thaw_notify (G_OBJECT (assistant));
269 }
270
271 static void
mail_config_assistant_notify_transport_backend(EMailConfigServicePage * page,GParamSpec * pspec,EMailConfigAssistant * assistant)272 mail_config_assistant_notify_transport_backend (EMailConfigServicePage *page,
273 GParamSpec *pspec,
274 EMailConfigAssistant *assistant)
275 {
276 g_object_freeze_notify (G_OBJECT (assistant));
277
278 g_object_notify (G_OBJECT (assistant), "transport-backend");
279 g_object_notify (G_OBJECT (assistant), "transport-source");
280
281 g_object_thaw_notify (G_OBJECT (assistant));
282 }
283
284 static void
mail_config_assistant_page_changed(EMailConfigPage * page,EMailConfigAssistant * assistant)285 mail_config_assistant_page_changed (EMailConfigPage *page,
286 EMailConfigAssistant *assistant)
287 {
288 gtk_assistant_set_page_complete (
289 GTK_ASSISTANT (assistant), GTK_WIDGET (page),
290 e_mail_config_page_check_complete (page));
291 }
292
293 static void
mail_config_assistant_config_lookup_run_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)294 mail_config_assistant_config_lookup_run_cb (GObject *source_object,
295 GAsyncResult *result,
296 gpointer user_data)
297 {
298 EMailConfigAssistantPrivate *priv;
299 ConfigLookupContext *context;
300 gint n_pages, ii, complete = 0;
301 gboolean any_configured = FALSE;
302 gboolean is_complete;
303
304 context = (ConfigLookupContext *) user_data;
305
306 priv = E_MAIL_CONFIG_ASSISTANT_GET_PRIVATE (context->assistant);
307
308 e_config_lookup_run_finish (E_CONFIG_LOOKUP (source_object), result);
309
310 is_complete = FALSE;
311
312 if (e_mail_config_service_page_auto_configure (priv->receiving_page, context->config_lookup, &is_complete)) {
313 any_configured = TRUE;
314 /* Add the page to the visited pages hash table to
315 * prevent calling e_mail_config_page_setup_defaults(). */
316 g_hash_table_add (priv->visited_pages, priv->receiving_page);
317
318 if (is_complete)
319 complete++;
320 }
321
322 is_complete = FALSE;
323
324 if (e_mail_config_service_page_auto_configure (priv->sending_page, context->config_lookup, &is_complete)) {
325 any_configured = TRUE;
326 /* Add the page to the visited pages hash table to
327 * prevent calling e_mail_config_page_setup_defaults(). */
328 g_hash_table_add (priv->visited_pages, priv->sending_page);
329
330 if (is_complete)
331 complete++;
332 }
333
334 if (!any_configured || complete != 2) {
335 if (any_configured) {
336 /* Set the initial display name to the email address
337 * given so the user can just click past the Summary page. */
338 e_source_set_display_name (priv->identity_source, context->email_address);
339 }
340
341 gtk_assistant_next_page (context->assistant);
342 goto exit;
343 }
344
345 /* Autoconfiguration worked! Feed the results to the
346 * service pages and then skip to the Summary page. */
347
348 /* For the summary page... */
349 priv->auto_configured = TRUE;
350
351 /* Also set the initial display name to the email address
352 * given so the user can just click past the Summary page. */
353 e_source_set_display_name (priv->identity_source, context->email_address);
354
355 /* Go to the next page (Receiving Email) before skipping to the
356 * Summary Page to get it into GtkAssistant visited page history.
357 * We want the back button to return to Receiving Email. */
358 gtk_assistant_next_page (context->assistant);
359
360 /* XXX Can't find a better way to learn the page number of
361 * the summary page. Oh my god this API is horrible. */
362 n_pages = gtk_assistant_get_n_pages (context->assistant);
363 for (ii = 0; ii < n_pages; ii++) {
364 GtkWidget *page;
365
366 page = gtk_assistant_get_nth_page (context->assistant, ii);
367 if (E_IS_MAIL_CONFIG_SUMMARY_PAGE (page))
368 break;
369 }
370
371 g_warn_if_fail (ii < n_pages);
372 gtk_assistant_set_current_page (context->assistant, ii);
373
374 exit:
375 /* Set the page invisible so we never revisit it. */
376 gtk_widget_set_visible (GTK_WIDGET (priv->lookup_page), FALSE);
377
378 config_lookup_context_free (context);
379 }
380
381 static ESource *
mail_config_assistant_get_source_cb(EConfigLookup * config_lookup,EConfigLookupSourceKind kind,gpointer user_data)382 mail_config_assistant_get_source_cb (EConfigLookup *config_lookup,
383 EConfigLookupSourceKind kind,
384 gpointer user_data)
385 {
386 EMailConfigAssistant *assistant = user_data;
387 EMailConfigServiceBackend *backend;
388 ESource *source = NULL;
389
390 g_return_val_if_fail (E_IS_CONFIG_LOOKUP (config_lookup), NULL);
391 g_return_val_if_fail (E_IS_MAIL_CONFIG_ASSISTANT (assistant), NULL);
392
393 switch (kind) {
394 case E_CONFIG_LOOKUP_SOURCE_UNKNOWN:
395 break;
396 case E_CONFIG_LOOKUP_SOURCE_COLLECTION:
397 backend = e_mail_config_assistant_get_account_backend (assistant);
398 source = e_mail_config_service_backend_get_collection (backend);
399 break;
400 case E_CONFIG_LOOKUP_SOURCE_MAIL_ACCOUNT:
401 source = e_mail_config_assistant_get_account_source (assistant);
402 break;
403 case E_CONFIG_LOOKUP_SOURCE_MAIL_IDENTITY:
404 source = e_mail_config_assistant_get_identity_source (assistant);
405 break;
406 case E_CONFIG_LOOKUP_SOURCE_MAIL_TRANSPORT:
407 source = e_mail_config_assistant_get_transport_source (assistant);
408 break;
409 }
410
411 return source;
412 }
413
414 static gboolean
mail_config_assistant_provider_page_visible(GBinding * binding,const GValue * source_value,GValue * target_value,gpointer unused)415 mail_config_assistant_provider_page_visible (GBinding *binding,
416 const GValue *source_value,
417 GValue *target_value,
418 gpointer unused)
419 {
420 EMailConfigServiceBackend *active_backend;
421 EMailConfigServiceBackend *page_backend;
422 EMailConfigProviderPage *page;
423 GObject *target_object;
424 gboolean visible;
425
426 target_object = g_binding_get_target (binding);
427 page = E_MAIL_CONFIG_PROVIDER_PAGE (target_object);
428 page_backend = e_mail_config_provider_page_get_backend (page);
429
430 active_backend = g_value_get_object (source_value);
431 visible = (page_backend == active_backend);
432 g_value_set_boolean (target_value, visible);
433
434 return TRUE;
435 }
436
437 static void
mail_config_assistant_select_account_node(const gchar * account_uid)438 mail_config_assistant_select_account_node (const gchar *account_uid)
439 {
440 EShell *shell;
441 EShellWindow *shell_window;
442 EShellView *shell_view;
443 EShellSidebar *shell_sidebar;
444 EMFolderTree *folder_tree = NULL;
445 GtkWindow *active_window;
446 const gchar *active_view;
447
448 g_return_if_fail (account_uid != NULL);
449
450 shell = e_shell_get_default ();
451 active_window = e_shell_get_active_window (shell);
452
453 if (!E_IS_SHELL_WINDOW (active_window))
454 return;
455
456 shell_window = E_SHELL_WINDOW (active_window);
457 active_view = e_shell_window_get_active_view (shell_window);
458
459 if (g_strcmp0 (active_view, "mail") != 0)
460 return;
461
462 shell_view = e_shell_window_get_shell_view (shell_window, "mail");
463
464 shell_sidebar = e_shell_view_get_shell_sidebar (shell_view);
465 g_object_get (shell_sidebar, "folder-tree", &folder_tree, NULL);
466
467 em_folder_tree_select_store_when_added (folder_tree, account_uid);
468
469 g_object_unref (folder_tree);
470
471 }
472
473 static void
mail_config_assistant_close_cb(GObject * object,GAsyncResult * result,gpointer user_data)474 mail_config_assistant_close_cb (GObject *object,
475 GAsyncResult *result,
476 gpointer user_data)
477 {
478 EMailConfigAssistant *assistant;
479 GdkWindow *gdk_window;
480 GError *error = NULL;
481
482 assistant = E_MAIL_CONFIG_ASSISTANT (object);
483
484 /* Set the cursor back to normal. */
485 gdk_window = gtk_widget_get_window (GTK_WIDGET (assistant));
486 gdk_window_set_cursor (gdk_window, NULL);
487
488 /* Allow user interaction with window content. */
489 gtk_widget_set_sensitive (GTK_WIDGET (assistant), TRUE);
490
491 e_mail_config_assistant_commit_finish (assistant, result, &error);
492
493 /* Ignore cancellations. */
494 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
495 g_error_free (error);
496
497 } else if (error != NULL) {
498 e_alert_submit (
499 E_ALERT_SINK (assistant),
500 "system:simple-error",
501 error->message, NULL);
502 g_error_free (error);
503
504 } else {
505 ESource *source;
506
507 source = e_mail_config_assistant_get_account_source (assistant);
508 if (source != NULL) {
509 const gchar *uid;
510
511 uid = e_source_get_uid (source);
512 mail_config_assistant_select_account_node (uid);
513 }
514
515 gtk_widget_destroy (GTK_WIDGET (assistant));
516 }
517 }
518
519 static void
mail_config_assistant_find_back_button_cb(GtkWidget * widget,gpointer user_data)520 mail_config_assistant_find_back_button_cb (GtkWidget *widget,
521 gpointer user_data)
522 {
523 EMailConfigAssistant *assistant;
524
525 assistant = E_MAIL_CONFIG_ASSISTANT (user_data);
526
527 if (GTK_IS_BUTTON (widget)) {
528 GtkButton *button;
529 const gchar *gtk_label;
530 const gchar *our_label;
531
532 button = GTK_BUTTON (widget);
533
534 /* XXX The gtkassistant.ui file assigns the back button
535 * an ID of "back", but I don't think we have access
536 * to it from here. I guess just compare by label,
537 * and hope our translation matches GTK's. Yuck. */
538
539 gtk_label = gtk_button_get_label (button);
540 our_label = gettext (BACK_BUTTON_LABEL);
541
542 if (g_strcmp0 (gtk_label, our_label) == 0)
543 assistant->priv->back_button = button;
544
545 } else if (GTK_IS_CONTAINER (widget)) {
546 gtk_container_forall (
547 GTK_CONTAINER (widget),
548 mail_config_assistant_find_back_button_cb,
549 assistant);
550 }
551 }
552
553 static void
mail_config_assistant_set_session(EMailConfigAssistant * assistant,EMailSession * session)554 mail_config_assistant_set_session (EMailConfigAssistant *assistant,
555 EMailSession *session)
556 {
557 g_return_if_fail (E_IS_MAIL_SESSION (session));
558 g_return_if_fail (assistant->priv->session == NULL);
559
560 assistant->priv->session = g_object_ref (session);
561 }
562
563 static void
mail_config_assistant_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)564 mail_config_assistant_set_property (GObject *object,
565 guint property_id,
566 const GValue *value,
567 GParamSpec *pspec)
568 {
569 switch (property_id) {
570 case PROP_SESSION:
571 mail_config_assistant_set_session (
572 E_MAIL_CONFIG_ASSISTANT (object),
573 g_value_get_object (value));
574 return;
575 }
576
577 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
578 }
579
580 static void
mail_config_assistant_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)581 mail_config_assistant_get_property (GObject *object,
582 guint property_id,
583 GValue *value,
584 GParamSpec *pspec)
585 {
586 switch (property_id) {
587 case PROP_ACCOUNT_BACKEND:
588 g_value_set_object (
589 value,
590 e_mail_config_assistant_get_account_backend (
591 E_MAIL_CONFIG_ASSISTANT (object)));
592 return;
593
594 case PROP_ACCOUNT_SOURCE:
595 g_value_set_object (
596 value,
597 e_mail_config_assistant_get_account_source (
598 E_MAIL_CONFIG_ASSISTANT (object)));
599 return;
600
601 case PROP_IDENTITY_SOURCE:
602 g_value_set_object (
603 value,
604 e_mail_config_assistant_get_identity_source (
605 E_MAIL_CONFIG_ASSISTANT (object)));
606 return;
607
608 case PROP_SESSION:
609 g_value_set_object (
610 value,
611 e_mail_config_assistant_get_session (
612 E_MAIL_CONFIG_ASSISTANT (object)));
613 return;
614
615 case PROP_TRANSPORT_BACKEND:
616 g_value_set_object (
617 value,
618 e_mail_config_assistant_get_transport_backend (
619 E_MAIL_CONFIG_ASSISTANT (object)));
620 return;
621
622 case PROP_TRANSPORT_SOURCE:
623 g_value_set_object (
624 value,
625 e_mail_config_assistant_get_transport_source (
626 E_MAIL_CONFIG_ASSISTANT (object)));
627 return;
628 }
629
630 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
631 }
632
633 static void
mail_config_assistant_dispose(GObject * object)634 mail_config_assistant_dispose (GObject *object)
635 {
636 EMailConfigAssistantPrivate *priv;
637
638 priv = E_MAIL_CONFIG_ASSISTANT_GET_PRIVATE (object);
639 g_clear_object (&priv->session);
640 g_clear_object (&priv->identity_source);
641 g_clear_object (&priv->receiving_page);
642 g_clear_object (&priv->sending_page);
643 g_clear_object (&priv->summary_page);
644 g_clear_object (&priv->lookup_page);
645 g_clear_object (&priv->identity_page);
646
647 g_ptr_array_set_size (priv->account_sources, 0);
648 g_ptr_array_set_size (priv->transport_sources, 0);
649
650 /* Chain up to parent's dispose() method. */
651 G_OBJECT_CLASS (e_mail_config_assistant_parent_class)->
652 dispose (object);
653 }
654
655 static void
mail_config_assistant_finalize(GObject * object)656 mail_config_assistant_finalize (GObject *object)
657 {
658 EMailConfigAssistantPrivate *priv;
659
660 priv = E_MAIL_CONFIG_ASSISTANT_GET_PRIVATE (object);
661
662 g_ptr_array_free (priv->account_sources, TRUE);
663 g_ptr_array_free (priv->transport_sources, TRUE);
664
665 g_hash_table_destroy (priv->visited_pages);
666
667 /* Chain up to parent's finalize() method. */
668 G_OBJECT_CLASS (e_mail_config_assistant_parent_class)->
669 finalize (object);
670 }
671
672 static void
mail_config_assistant_prefill_user(ESource * on_source)673 mail_config_assistant_prefill_user (ESource *on_source)
674 {
675 if (e_source_has_extension (on_source, E_SOURCE_EXTENSION_AUTHENTICATION)) {
676 ESourceAuthentication *auth_extension;
677
678 auth_extension = e_source_get_extension (on_source, E_SOURCE_EXTENSION_AUTHENTICATION);
679
680 if (!e_source_authentication_get_user (auth_extension))
681 e_source_authentication_set_user (auth_extension, g_get_user_name ());
682 }
683 }
684
685 static void
mail_config_assistant_constructed(GObject * object)686 mail_config_assistant_constructed (GObject *object)
687 {
688 EMailConfigAssistant *assistant;
689 ESource *identity_source;
690 ESourceRegistry *registry;
691 ESourceExtension *extension;
692 ESourceMailComposition *mail_composition_extension;
693 ESourceMailIdentity *mail_identity_extension;
694 ESourceMailSubmission *mail_submission_extension;
695 EMailSession *session;
696 EMailConfigPage *page;
697 GtkWidget *autodiscover_check;
698 GList *list, *link;
699 const gchar *extension_name;
700 const gchar *title;
701 GtkRequisition requisition;
702 GSList *children = NULL;
703 gint ii, npages;
704
705 assistant = E_MAIL_CONFIG_ASSISTANT (object);
706
707 /* Chain up to parent's constructed() method. */
708 G_OBJECT_CLASS (e_mail_config_assistant_parent_class)->constructed (object);
709
710 title = _("Evolution Account Assistant");
711 gtk_window_set_title (GTK_WINDOW (assistant), title);
712 gtk_window_set_position (GTK_WINDOW (assistant), GTK_WIN_POS_CENTER);
713 gtk_window_set_default_size (GTK_WINDOW (assistant), 640, 480);
714
715 session = e_mail_config_assistant_get_session (assistant);
716 registry = e_mail_session_get_registry (session);
717
718 /* XXX Locate the GtkAssistant's internal "Go Back" button so
719 * we can temporarily rename it for autoconfigure results.
720 * Walking the container like this is an extremely naughty
721 * and brittle hack, but GtkAssistant does not provide API
722 * to access it directly. */
723 gtk_container_forall (
724 GTK_CONTAINER (assistant),
725 mail_config_assistant_find_back_button_cb,
726 assistant);
727
728 /* Configure a new identity source. */
729
730 identity_source = e_source_new (NULL, NULL, NULL);
731 assistant->priv->identity_source = identity_source;
732 session = e_mail_config_assistant_get_session (assistant);
733
734 extension_name = E_SOURCE_EXTENSION_MAIL_COMPOSITION;
735 extension = e_source_get_extension (identity_source, extension_name);
736 mail_composition_extension = E_SOURCE_MAIL_COMPOSITION (extension);
737
738 extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY;
739 extension = e_source_get_extension (identity_source, extension_name);
740 mail_identity_extension = E_SOURCE_MAIL_IDENTITY (extension);
741
742 extension_name = E_SOURCE_EXTENSION_MAIL_SUBMISSION;
743 extension = e_source_get_extension (identity_source, extension_name);
744 mail_submission_extension = E_SOURCE_MAIL_SUBMISSION (extension);
745
746 e_source_mail_identity_set_name (mail_identity_extension, g_get_real_name ());
747
748 e_source_mail_composition_set_drafts_folder (
749 mail_composition_extension,
750 e_mail_session_get_local_folder_uri (
751 session, E_MAIL_LOCAL_FOLDER_DRAFTS));
752
753 e_source_mail_composition_set_templates_folder (
754 mail_composition_extension,
755 e_mail_session_get_local_folder_uri (
756 session, E_MAIL_LOCAL_FOLDER_TEMPLATES));
757
758 e_source_mail_submission_set_sent_folder (
759 mail_submission_extension,
760 e_mail_session_get_local_folder_uri (
761 session, E_MAIL_LOCAL_FOLDER_SENT));
762
763 gtk_widget_get_preferred_size (GTK_WIDGET (assistant), &requisition, NULL);
764 requisition.width += 2 * 12;
765 requisition.height += 2 * 12;
766
767 /*** Welcome Page ***/
768
769 page = e_mail_config_welcome_page_new ();
770 e_mail_config_assistant_add_page (assistant, page);
771
772 /*** Identity Page ***/
773
774 page = e_mail_config_identity_page_new (registry, identity_source);
775 e_mail_config_identity_page_set_show_account_info (
776 E_MAIL_CONFIG_IDENTITY_PAGE (page), FALSE);
777 e_mail_config_identity_page_set_show_signatures (
778 E_MAIL_CONFIG_IDENTITY_PAGE (page), FALSE);
779 e_mail_config_identity_page_set_show_autodiscover_check (
780 E_MAIL_CONFIG_IDENTITY_PAGE (page), TRUE);
781 autodiscover_check = e_mail_config_identity_page_get_autodiscover_check (
782 E_MAIL_CONFIG_IDENTITY_PAGE (page));
783 e_mail_config_assistant_add_page (assistant, page);
784 assistant->priv->identity_page = g_object_ref (page);
785
786 /*** Lookup Page ***/
787
788 page = e_mail_config_lookup_page_new ();
789 e_mail_config_assistant_add_page (assistant, page);
790 assistant->priv->lookup_page = g_object_ref (page);
791
792 e_binding_bind_property (
793 autodiscover_check, "active",
794 page, "visible",
795 G_BINDING_SYNC_CREATE);
796
797 /*** Receiving Page ***/
798
799 page = e_mail_config_receiving_page_new (registry);
800 e_mail_config_assistant_add_page (assistant, page);
801 assistant->priv->receiving_page = E_MAIL_CONFIG_SERVICE_PAGE (g_object_ref (page));
802
803 e_binding_bind_object_text_property (
804 mail_identity_extension, "address",
805 page, "email-address",
806 G_BINDING_SYNC_CREATE);
807
808 e_signal_connect_notify (
809 page, "notify::active-backend",
810 G_CALLBACK (mail_config_assistant_notify_account_backend),
811 assistant);
812
813 /*** Receiving Options (multiple) ***/
814
815 /* Populate the Receiving Email page while at the same time
816 * adding a Receiving Options page for each account type. */
817
818 list = mail_config_assistant_list_providers ();
819
820 for (link = list; link != NULL; link = g_list_next (link)) {
821 EMailConfigServiceBackend *backend;
822 CamelProvider *provider = link->data;
823 ESourceBackend *backend_extension;
824 ESource *scratch_source;
825 const gchar *backend_name;
826
827 if (provider->object_types[CAMEL_PROVIDER_STORE] == 0)
828 continue;
829
830 /* ESource uses "backend_name" and CamelProvider
831 * uses "protocol", but the terms are synonymous. */
832 backend_name = provider->protocol;
833
834 scratch_source = e_source_new (NULL, NULL, NULL);
835 backend_extension = e_source_get_extension (
836 scratch_source, E_SOURCE_EXTENSION_MAIL_ACCOUNT);
837 e_source_backend_set_backend_name (
838 backend_extension, backend_name);
839
840 /* Keep display names synchronized. */
841 e_binding_bind_property (
842 identity_source, "display-name",
843 scratch_source, "display-name",
844 G_BINDING_BIDIRECTIONAL |
845 G_BINDING_SYNC_CREATE);
846
847 /* We always pass NULL for the collection argument.
848 * The backend generates its own scratch collection
849 * source if implements the new_collection() method. */
850 backend = e_mail_config_service_page_add_scratch_source (
851 assistant->priv->receiving_page, scratch_source, NULL);
852
853 mail_config_assistant_prefill_user (scratch_source);
854
855 g_object_unref (scratch_source);
856
857 page = e_mail_config_provider_page_new (backend);
858
859 /* Note: We exclude this page if it has no options,
860 * but we don't know that until we create it. */
861 if (e_mail_config_provider_page_is_empty (
862 E_MAIL_CONFIG_PROVIDER_PAGE (page))) {
863 g_object_unref (g_object_ref_sink (page));
864 continue;
865 } else {
866 e_mail_config_assistant_add_page (assistant, page);
867 }
868
869 /* Each Receiving Options page is only visible when its
870 * service backend is active on the Receiving Email page. */
871 e_binding_bind_property_full (
872 assistant->priv->receiving_page, "active-backend",
873 page, "visible",
874 G_BINDING_SYNC_CREATE,
875 mail_config_assistant_provider_page_visible,
876 NULL,
877 NULL, (GDestroyNotify) NULL);
878 }
879
880 g_list_free (list);
881
882 /*** Sending Page ***/
883
884 page = e_mail_config_sending_page_new (registry);
885 e_mail_config_assistant_add_page (assistant, page);
886 assistant->priv->sending_page = E_MAIL_CONFIG_SERVICE_PAGE (g_object_ref (page));
887
888 e_binding_bind_object_text_property (
889 mail_identity_extension, "address",
890 page, "email-address",
891 G_BINDING_SYNC_CREATE);
892
893 e_signal_connect_notify (
894 page, "notify::active-backend",
895 G_CALLBACK (mail_config_assistant_notify_transport_backend),
896 assistant);
897
898 list = mail_config_assistant_list_providers ();
899
900 for (link = list; link != NULL; link = g_list_next (link)) {
901 CamelProvider *provider = link->data;
902 ESourceBackend *backend_extension;
903 ESource *scratch_source;
904 const gchar *backend_name;
905
906 if (provider->object_types[CAMEL_PROVIDER_TRANSPORT] == 0)
907 continue;
908
909 /* ESource uses "backend_name" and CamelProvider
910 * uses "protocol", but the terms are synonymous. */
911 backend_name = provider->protocol;
912
913 scratch_source = e_source_new (NULL, NULL, NULL);
914 backend_extension = e_source_get_extension (
915 scratch_source, E_SOURCE_EXTENSION_MAIL_TRANSPORT);
916 e_source_backend_set_backend_name (
917 backend_extension, backend_name);
918
919 /* Keep display names synchronized. */
920 e_binding_bind_property (
921 identity_source, "display-name",
922 scratch_source, "display-name",
923 G_BINDING_BIDIRECTIONAL |
924 G_BINDING_SYNC_CREATE);
925
926 /* We always pass NULL for the collection argument.
927 * The backend generates its own scratch collection
928 * source if implements the new_collection() method. */
929 e_mail_config_service_page_add_scratch_source (
930 assistant->priv->sending_page, scratch_source, NULL);
931
932 mail_config_assistant_prefill_user (scratch_source);
933
934 g_object_unref (scratch_source);
935 }
936
937 g_list_free (list);
938
939 /*** Summary Page ***/
940
941 page = e_mail_config_summary_page_new ();
942 e_mail_config_assistant_add_page (assistant, page);
943 assistant->priv->summary_page = E_MAIL_CONFIG_SUMMARY_PAGE (g_object_ref (page));
944
945 e_binding_bind_property (
946 assistant, "account-backend",
947 page, "account-backend",
948 G_BINDING_SYNC_CREATE);
949
950 e_binding_bind_property (
951 assistant, "identity-source",
952 page, "identity-source",
953 G_BINDING_SYNC_CREATE);
954
955 e_binding_bind_property (
956 assistant, "transport-backend",
957 page, "transport-backend",
958 G_BINDING_SYNC_CREATE);
959
960 /*** Confirm Page ***/
961
962 page = e_mail_config_confirm_page_new ();
963 e_mail_config_assistant_add_page (assistant, page);
964
965 e_extensible_load_extensions (E_EXTENSIBLE (assistant));
966
967 npages = gtk_assistant_get_n_pages (GTK_ASSISTANT (assistant));
968 for (ii = 0; ii < npages; ii++) {
969 children = g_slist_prepend (children, gtk_assistant_get_nth_page (GTK_ASSISTANT (assistant), ii));
970 }
971
972 e_util_resize_window_for_screen (GTK_WINDOW (assistant), requisition.width, requisition.height, children);
973
974 g_slist_free (children);
975 }
976
977 static void
mail_config_assistant_remove(GtkContainer * container,GtkWidget * widget)978 mail_config_assistant_remove (GtkContainer *container,
979 GtkWidget *widget)
980 {
981 if (E_IS_MAIL_CONFIG_PAGE (widget))
982 g_signal_handlers_disconnect_by_func (
983 widget, mail_config_assistant_page_changed,
984 E_MAIL_CONFIG_ASSISTANT (container));
985
986 /* Chain up to parent's remove() method. */
987 GTK_CONTAINER_CLASS (e_mail_config_assistant_parent_class)->
988 remove (container, widget);
989 }
990
991 static void
mail_config_assistant_prepare(GtkAssistant * assistant,GtkWidget * page)992 mail_config_assistant_prepare (GtkAssistant *assistant,
993 GtkWidget *page)
994 {
995 EMailConfigAssistantPrivate *priv;
996 gboolean first_visit = FALSE;
997
998 priv = E_MAIL_CONFIG_ASSISTANT_GET_PRIVATE (assistant);
999
1000 /* Only setup defaults the first time a page is visited. */
1001 if (!g_hash_table_contains (priv->visited_pages, page)) {
1002 if (E_IS_MAIL_CONFIG_PAGE (page))
1003 e_mail_config_page_setup_defaults (
1004 E_MAIL_CONFIG_PAGE (page));
1005 g_hash_table_add (priv->visited_pages, page);
1006 first_visit = TRUE;
1007 }
1008
1009 /* Are we viewing autoconfiguration results? If so, temporarily
1010 * rename the back button to clarify that account details can be
1011 * revised. Otherwise reset the button to its original label. */
1012 if (priv->back_button != NULL) {
1013 gboolean auto_configure_results;
1014 const gchar *label;
1015
1016 auto_configure_results =
1017 E_IS_MAIL_CONFIG_SUMMARY_PAGE (page) &&
1018 priv->auto_configured && first_visit;
1019
1020 if (auto_configure_results)
1021 label = _("_Revise Details");
1022 else
1023 label = gettext (BACK_BUTTON_LABEL);
1024
1025 gtk_button_set_label (priv->back_button, label);
1026 }
1027
1028 if (E_IS_MAIL_CONFIG_LOOKUP_PAGE (page)) {
1029 ConfigLookupContext *context;
1030 ESource *source;
1031 ESourceRegistry *registry;
1032 ESourceMailIdentity *extension;
1033 ENamedParameters *params;
1034 const gchar *email_address;
1035 const gchar *extension_name;
1036
1037 registry = e_mail_session_get_registry (priv->session);
1038
1039 source = priv->identity_source;
1040 extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY;
1041 extension = e_source_get_extension (source, extension_name);
1042 email_address = e_source_mail_identity_get_address (extension);
1043
1044 context = config_lookup_context_new (assistant, registry, email_address);
1045
1046 g_signal_connect (context->config_lookup, "get-source",
1047 G_CALLBACK (mail_config_assistant_get_source_cb), assistant);
1048
1049 params = e_named_parameters_new ();
1050 e_named_parameters_set (params, E_CONFIG_LOOKUP_PARAM_EMAIL_ADDRESS, email_address);
1051
1052 e_config_lookup_run (context->config_lookup,
1053 params,
1054 context->cancellable,
1055 mail_config_assistant_config_lookup_run_cb,
1056 context);
1057
1058 e_named_parameters_free (params);
1059 }
1060
1061 if (!first_visit && E_IS_MAIL_CONFIG_IDENTITY_PAGE (page)) {
1062 ESource *source;
1063 ESourceMailIdentity *extension;
1064 const gchar *email_address;
1065 const gchar *extension_name;
1066
1067 source = priv->identity_source;
1068 extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY;
1069 extension = e_source_get_extension (source, extension_name);
1070 email_address = e_source_mail_identity_get_address (extension);
1071
1072 /* Set the value to an empty string when going back to the identity page,
1073 thus when moving away from it the source's display name is updated
1074 with the new address, in case it changed. Do not modify the display
1075 name when the user changed it. */
1076 if (g_strcmp0 (e_mail_config_summary_page_get_account_name (priv->summary_page), email_address) == 0)
1077 e_source_set_display_name (source, "");
1078 }
1079
1080 if (E_IS_MAIL_CONFIG_RECEIVING_PAGE (page)) {
1081 ESource *source;
1082 ESourceMailIdentity *extension;
1083 const gchar *email_address;
1084 const gchar *extension_name;
1085
1086 /* Use the email address from the Identity Page as
1087 * the initial display name, so in case we have to
1088 * query a remote mail server, the password prompt
1089 * will have a more meaningful description. */
1090
1091 source = priv->identity_source;
1092 extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY;
1093 extension = e_source_get_extension (source, extension_name);
1094 email_address = e_source_mail_identity_get_address (extension);
1095
1096 if (first_visit || g_strcmp0 (e_source_get_display_name (source), "") == 0)
1097 e_source_set_display_name (source, email_address);
1098 }
1099
1100 if (first_visit && (
1101 E_IS_MAIL_CONFIG_LOOKUP_PAGE (page) ||
1102 E_IS_MAIL_CONFIG_RECEIVING_PAGE (page)))
1103 e_mail_config_identity_page_set_show_autodiscover_check (
1104 E_MAIL_CONFIG_IDENTITY_PAGE (priv->identity_page), FALSE);
1105 }
1106
1107 static void
mail_config_assistant_close(GtkAssistant * assistant)1108 mail_config_assistant_close (GtkAssistant *assistant)
1109 {
1110 GdkCursor *gdk_cursor;
1111 GdkWindow *gdk_window;
1112
1113 /* Do not chain up. GtkAssistant does not implement this method. */
1114
1115 /* Make the cursor appear busy. */
1116 gdk_cursor = gdk_cursor_new (GDK_WATCH);
1117 gdk_window = gtk_widget_get_window (GTK_WIDGET (assistant));
1118 gdk_window_set_cursor (gdk_window, gdk_cursor);
1119 g_object_unref (gdk_cursor);
1120
1121 /* Prevent user interaction with window content. */
1122 gtk_widget_set_sensitive (GTK_WIDGET (assistant), FALSE);
1123
1124 /* XXX This operation is not cancellable. */
1125 e_mail_config_assistant_commit (
1126 E_MAIL_CONFIG_ASSISTANT (assistant),
1127 NULL, mail_config_assistant_close_cb, NULL);
1128 }
1129
1130 static void
mail_config_assistant_cancel(GtkAssistant * assistant)1131 mail_config_assistant_cancel (GtkAssistant *assistant)
1132 {
1133 /* Do not chain up. GtkAssistant does not implement this method. */
1134
1135 gtk_widget_destroy (GTK_WIDGET (assistant));
1136 }
1137
1138 static void
e_mail_config_assistant_class_init(EMailConfigAssistantClass * class)1139 e_mail_config_assistant_class_init (EMailConfigAssistantClass *class)
1140 {
1141 GObjectClass *object_class;
1142 GtkContainerClass *container_class;
1143 GtkAssistantClass *assistant_class;
1144
1145 g_type_class_add_private (class, sizeof (EMailConfigAssistantPrivate));
1146
1147 object_class = G_OBJECT_CLASS (class);
1148 object_class->set_property = mail_config_assistant_set_property;
1149 object_class->get_property = mail_config_assistant_get_property;
1150 object_class->dispose = mail_config_assistant_dispose;
1151 object_class->finalize = mail_config_assistant_finalize;
1152 object_class->constructed = mail_config_assistant_constructed;
1153
1154 container_class = GTK_CONTAINER_CLASS (class);
1155 container_class->remove = mail_config_assistant_remove;
1156
1157 assistant_class = GTK_ASSISTANT_CLASS (class);
1158 assistant_class->prepare = mail_config_assistant_prepare;
1159 assistant_class->close = mail_config_assistant_close;
1160 assistant_class->cancel = mail_config_assistant_cancel;
1161
1162 g_object_class_install_property (
1163 object_class,
1164 PROP_ACCOUNT_BACKEND,
1165 g_param_spec_object (
1166 "account-backend",
1167 "Account Backend",
1168 "Active mail account service backend",
1169 E_TYPE_MAIL_CONFIG_SERVICE_BACKEND,
1170 G_PARAM_READABLE |
1171 G_PARAM_STATIC_STRINGS));
1172
1173 g_object_class_install_property (
1174 object_class,
1175 PROP_ACCOUNT_SOURCE,
1176 g_param_spec_object (
1177 "account-source",
1178 "Account Source",
1179 "Mail account source being edited",
1180 E_TYPE_SOURCE,
1181 G_PARAM_READABLE |
1182 G_PARAM_STATIC_STRINGS));
1183
1184 g_object_class_install_property (
1185 object_class,
1186 PROP_IDENTITY_SOURCE,
1187 g_param_spec_object (
1188 "identity-source",
1189 "Identity Source",
1190 "Mail identity source being edited",
1191 E_TYPE_SOURCE,
1192 G_PARAM_READABLE |
1193 G_PARAM_STATIC_STRINGS));
1194
1195 g_object_class_install_property (
1196 object_class,
1197 PROP_SESSION,
1198 g_param_spec_object (
1199 "session",
1200 "Session",
1201 "Mail session",
1202 E_TYPE_MAIL_SESSION,
1203 G_PARAM_READWRITE |
1204 G_PARAM_CONSTRUCT_ONLY |
1205 G_PARAM_STATIC_STRINGS));
1206
1207 g_object_class_install_property (
1208 object_class,
1209 PROP_TRANSPORT_BACKEND,
1210 g_param_spec_object (
1211 "transport-backend",
1212 "Transport Backend",
1213 "Active mail transport service backend",
1214 E_TYPE_MAIL_CONFIG_SERVICE_BACKEND,
1215 G_PARAM_READABLE |
1216 G_PARAM_STATIC_STRINGS));
1217
1218 g_object_class_install_property (
1219 object_class,
1220 PROP_TRANSPORT_SOURCE,
1221 g_param_spec_object (
1222 "transport-source",
1223 "Transport Source",
1224 "Mail transport source being edited",
1225 E_TYPE_SOURCE,
1226 G_PARAM_READABLE |
1227 G_PARAM_STATIC_STRINGS));
1228
1229 /**
1230 * EMailConfigAssistant::new-source:
1231 * @uid: an #ESource UID which had been created
1232 *
1233 * Emitted to notify about the assistant finishing an account #ESource.
1234 *
1235 * Since: 3.28
1236 **/
1237 signals[NEW_SOURCE] = g_signal_new (
1238 "new-source",
1239 G_TYPE_FROM_CLASS (class),
1240 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1241 G_STRUCT_OFFSET (EMailConfigAssistantClass, new_source),
1242 NULL, NULL,
1243 NULL,
1244 G_TYPE_NONE, 1, G_TYPE_STRING);
1245 }
1246
1247 static void
e_mail_config_assistant_init(EMailConfigAssistant * assistant)1248 e_mail_config_assistant_init (EMailConfigAssistant *assistant)
1249 {
1250 GObject *action_area;
1251 GtkBuilder *builder;
1252
1253 builder = gtk_builder_new ();
1254 action_area = gtk_buildable_get_internal_child (
1255 GTK_BUILDABLE (assistant), builder, "action_area");
1256 if (action_area)
1257 gtk_container_set_border_width (GTK_CONTAINER (action_area), 12);
1258 g_object_unref (builder);
1259
1260 assistant->priv = E_MAIL_CONFIG_ASSISTANT_GET_PRIVATE (assistant);
1261
1262 assistant->priv->account_sources =
1263 g_ptr_array_new_with_free_func (
1264 (GDestroyNotify) g_object_unref);
1265
1266 assistant->priv->transport_sources =
1267 g_ptr_array_new_with_free_func (
1268 (GDestroyNotify) g_object_unref);
1269
1270 assistant->priv->visited_pages = g_hash_table_new (NULL, NULL);
1271 }
1272
1273 GtkWidget *
e_mail_config_assistant_new(EMailSession * session)1274 e_mail_config_assistant_new (EMailSession *session)
1275 {
1276 g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL);
1277
1278 return g_object_new (
1279 E_TYPE_MAIL_CONFIG_ASSISTANT,
1280 "session", session, NULL);
1281 }
1282
1283 EMailSession *
e_mail_config_assistant_get_session(EMailConfigAssistant * assistant)1284 e_mail_config_assistant_get_session (EMailConfigAssistant *assistant)
1285 {
1286 g_return_val_if_fail (E_IS_MAIL_CONFIG_ASSISTANT (assistant), NULL);
1287
1288 return assistant->priv->session;
1289 }
1290
1291 EMailConfigServiceBackend *
e_mail_config_assistant_get_account_backend(EMailConfigAssistant * assistant)1292 e_mail_config_assistant_get_account_backend (EMailConfigAssistant *assistant)
1293 {
1294 EMailConfigServicePage *page;
1295
1296 g_return_val_if_fail (E_IS_MAIL_CONFIG_ASSISTANT (assistant), NULL);
1297
1298 page = assistant->priv->receiving_page;
1299
1300 return e_mail_config_service_page_get_active_backend (page);
1301 }
1302
1303 ESource *
e_mail_config_assistant_get_account_source(EMailConfigAssistant * assistant)1304 e_mail_config_assistant_get_account_source (EMailConfigAssistant *assistant)
1305 {
1306 EMailConfigServiceBackend *backend;
1307 ESource *source = NULL;
1308
1309 g_return_val_if_fail (E_IS_MAIL_CONFIG_ASSISTANT (assistant), NULL);
1310
1311 backend = e_mail_config_assistant_get_account_backend (assistant);
1312
1313 if (backend != NULL)
1314 source = e_mail_config_service_backend_get_source (backend);
1315
1316 return source;
1317 }
1318
1319 ESource *
e_mail_config_assistant_get_identity_source(EMailConfigAssistant * assistant)1320 e_mail_config_assistant_get_identity_source (EMailConfigAssistant *assistant)
1321 {
1322 g_return_val_if_fail (E_IS_MAIL_CONFIG_ASSISTANT (assistant), NULL);
1323
1324 return assistant->priv->identity_source;
1325 }
1326
1327 EMailConfigServiceBackend *
e_mail_config_assistant_get_transport_backend(EMailConfigAssistant * assistant)1328 e_mail_config_assistant_get_transport_backend (EMailConfigAssistant *assistant)
1329 {
1330 EMailConfigServicePage *page;
1331
1332 g_return_val_if_fail (E_IS_MAIL_CONFIG_ASSISTANT (assistant), NULL);
1333
1334 page = assistant->priv->sending_page;
1335
1336 return e_mail_config_service_page_get_active_backend (page);
1337 }
1338
1339 ESource *
e_mail_config_assistant_get_transport_source(EMailConfigAssistant * assistant)1340 e_mail_config_assistant_get_transport_source (EMailConfigAssistant *assistant)
1341 {
1342 EMailConfigServiceBackend *backend;
1343 ESource *source = NULL;
1344
1345 g_return_val_if_fail (E_IS_MAIL_CONFIG_ASSISTANT (assistant), NULL);
1346
1347 backend = e_mail_config_assistant_get_transport_backend (assistant);
1348
1349 if (backend != NULL)
1350 source = e_mail_config_service_backend_get_source (backend);
1351
1352 return source;
1353 }
1354
1355 void
e_mail_config_assistant_add_page(EMailConfigAssistant * assistant,EMailConfigPage * page)1356 e_mail_config_assistant_add_page (EMailConfigAssistant *assistant,
1357 EMailConfigPage *page)
1358 {
1359 EMailConfigPageInterface *page_interface;
1360 GtkAssistantPageType page_type;
1361 GtkWidget *page_widget;
1362 gint n_pages, position;
1363 const gchar *page_title;
1364 gboolean complete;
1365
1366 g_return_if_fail (E_IS_MAIL_CONFIG_ASSISTANT (assistant));
1367 g_return_if_fail (E_IS_MAIL_CONFIG_PAGE (page));
1368
1369 page_widget = GTK_WIDGET (page);
1370 page_interface = E_MAIL_CONFIG_PAGE_GET_INTERFACE (page);
1371 page_type = page_interface->page_type;
1372 page_title = page_interface->title;
1373
1374 /* Determine the position to insert the page. */
1375 n_pages = gtk_assistant_get_n_pages (GTK_ASSISTANT (assistant));
1376 for (position = 0; position < n_pages; position++) {
1377 GtkWidget *nth_page;
1378
1379 nth_page = gtk_assistant_get_nth_page (
1380 GTK_ASSISTANT (assistant), position);
1381 if (e_mail_config_page_compare (page_widget, nth_page) < 0)
1382 break;
1383 }
1384
1385 gtk_widget_show (page_widget);
1386
1387 /* Some pages can be clicked through unchanged. */
1388 complete = e_mail_config_page_check_complete (page);
1389
1390 gtk_assistant_insert_page (
1391 GTK_ASSISTANT (assistant), page_widget, position);
1392 gtk_assistant_set_page_type (
1393 GTK_ASSISTANT (assistant), page_widget, page_type);
1394 gtk_assistant_set_page_title (
1395 GTK_ASSISTANT (assistant), page_widget, page_title);
1396 gtk_assistant_set_page_complete (
1397 GTK_ASSISTANT (assistant), page_widget, complete);
1398
1399 /* XXX GtkAssistant has no equivalent to GtkNotebook's
1400 * "page-added" and "page-removed" signals. Fortunately
1401 * removing a page does trigger GtkContainer::remove, so
1402 * we can override that method and disconnect our signal
1403 * handler before chaining up. But I don't see any way
1404 * for a subclass to intercept GtkAssistant pages being
1405 * added, so we have to connect our signal handler here.
1406 * Not really an issue, I'm just being pedantic. */
1407
1408 g_signal_connect (
1409 page, "changed",
1410 G_CALLBACK (mail_config_assistant_page_changed),
1411 assistant);
1412 }
1413
1414 /********************* e_mail_config_assistant_commit() **********************/
1415
1416 static void
mail_config_assistant_commit_cb(GObject * object,GAsyncResult * result,gpointer user_data)1417 mail_config_assistant_commit_cb (GObject *object,
1418 GAsyncResult *result,
1419 gpointer user_data)
1420 {
1421 GSimpleAsyncResult *simple;
1422 GError *error = NULL;
1423
1424 simple = G_SIMPLE_ASYNC_RESULT (user_data);
1425
1426 e_source_registry_create_sources_finish (
1427 E_SOURCE_REGISTRY (object), result, &error);
1428
1429 if (error != NULL)
1430 g_simple_async_result_take_error (simple, error);
1431
1432 g_simple_async_result_complete (simple);
1433
1434 g_object_unref (simple);
1435 }
1436
1437 void
e_mail_config_assistant_commit(EMailConfigAssistant * assistant,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1438 e_mail_config_assistant_commit (EMailConfigAssistant *assistant,
1439 GCancellable *cancellable,
1440 GAsyncReadyCallback callback,
1441 gpointer user_data)
1442 {
1443 EMailConfigServiceBackend *backend;
1444 GSimpleAsyncResult *simple;
1445 ESourceRegistry *registry;
1446 EMailSession *session;
1447 ESource *source;
1448 GQueue *queue;
1449 gint n_pages, ii;
1450
1451 g_return_if_fail (E_IS_MAIL_CONFIG_ASSISTANT (assistant));
1452
1453 session = e_mail_config_assistant_get_session (assistant);
1454 registry = e_mail_session_get_registry (session);
1455
1456 queue = g_queue_new ();
1457
1458 /* Queue the collection data source if one is defined. */
1459 backend = e_mail_config_assistant_get_account_backend (assistant);
1460 source = e_mail_config_service_backend_get_collection (backend);
1461 if (source != NULL)
1462 g_queue_push_tail (queue, g_object_ref (source));
1463
1464 /* Queue the mail-related data sources for the account. */
1465 source = e_mail_config_assistant_get_account_source (assistant);
1466 if (source != NULL)
1467 g_queue_push_tail (queue, g_object_ref (source));
1468 source = e_mail_config_assistant_get_identity_source (assistant);
1469 if (source != NULL)
1470 g_queue_push_tail (queue, g_object_ref (source));
1471 source = e_mail_config_assistant_get_transport_source (assistant);
1472 if (source != NULL)
1473 g_queue_push_tail (queue, g_object_ref (source));
1474
1475 n_pages = gtk_assistant_get_n_pages (GTK_ASSISTANT (assistant));
1476
1477 /* Tell all EMailConfigPages to commit their UI state to their
1478 * scratch ESources and push any additional data sources on to
1479 * the given source queue, such as calendars or address books
1480 * to be bundled with the mail account. */
1481 for (ii = 0; ii < n_pages; ii++) {
1482 GtkWidget *widget;
1483
1484 widget = gtk_assistant_get_nth_page (
1485 GTK_ASSISTANT (assistant), ii);
1486
1487 if (E_IS_MAIL_CONFIG_PAGE (widget)) {
1488 EMailConfigPage *page;
1489 page = E_MAIL_CONFIG_PAGE (widget);
1490 e_mail_config_page_commit_changes (page, queue);
1491 }
1492 }
1493
1494 simple = g_simple_async_result_new (
1495 G_OBJECT (assistant), callback, user_data,
1496 e_mail_config_assistant_commit);
1497
1498 e_source_registry_create_sources (
1499 registry, g_queue_peek_head_link (queue),
1500 cancellable, mail_config_assistant_commit_cb, simple);
1501
1502 g_queue_free_full (queue, (GDestroyNotify) g_object_unref);
1503 }
1504
1505 gboolean
e_mail_config_assistant_commit_finish(EMailConfigAssistant * assistant,GAsyncResult * result,GError ** error)1506 e_mail_config_assistant_commit_finish (EMailConfigAssistant *assistant,
1507 GAsyncResult *result,
1508 GError **error)
1509 {
1510 GSimpleAsyncResult *simple;
1511 gboolean success;
1512
1513 g_return_val_if_fail (
1514 g_simple_async_result_is_valid (
1515 result, G_OBJECT (assistant),
1516 e_mail_config_assistant_commit), FALSE);
1517
1518 simple = G_SIMPLE_ASYNC_RESULT (result);
1519
1520 /* Assume success unless a GError is set. */
1521 success = !g_simple_async_result_propagate_error (simple, error);
1522
1523 if (success) {
1524 ESource *source;
1525
1526 source = e_mail_config_assistant_get_account_source (assistant);
1527 if (source)
1528 g_signal_emit (assistant, signals[NEW_SOURCE], 0, e_source_get_uid (source));
1529 }
1530
1531 return success;
1532 }
1533
1534