evolution-3.6.4/mail/e-mail-config-service-page.c

No issues found

Incomplete coverage

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
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
  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 }