1 /*
2 * e-mail-config-service-page.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 <camel/camel.h>
23 #include <libebackend/libebackend.h>
24
25 #include "e-mail-config-page.h"
26 #include "e-mail-config-service-notebook.h"
27
28 #include "e-mail-config-service-page.h"
29
30 #define E_MAIL_CONFIG_SERVICE_PAGE_GET_PRIVATE(obj) \
31 (G_TYPE_INSTANCE_GET_PRIVATE \
32 ((obj), E_TYPE_MAIL_CONFIG_SERVICE_PAGE, EMailConfigServicePagePrivate))
33
34 typedef struct _Candidate Candidate;
35
36 struct _EMailConfigServicePagePrivate {
37 ESourceRegistry *registry;
38 EMailConfigServiceBackend *active_backend;
39 gchar *email_address;
40
41 GHashTable *backends;
42 GPtrArray *candidates;
43
44 /* Hidden candidates are not listed in the
45 * combo box but can still be accessed through
46 * e_mail_config_service_page_lookup_backend(). */
47 GPtrArray *hidden_candidates;
48
49 GtkWidget *type_combo;
50 GtkWidget *type_label;
51 GtkWidget *desc_label;
52 GtkWidget *notebook;
53
54 /* Combo box list store */
55 GtkListStore *list_store;
56 };
57
58 struct _Candidate {
59 gchar *name;
60 EMailConfigServiceBackend *backend;
61
62 CamelProvider *provider;
63 CamelSettings *settings;
64 gulong settings_notify_handler_id;
65
66 GtkWidget *widget;
67 };
68
69 enum {
70 PROP_0,
71 PROP_ACTIVE_BACKEND,
72 PROP_EMAIL_ADDRESS,
73 PROP_REGISTRY
74 };
75
76 enum {
77 COLUMN_BACKEND_NAME,
78 COLUMN_DISPLAY_NAME,
79 COLUMN_SELECTABLE,
80 NUM_COLUMNS
81 };
82
83 /* Forward Declarations */
84 static void e_mail_config_service_page_interface_init
85 (EMailConfigPageInterface *iface);
86
G_DEFINE_ABSTRACT_TYPE_WITH_CODE(EMailConfigServicePage,e_mail_config_service_page,E_TYPE_MAIL_CONFIG_ACTIVITY_PAGE,G_IMPLEMENT_INTERFACE (E_TYPE_EXTENSIBLE,NULL)G_IMPLEMENT_INTERFACE (E_TYPE_MAIL_CONFIG_PAGE,e_mail_config_service_page_interface_init))87 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (
88 EMailConfigServicePage,
89 e_mail_config_service_page,
90 E_TYPE_MAIL_CONFIG_ACTIVITY_PAGE,
91 G_IMPLEMENT_INTERFACE (
92 E_TYPE_EXTENSIBLE, NULL)
93 G_IMPLEMENT_INTERFACE (
94 E_TYPE_MAIL_CONFIG_PAGE,
95 e_mail_config_service_page_interface_init))
96
97 static void
98 mail_config_service_page_settings_notify_cb (CamelSettings *settings,
99 GParamSpec *pspec,
100 EMailConfigPage *page)
101 {
102 e_mail_config_page_changed (page);
103 }
104
105 static Candidate *
mail_config_service_page_new_candidate(EMailConfigServicePage * page,ESource * scratch_source,ESource * opt_collection)106 mail_config_service_page_new_candidate (EMailConfigServicePage *page,
107 ESource *scratch_source,
108 ESource *opt_collection)
109 {
110 Candidate *candidate;
111 CamelProvider *provider;
112 CamelSettings *settings;
113 ESourceBackend *extension;
114 EMailConfigServiceBackend *backend;
115 EMailConfigServicePageClass *class;
116 const gchar *extension_name;
117 const gchar *backend_name;
118 gulong handler_id;
119
120 /* Get the backend name for this scratch source. */
121 class = E_MAIL_CONFIG_SERVICE_PAGE_GET_CLASS (page);
122 g_return_val_if_fail (class != NULL, NULL);
123
124 extension_name = class->extension_name;
125 extension = e_source_get_extension (scratch_source, extension_name);
126 backend_name = e_source_backend_get_backend_name (extension);
127 g_return_val_if_fail (backend_name != NULL, NULL);
128
129 /* Make sure we have a corresponding EMailConfigServicePageBackend. */
130 backend = g_hash_table_lookup (page->priv->backends, backend_name);
131 g_return_val_if_fail (E_IS_MAIL_CONFIG_SERVICE_BACKEND (backend), NULL);
132
133 /* Make sure we have a corresponding CamelProvider. */
134 provider = e_mail_config_service_backend_get_provider (backend);
135 g_return_val_if_fail (provider != NULL, NULL);
136
137 /* Need to give the backend a scratch source and (if provided) a
138 * scratch collection source before we can extract a CamelSettings
139 * instance, since the CamelSettings instance comes from either the
140 * scratch collection source or else the scratch source. */
141 e_mail_config_service_backend_set_source (backend, scratch_source);
142 if (opt_collection != NULL)
143 e_mail_config_service_backend_set_collection (
144 backend, opt_collection);
145
146 /* Backend may have created its own collection source,
147 * so we need to get it from the backend before binding. */
148 opt_collection = e_mail_config_service_backend_get_collection (backend);
149
150 /* Keep display names synchronized. */
151 if (opt_collection != NULL)
152 e_binding_bind_property (
153 scratch_source, "display-name",
154 opt_collection, "display-name",
155 G_BINDING_BIDIRECTIONAL |
156 G_BINDING_SYNC_CREATE);
157
158 /* Make sure we have a corresponding CamelSettings. */
159 settings = e_mail_config_service_backend_get_settings (backend);
160 g_return_val_if_fail (CAMEL_IS_SETTINGS (settings), NULL);
161
162 candidate = g_slice_new0 (Candidate);
163 candidate->name = g_strdup (backend_name);
164 candidate->backend = g_object_ref (backend);
165 candidate->provider = provider;
166 candidate->settings = g_object_ref (settings);
167
168 /* Remove the backend so it can't be reused. If another scratch
169 * source with the same backend name gets added, the hash table
170 * lookup will fail and emit a runtime warning, which we want. */
171 g_hash_table_remove (page->priv->backends, backend_name);
172
173 /* Emit "changed" signals for subsequent CamelSettings changes. */
174 handler_id = g_signal_connect (
175 candidate->settings, "notify",
176 G_CALLBACK (mail_config_service_page_settings_notify_cb), page);
177 candidate->settings_notify_handler_id = handler_id;
178
179 return candidate;
180 }
181
182 static void
mail_config_service_page_free_candidate(Candidate * candidate)183 mail_config_service_page_free_candidate (Candidate *candidate)
184 {
185 g_free (candidate->name);
186
187 if (candidate->backend != NULL)
188 g_object_unref (candidate->backend);
189
190 if (candidate->settings != NULL) {
191 g_signal_handler_disconnect (
192 candidate->settings,
193 candidate->settings_notify_handler_id);
194 g_object_unref (candidate->settings);
195 }
196
197 if (candidate->widget != NULL)
198 g_object_unref (candidate->widget);
199
200 g_slice_free (Candidate, candidate);
201 }
202
203 static void
mail_config_service_page_init_backends(EMailConfigServicePage * page)204 mail_config_service_page_init_backends (EMailConfigServicePage *page)
205 {
206 GList *list, *iter;
207
208 page->priv->backends = g_hash_table_new_full (
209 (GHashFunc) g_str_hash,
210 (GEqualFunc) g_str_equal,
211 (GDestroyNotify) g_free,
212 (GDestroyNotify) g_object_unref);
213
214 e_extensible_load_extensions (E_EXTENSIBLE (page));
215
216 list = e_extensible_list_extensions (
217 E_EXTENSIBLE (page), E_TYPE_MAIL_CONFIG_SERVICE_BACKEND);
218
219 for (iter = list; iter != NULL; iter = g_list_next (iter)) {
220 EMailConfigServiceBackend *backend;
221 EMailConfigServiceBackendClass *class;
222
223 backend = E_MAIL_CONFIG_SERVICE_BACKEND (iter->data);
224 class = E_MAIL_CONFIG_SERVICE_BACKEND_GET_CLASS (backend);
225
226 if (class->backend_name != NULL)
227 g_hash_table_insert (
228 page->priv->backends,
229 g_strdup (class->backend_name),
230 g_object_ref (backend));
231 }
232
233 g_list_free (list);
234 }
235
236 static gboolean
mail_config_service_page_backend_to_id(GBinding * binding,const GValue * source_value,GValue * target_value,gpointer user_data)237 mail_config_service_page_backend_to_id (GBinding *binding,
238 const GValue *source_value,
239 GValue *target_value,
240 gpointer user_data)
241 {
242 EMailConfigServiceBackend *backend;
243 EMailConfigServiceBackendClass *backend_class;
244
245 backend = g_value_get_object (source_value);
246 g_return_val_if_fail (backend != NULL, FALSE);
247
248 backend_class = E_MAIL_CONFIG_SERVICE_BACKEND_GET_CLASS (backend);
249 g_value_set_string (target_value, backend_class->backend_name);
250
251 return TRUE;
252 }
253
254 static gboolean
mail_config_service_page_id_to_backend(GBinding * binding,const GValue * source_value,GValue * target_value,gpointer user_data)255 mail_config_service_page_id_to_backend (GBinding *binding,
256 const GValue *source_value,
257 GValue *target_value,
258 gpointer user_data)
259 {
260 EMailConfigServiceBackend *backend = NULL;
261 GObject *source_object;
262 const gchar *backend_name;
263
264 source_object = g_binding_get_source (binding);
265 backend_name = g_value_get_string (source_value);
266
267 if (backend_name != NULL)
268 backend = e_mail_config_service_page_lookup_backend (
269 E_MAIL_CONFIG_SERVICE_PAGE (source_object),
270 backend_name);
271
272 g_value_set_object (target_value, backend);
273
274 return TRUE;
275 }
276
277 static gboolean
mail_config_service_page_backend_name_to_description(GBinding * binding,const GValue * source_value,GValue * target_value,gpointer user_data)278 mail_config_service_page_backend_name_to_description (GBinding *binding,
279 const GValue *source_value,
280 GValue *target_value,
281 gpointer user_data)
282 {
283 CamelProvider *provider;
284 const gchar *description;
285 const gchar *backend_name;
286
287 backend_name = g_value_get_string (source_value);
288
289 /* XXX Silly special case. */
290 if (backend_name == NULL)
291 backend_name = "none";
292
293 provider = camel_provider_get (backend_name, NULL);
294
295 if (provider != NULL && provider->description != NULL)
296 description = g_dgettext (
297 provider->translation_domain,
298 provider->description);
299 else
300 description = "";
301
302 g_value_set_string (target_value, description);
303
304 return TRUE;
305 }
306
307 static void
mail_config_service_page_set_registry(EMailConfigServicePage * page,ESourceRegistry * registry)308 mail_config_service_page_set_registry (EMailConfigServicePage *page,
309 ESourceRegistry *registry)
310 {
311 g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
312 g_return_if_fail (page->priv->registry == NULL);
313
314 page->priv->registry = g_object_ref (registry);
315 }
316
317 static void
mail_config_service_page_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)318 mail_config_service_page_set_property (GObject *object,
319 guint property_id,
320 const GValue *value,
321 GParamSpec *pspec)
322 {
323 switch (property_id) {
324 case PROP_ACTIVE_BACKEND:
325 e_mail_config_service_page_set_active_backend (
326 E_MAIL_CONFIG_SERVICE_PAGE (object),
327 g_value_get_object (value));
328 return;
329
330 case PROP_EMAIL_ADDRESS:
331 e_mail_config_service_page_set_email_address (
332 E_MAIL_CONFIG_SERVICE_PAGE (object),
333 g_value_get_string (value));
334 return;
335
336 case PROP_REGISTRY:
337 mail_config_service_page_set_registry (
338 E_MAIL_CONFIG_SERVICE_PAGE (object),
339 g_value_get_object (value));
340 return;
341 }
342
343 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
344 }
345
346 static void
mail_config_service_page_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)347 mail_config_service_page_get_property (GObject *object,
348 guint property_id,
349 GValue *value,
350 GParamSpec *pspec)
351 {
352 switch (property_id) {
353 case PROP_ACTIVE_BACKEND:
354 g_value_set_object (
355 value,
356 e_mail_config_service_page_get_active_backend (
357 E_MAIL_CONFIG_SERVICE_PAGE (object)));
358 return;
359
360 case PROP_EMAIL_ADDRESS:
361 g_value_set_string (
362 value,
363 e_mail_config_service_page_get_email_address (
364 E_MAIL_CONFIG_SERVICE_PAGE (object)));
365 return;
366
367 case PROP_REGISTRY:
368 g_value_set_object (
369 value,
370 e_mail_config_service_page_get_registry (
371 E_MAIL_CONFIG_SERVICE_PAGE (object)));
372 return;
373 }
374
375 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
376 }
377
378 static void
mail_config_service_page_dispose(GObject * object)379 mail_config_service_page_dispose (GObject *object)
380 {
381 EMailConfigServicePagePrivate *priv;
382
383 priv = E_MAIL_CONFIG_SERVICE_PAGE_GET_PRIVATE (object);
384 g_clear_object (&priv->registry);
385 g_clear_object (&priv->active_backend);
386
387 g_hash_table_remove_all (priv->backends);
388 g_ptr_array_set_size (priv->candidates, 0);
389 g_ptr_array_set_size (priv->hidden_candidates, 0);
390
391 g_clear_object (&priv->list_store);
392
393 /* Chain up to parent's dispose() method. */
394 G_OBJECT_CLASS (e_mail_config_service_page_parent_class)->dispose (object);
395 }
396
397 static void
mail_config_service_page_finalize(GObject * object)398 mail_config_service_page_finalize (GObject *object)
399 {
400 EMailConfigServicePagePrivate *priv;
401
402 priv = E_MAIL_CONFIG_SERVICE_PAGE_GET_PRIVATE (object);
403
404 g_free (priv->email_address);
405 g_hash_table_destroy (priv->backends);
406 g_ptr_array_free (priv->candidates, TRUE);
407 g_ptr_array_free (priv->hidden_candidates, TRUE);
408
409 /* Chain up to parent's finalize() method. */
410 G_OBJECT_CLASS (e_mail_config_service_page_parent_class)->finalize (object);
411 }
412
413 static void
mail_config_service_page_constructed(GObject * object)414 mail_config_service_page_constructed (GObject *object)
415 {
416 EMailConfigServicePage *page;
417 GPtrArray *candidates;
418 GPtrArray *hidden_candidates;
419 PangoAttribute *attr;
420 PangoAttrList *attr_list;
421 GtkLabel *label;
422 GtkWidget *widget;
423 GtkWidget *container;
424 GtkWidget *main_box;
425 GtkTreeModel *tree_model;
426 GtkCellRenderer *renderer;
427
428 page = E_MAIL_CONFIG_SERVICE_PAGE (object);
429
430 /* Chain up to parent's constructed() method. */
431 G_OBJECT_CLASS (e_mail_config_service_page_parent_class)->constructed (object);
432
433 /* The candidates array holds scratch ESources, one for each
434 * item in the "type" combo box. Scratch ESources are never
435 * added to the registry, so backend extensions can make any
436 * changes they want to them. Whichever scratch ESource is
437 * "active" (selected in the "type" combo box) when the user
438 * clicks OK wins and is written to disk. The others are
439 * discarded. */
440 candidates = g_ptr_array_new_with_free_func (
441 (GDestroyNotify) mail_config_service_page_free_candidate);
442
443 /* Hidden candidates are not listed in the "type" combo box
444 * but their scratch ESource can still be "active". This is
445 * a hack to accommodate groupware backends. Usually when a
446 * hidden candidate is active the service page will not be
447 * visible anyway. */
448 hidden_candidates = g_ptr_array_new_with_free_func (
449 (GDestroyNotify) mail_config_service_page_free_candidate);
450
451 main_box = e_mail_config_activity_page_get_internal_box (E_MAIL_CONFIG_ACTIVITY_PAGE (page));
452 gtk_box_set_spacing (GTK_BOX (main_box), 12);
453
454 page->priv->candidates = candidates;
455 page->priv->hidden_candidates = hidden_candidates;
456
457 /* Build a filtered model for the combo box, where row
458 * visibility is determined by the "selectable" column. */
459
460 page->priv->list_store = gtk_list_store_new (
461 NUM_COLUMNS,
462 G_TYPE_STRING, /* COLUMN_BACKEND_NAME */
463 G_TYPE_STRING, /* COLUMN_DISPLAY_NAME */
464 G_TYPE_BOOLEAN); /* COLUMN_SELECTABLE */
465
466 tree_model = gtk_tree_model_filter_new (
467 GTK_TREE_MODEL (page->priv->list_store), NULL);
468
469 gtk_tree_model_filter_set_visible_column (
470 GTK_TREE_MODEL_FILTER (tree_model), COLUMN_SELECTABLE);
471
472 /* Either the combo box or the label is shown, never both.
473 * But we create both widgets and keep them both up-to-date
474 * regardless just because it makes the logic simpler. */
475
476 container = GTK_WIDGET (main_box);
477
478 widget = gtk_grid_new ();
479 gtk_grid_set_row_spacing (GTK_GRID (widget), 12);
480 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
481 gtk_widget_show (widget);
482
483 container = widget;
484
485 attr_list = pango_attr_list_new ();
486
487 attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
488 pango_attr_list_insert (attr_list, attr);
489
490 widget = gtk_label_new_with_mnemonic (_("Server _Type:"));
491 gtk_widget_set_margin_right (widget, 12);
492 gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5);
493 gtk_grid_attach (GTK_GRID (container), widget, 0, 0, 1, 1);
494 gtk_widget_show (widget);
495
496 label = GTK_LABEL (widget);
497
498 widget = gtk_combo_box_new_with_model (tree_model);
499 gtk_widget_set_hexpand (widget, TRUE);
500 gtk_label_set_mnemonic_widget (label, widget);
501 gtk_combo_box_set_id_column (
502 GTK_COMBO_BOX (widget), COLUMN_BACKEND_NAME);
503 gtk_grid_attach (GTK_GRID (container), widget, 1, 0, 1, 1);
504 page->priv->type_combo = widget; /* not referenced */
505 gtk_widget_show (widget);
506
507 renderer = gtk_cell_renderer_text_new ();
508 gtk_cell_layout_pack_start (
509 GTK_CELL_LAYOUT (widget), renderer, TRUE);
510 gtk_cell_layout_add_attribute (
511 GTK_CELL_LAYOUT (widget), renderer,
512 "text", COLUMN_DISPLAY_NAME);
513
514 widget = gtk_label_new (NULL);
515 gtk_widget_set_hexpand (widget, TRUE);
516 gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
517 gtk_label_set_attributes (GTK_LABEL (widget), attr_list);
518 gtk_grid_attach (GTK_GRID (container), widget, 2, 0, 1, 1);
519 page->priv->type_label = widget; /* not referenced */
520 gtk_widget_show (widget);
521
522 widget = gtk_label_new (_("Description:"));
523 gtk_widget_set_margin_right (widget, 12);
524 gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.0);
525 gtk_grid_attach (GTK_GRID (container), widget, 0, 1, 1, 1);
526 gtk_widget_show (widget);
527
528 widget = gtk_label_new (NULL);
529 gtk_label_set_line_wrap (GTK_LABEL (widget), TRUE);
530 gtk_label_set_width_chars (GTK_LABEL (widget), 20);
531 gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
532 gtk_grid_attach (GTK_GRID (container), widget, 1, 1, 2, 1);
533 page->priv->desc_label = widget; /* not referenced */
534 gtk_widget_show (widget);
535
536 pango_attr_list_unref (attr_list);
537
538 container = GTK_WIDGET (main_box);
539
540 widget = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
541 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
542 gtk_widget_show (widget);
543
544 widget = e_mail_config_service_notebook_new ();
545 gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
546 page->priv->notebook = widget; /* not referenced */
547 gtk_widget_show (widget);
548
549 /* Keep the notebook's active page number synchronized with our
550 * own "active-backend" property. Avoid G_BINDING_SYNC_CREATE
551 * since we haven't added any notebook pages. */
552 e_binding_bind_property (
553 page, "active-backend",
554 page->priv->notebook, "active-backend",
555 G_BINDING_BIDIRECTIONAL);
556
557 /* Keep the combo box's active row number synchronized with our
558 * own "active-backend" property. Avoid G_BINDING_SYNC_CREATE
559 * since we haven't added any combo box rows. */
560 e_binding_bind_property_full (
561 page, "active-backend",
562 page->priv->type_combo, "active-id",
563 G_BINDING_BIDIRECTIONAL,
564 mail_config_service_page_backend_to_id,
565 mail_config_service_page_id_to_backend,
566 NULL, (GDestroyNotify) NULL);
567
568 /* This keeps the description field up-to-date. */
569 e_binding_bind_property_full (
570 page->priv->type_combo, "active-id",
571 page->priv->desc_label, "label",
572 G_BINDING_DEFAULT,
573 mail_config_service_page_backend_name_to_description,
574 NULL,
575 NULL, (GDestroyNotify) NULL);
576
577 /* For the "Server Type", either the combo
578 * box or the label is visible, never both. */
579 e_binding_bind_property (
580 page->priv->type_combo, "visible",
581 page->priv->type_label, "visible",
582 G_BINDING_SYNC_CREATE |
583 G_BINDING_BIDIRECTIONAL |
584 G_BINDING_INVERT_BOOLEAN);
585
586 g_signal_connect_swapped (
587 page->priv->type_combo, "changed",
588 G_CALLBACK (e_mail_config_page_changed), page);
589
590 g_object_unref (tree_model);
591
592 e_mail_config_page_set_content (E_MAIL_CONFIG_PAGE (page), main_box);
593
594 mail_config_service_page_init_backends (page);
595 }
596
597 static void
mail_config_service_page_setup_defaults(EMailConfigPage * page)598 mail_config_service_page_setup_defaults (EMailConfigPage *page)
599 {
600 EMailConfigServicePageClass *class;
601 EMailConfigServicePagePrivate *priv;
602 guint ii;
603
604 class = E_MAIL_CONFIG_SERVICE_PAGE_GET_CLASS (page);
605 g_return_if_fail (class != NULL);
606
607 priv = E_MAIL_CONFIG_SERVICE_PAGE_GET_PRIVATE (page);
608
609 for (ii = 0; ii < priv->candidates->len; ii++) {
610 Candidate *candidate;
611
612 candidate = priv->candidates->pdata[ii];
613 g_return_if_fail (candidate != NULL);
614
615 e_mail_config_service_backend_setup_defaults (
616 candidate->backend);
617 }
618
619 /* XXX Not sure if we need to call setup_defaults() for
620 * hidden candidates. Hold off until a need arises. */
621
622 if (class->default_backend_name != NULL)
623 gtk_combo_box_set_active_id (
624 GTK_COMBO_BOX (priv->type_combo),
625 class->default_backend_name);
626 }
627
628 static gboolean
mail_config_service_page_check_complete(EMailConfigPage * page)629 mail_config_service_page_check_complete (EMailConfigPage *page)
630 {
631 EMailConfigServicePagePrivate *priv;
632 EMailConfigServiceBackend *backend;
633 GtkComboBox *type_combo;
634 const gchar *backend_name;
635
636 priv = E_MAIL_CONFIG_SERVICE_PAGE_GET_PRIVATE (page);
637
638 type_combo = GTK_COMBO_BOX (priv->type_combo);
639 backend_name = gtk_combo_box_get_active_id (type_combo);
640
641 if (backend_name == NULL)
642 return FALSE;
643
644 backend = e_mail_config_service_page_lookup_backend (
645 E_MAIL_CONFIG_SERVICE_PAGE (page), backend_name);
646
647 return e_mail_config_service_backend_check_complete (backend);
648 }
649
650 static void
mail_config_service_page_commit_changes(EMailConfigPage * page,GQueue * source_queue)651 mail_config_service_page_commit_changes (EMailConfigPage *page,
652 GQueue *source_queue)
653 {
654 EMailConfigServicePagePrivate *priv;
655 EMailConfigServiceBackend *backend;
656 GtkComboBox *type_combo;
657 const gchar *backend_name;
658
659 priv = E_MAIL_CONFIG_SERVICE_PAGE_GET_PRIVATE (page);
660
661 type_combo = GTK_COMBO_BOX (priv->type_combo);
662 backend_name = gtk_combo_box_get_active_id (type_combo);
663 g_return_if_fail (backend_name != NULL);
664
665 backend = e_mail_config_service_page_lookup_backend (
666 E_MAIL_CONFIG_SERVICE_PAGE (page), backend_name);
667
668 e_mail_config_service_backend_commit_changes (backend);
669 }
670
671 static void
e_mail_config_service_page_class_init(EMailConfigServicePageClass * class)672 e_mail_config_service_page_class_init (EMailConfigServicePageClass *class)
673 {
674 GObjectClass *object_class;
675
676 g_type_class_add_private (class, sizeof (EMailConfigServicePagePrivate));
677
678 object_class = G_OBJECT_CLASS (class);
679 object_class->set_property = mail_config_service_page_set_property;
680 object_class->get_property = mail_config_service_page_get_property;
681 object_class->dispose = mail_config_service_page_dispose;
682 object_class->finalize = mail_config_service_page_finalize;
683 object_class->constructed = mail_config_service_page_constructed;
684
685 g_object_class_install_property (
686 object_class,
687 PROP_ACTIVE_BACKEND,
688 g_param_spec_object (
689 "active-backend",
690 "Active Backend",
691 "The active service backend",
692 E_TYPE_MAIL_CONFIG_SERVICE_BACKEND,
693 G_PARAM_READWRITE |
694 G_PARAM_STATIC_STRINGS));
695
696 g_object_class_install_property (
697 object_class,
698 PROP_EMAIL_ADDRESS,
699 g_param_spec_string (
700 "email-address",
701 "Email Address",
702 "The user's email address",
703 NULL,
704 G_PARAM_READWRITE |
705 G_PARAM_STATIC_STRINGS));
706
707 g_object_class_install_property (
708 object_class,
709 PROP_REGISTRY,
710 g_param_spec_object (
711 "registry",
712 "Registry",
713 "Data source registry",
714 E_TYPE_SOURCE_REGISTRY,
715 G_PARAM_READWRITE |
716 G_PARAM_CONSTRUCT_ONLY |
717 G_PARAM_STATIC_STRINGS));
718 }
719
720 static void
e_mail_config_service_page_interface_init(EMailConfigPageInterface * iface)721 e_mail_config_service_page_interface_init (EMailConfigPageInterface *iface)
722 {
723 iface->setup_defaults = mail_config_service_page_setup_defaults;
724 iface->check_complete = mail_config_service_page_check_complete;
725 iface->commit_changes = mail_config_service_page_commit_changes;
726 }
727
728 static void
e_mail_config_service_page_init(EMailConfigServicePage * page)729 e_mail_config_service_page_init (EMailConfigServicePage *page)
730 {
731 page->priv = E_MAIL_CONFIG_SERVICE_PAGE_GET_PRIVATE (page);
732 }
733
734 EMailConfigServiceBackend *
e_mail_config_service_page_get_active_backend(EMailConfigServicePage * page)735 e_mail_config_service_page_get_active_backend (EMailConfigServicePage *page)
736 {
737 g_return_val_if_fail (E_IS_MAIL_CONFIG_SERVICE_PAGE (page), NULL);
738
739 return page->priv->active_backend;
740 }
741
742 void
e_mail_config_service_page_set_active_backend(EMailConfigServicePage * page,EMailConfigServiceBackend * backend)743 e_mail_config_service_page_set_active_backend (EMailConfigServicePage *page,
744 EMailConfigServiceBackend *backend)
745 {
746 g_return_if_fail (E_IS_MAIL_CONFIG_SERVICE_PAGE (page));
747
748 if (page->priv->active_backend == backend)
749 return;
750
751 if (backend != NULL) {
752 g_return_if_fail (E_IS_MAIL_CONFIG_SERVICE_BACKEND (backend));
753 g_object_ref (backend);
754 }
755
756 if (page->priv->active_backend != NULL)
757 g_object_unref (page->priv->active_backend);
758
759 page->priv->active_backend = backend;
760
761 g_object_notify (G_OBJECT (page), "active-backend");
762 }
763
764 const gchar *
e_mail_config_service_page_get_email_address(EMailConfigServicePage * page)765 e_mail_config_service_page_get_email_address (EMailConfigServicePage *page)
766 {
767 g_return_val_if_fail (E_IS_MAIL_CONFIG_SERVICE_PAGE (page), NULL);
768
769 return page->priv->email_address;
770 }
771
772 void
e_mail_config_service_page_set_email_address(EMailConfigServicePage * page,const gchar * email_address)773 e_mail_config_service_page_set_email_address (EMailConfigServicePage *page,
774 const gchar *email_address)
775 {
776 g_return_if_fail (E_IS_MAIL_CONFIG_SERVICE_PAGE (page));
777
778 if (g_strcmp0 (page->priv->email_address, email_address) == 0)
779 return;
780
781 g_free (page->priv->email_address);
782 page->priv->email_address = g_strdup (email_address);
783
784 g_object_notify (G_OBJECT (page), "email-address");
785 }
786
787 ESourceRegistry *
e_mail_config_service_page_get_registry(EMailConfigServicePage * page)788 e_mail_config_service_page_get_registry (EMailConfigServicePage *page)
789 {
790 g_return_val_if_fail (E_IS_MAIL_CONFIG_SERVICE_PAGE (page), NULL);
791
792 return page->priv->registry;
793 }
794
795 EMailConfigServiceBackend *
e_mail_config_service_page_add_scratch_source(EMailConfigServicePage * page,ESource * scratch_source,ESource * opt_collection)796 e_mail_config_service_page_add_scratch_source (EMailConfigServicePage *page,
797 ESource *scratch_source,
798 ESource *opt_collection)
799 {
800 GtkWidget *widget;
801 GtkLabel *type_label;
802 GtkComboBox *type_combo;
803 GtkTreeIter iter;
804 Candidate *candidate;
805 const gchar *display_name;
806 gboolean selectable;
807 gint page_num;
808
809 g_return_val_if_fail (E_IS_MAIL_CONFIG_SERVICE_PAGE (page), NULL);
810 g_return_val_if_fail (E_IS_SOURCE (scratch_source), NULL);
811
812 if (opt_collection != NULL)
813 g_return_val_if_fail (E_IS_SOURCE (opt_collection), NULL);
814
815 type_label = GTK_LABEL (page->priv->type_label);
816 type_combo = GTK_COMBO_BOX (page->priv->type_combo);
817
818 candidate = mail_config_service_page_new_candidate (
819 page, scratch_source, opt_collection);
820 g_return_val_if_fail (candidate != NULL, NULL);
821
822 widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
823 e_mail_config_service_backend_insert_widgets (
824 candidate->backend, GTK_BOX (widget));
825 candidate->widget = g_object_ref_sink (widget);
826 gtk_widget_show (widget);
827
828 g_ptr_array_add (page->priv->candidates, candidate);
829
830 display_name = g_dgettext (
831 candidate->provider->translation_domain,
832 candidate->provider->name);
833
834 page_num = e_mail_config_service_notebook_add_page (
835 E_MAIL_CONFIG_SERVICE_NOTEBOOK (page->priv->notebook),
836 candidate->backend, widget);
837
838 selectable = e_mail_config_service_backend_get_selectable (
839 candidate->backend);
840
841 gtk_list_store_append (page->priv->list_store, &iter);
842
843 gtk_list_store_set (
844 page->priv->list_store, &iter,
845 COLUMN_BACKEND_NAME, candidate->name,
846 COLUMN_DISPLAY_NAME, display_name,
847 COLUMN_SELECTABLE, selectable,
848 -1);
849
850 /* The type label is only visible if we have one scratch source,
851 * so just always set the label text to the most recently added
852 * scratch source. */
853 gtk_label_set_text (type_label, display_name);
854
855 /* If no combo box row is active yet, choose the new row. */
856 if (gtk_combo_box_get_active_id (type_combo) == NULL)
857 gtk_combo_box_set_active_id (type_combo, candidate->name);
858
859 /* If the page number of the newly-added notebook page is zero,
860 * show the "type" label. Otherwise show the "type" combo box.
861 * There's an inverted "visible" binding between the combo box
862 * and label, so we only need to change one of the widgets. */
863 gtk_widget_set_visible (GTK_WIDGET (type_combo), page_num > 0);
864
865 return candidate->backend;
866 }
867
868 EMailConfigServiceBackend *
e_mail_config_service_page_lookup_backend(EMailConfigServicePage * page,const gchar * backend_name)869 e_mail_config_service_page_lookup_backend (EMailConfigServicePage *page,
870 const gchar *backend_name)
871 {
872 guint index;
873
874 g_return_val_if_fail (E_IS_MAIL_CONFIG_SERVICE_PAGE (page), NULL);
875 g_return_val_if_fail (backend_name != NULL, NULL);
876
877 for (index = 0; index < page->priv->candidates->len; index++) {
878 Candidate *candidate;
879
880 candidate = page->priv->candidates->pdata[index];
881
882 if (g_strcmp0 (backend_name, candidate->name) == 0)
883 return candidate->backend;
884 }
885
886 return NULL;
887 }
888
889 gboolean
e_mail_config_service_page_auto_configure(EMailConfigServicePage * page,EConfigLookup * config_lookup,gboolean * out_is_complete)890 e_mail_config_service_page_auto_configure (EMailConfigServicePage *page,
891 EConfigLookup *config_lookup,
892 gboolean *out_is_complete)
893 {
894 EMailConfigServiceBackend *select_backend = NULL;
895 gint selected_priority = G_MAXINT;
896 gboolean selected_is_complete = FALSE;
897 gboolean any_configured = FALSE;
898 guint ii;
899
900 g_return_val_if_fail (E_IS_MAIL_CONFIG_SERVICE_PAGE (page), FALSE);
901 g_return_val_if_fail (E_IS_CONFIG_LOOKUP (config_lookup), FALSE);
902
903 for (ii = 0; ii < page->priv->candidates->len; ii++) {
904 EMailConfigServiceBackend *backend;
905 Candidate *candidate;
906 gboolean configured;
907 gint priority = G_MAXINT;
908 gboolean is_complete = FALSE;
909
910 candidate = page->priv->candidates->pdata[ii];
911 backend = candidate->backend;
912
913 configured = e_mail_config_service_backend_auto_configure (backend, config_lookup, &priority, &is_complete);
914
915 if (configured && priority < selected_priority) {
916 selected_priority = priority;
917 selected_is_complete = is_complete;
918 select_backend = backend;
919 }
920
921 any_configured = any_configured || configured;
922 }
923
924 if (select_backend)
925 e_mail_config_service_page_set_active_backend (page, select_backend);
926
927 if (out_is_complete)
928 *out_is_complete = selected_is_complete;
929
930 return any_configured;
931 }
932
933