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