evolution-3.6.4/mail/e-mail-config-assistant.c

No issues found

Incomplete coverage

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