evolution-3.6.4/widgets/misc/e-source-config.c

No issues found

   1 /*
   2  * e-source-config.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-source-config.h"
  20 
  21 #include <config.h>
  22 #include <glib/gi18n-lib.h>
  23 
  24 #include <libebackend/libebackend.h>
  25 
  26 #include <e-util/e-marshal.h>
  27 #include <misc/e-interval-chooser.h>
  28 
  29 #include "e-source-config-backend.h"
  30 
  31 #define E_SOURCE_CONFIG_GET_PRIVATE(obj) \
  32 	(G_TYPE_INSTANCE_GET_PRIVATE \
  33 	((obj), E_TYPE_SOURCE_CONFIG, ESourceConfigPrivate))
  34 
  35 typedef struct _Candidate Candidate;
  36 
  37 struct _ESourceConfigPrivate {
  38 	ESource *original_source;
  39 	ESource *collection_source;
  40 	ESourceRegistry *registry;
  41 
  42 	GHashTable *backends;
  43 	GPtrArray *candidates;
  44 
  45 	GtkWidget *type_label;
  46 	GtkWidget *type_combo;
  47 	GtkWidget *name_label;
  48 	GtkWidget *name_entry;
  49 	GtkWidget *backend_box;
  50 	GtkSizeGroup *size_group;
  51 
  52 	gboolean complete;
  53 };
  54 
  55 struct _Candidate {
  56 	GtkWidget *page;
  57 	ESource *scratch_source;
  58 	ESourceConfigBackend *backend;
  59 	gulong changed_handler_id;
  60 };
  61 
  62 enum {
  63 	PROP_0,
  64 	PROP_COLLECTION_SOURCE,
  65 	PROP_COMPLETE,
  66 	PROP_ORIGINAL_SOURCE,
  67 	PROP_REGISTRY
  68 };
  69 
  70 enum {
  71 	CHECK_COMPLETE,
  72 	COMMIT_CHANGES,
  73 	INIT_CANDIDATE,
  74 	RESIZE_WINDOW,
  75 	LAST_SIGNAL
  76 };
  77 
  78 static guint signals[LAST_SIGNAL];
  79 
  80 G_DEFINE_TYPE_WITH_CODE (
  81 	ESourceConfig,
  82 	e_source_config,
  83 	GTK_TYPE_BOX,
  84 	G_IMPLEMENT_INTERFACE (
  85 		E_TYPE_EXTENSIBLE, NULL))
  86 
  87 static void
  88 source_config_init_backends (ESourceConfig *config)
  89 {
  90 	GList *list, *iter;
  91 
  92 	config->priv->backends = g_hash_table_new_full (
  93 		(GHashFunc) g_str_hash,
  94 		(GEqualFunc) g_str_equal,
  95 		(GDestroyNotify) g_free,
  96 		(GDestroyNotify) g_object_unref);
  97 
  98 	e_extensible_load_extensions (E_EXTENSIBLE (config));
  99 
 100 	list = e_extensible_list_extensions (
 101 		E_EXTENSIBLE (config), E_TYPE_SOURCE_CONFIG_BACKEND);
 102 
 103 	for (iter = list; iter != NULL; iter = g_list_next (iter)) {
 104 		ESourceConfigBackend *backend;
 105 		ESourceConfigBackendClass *class;
 106 
 107 		backend = E_SOURCE_CONFIG_BACKEND (iter->data);
 108 		class = E_SOURCE_CONFIG_BACKEND_GET_CLASS (backend);
 109 
 110 		if (class->backend_name != NULL)
 111 			g_hash_table_insert (
 112 				config->priv->backends,
 113 				g_strdup (class->backend_name),
 114 				g_object_ref (backend));
 115 	}
 116 
 117 	g_list_free (list);
 118 }
 119 
 120 static gint
 121 source_config_compare_sources (gconstpointer a,
 122                                gconstpointer b,
 123                                gpointer user_data)
 124 {
 125 	ESource *source_a;
 126 	ESource *source_b;
 127 	ESource *parent_a;
 128 	ESource *parent_b;
 129 	ESourceConfig *config;
 130 	ESourceRegistry *registry;
 131 	const gchar *parent_uid_a;
 132 	const gchar *parent_uid_b;
 133 	gint result;
 134 
 135 	source_a = E_SOURCE (a);
 136 	source_b = E_SOURCE (b);
 137 	config = E_SOURCE_CONFIG (user_data);
 138 
 139 	if (e_source_equal (source_a, source_b))
 140 		return 0;
 141 
 142 	/* "On This Computer" always comes first. */
 143 
 144 	parent_uid_a = e_source_get_parent (source_a);
 145 	parent_uid_b = e_source_get_parent (source_b);
 146 
 147 	if (g_strcmp0 (parent_uid_a, "local-stub") == 0)
 148 		return -1;
 149 
 150 	if (g_strcmp0 (parent_uid_b, "local-stub") == 0)
 151 		return 1;
 152 
 153 	registry = e_source_config_get_registry (config);
 154 
 155 	parent_a = e_source_registry_ref_source (registry, parent_uid_a);
 156 	parent_b = e_source_registry_ref_source (registry, parent_uid_b);
 157 
 158 	g_return_val_if_fail (parent_a != NULL, 1);
 159 	g_return_val_if_fail (parent_b != NULL, -1);
 160 
 161 	result = e_source_compare_by_display_name (parent_a, parent_b);
 162 
 163 	g_object_unref (parent_a);
 164 	g_object_unref (parent_b);
 165 
 166 	return result;
 167 }
 168 
 169 static void
 170 source_config_add_candidate (ESourceConfig *config,
 171                              ESource *scratch_source,
 172                              ESourceConfigBackend *backend)
 173 {
 174 	Candidate *candidate;
 175 	GtkBox *backend_box;
 176 	GtkLabel *type_label;
 177 	GtkComboBoxText *type_combo;
 178 	ESource *parent_source;
 179 	ESourceRegistry *registry;
 180 	const gchar *display_name;
 181 	const gchar *parent_uid;
 182 	gulong handler_id;
 183 
 184 	backend_box = GTK_BOX (config->priv->backend_box);
 185 	type_label = GTK_LABEL (config->priv->type_label);
 186 	type_combo = GTK_COMBO_BOX_TEXT (config->priv->type_combo);
 187 
 188 	registry = e_source_config_get_registry (config);
 189 	parent_uid = e_source_get_parent (scratch_source);
 190 	parent_source = e_source_registry_ref_source (registry, parent_uid);
 191 	g_return_if_fail (parent_source != NULL);
 192 
 193 	candidate = g_slice_new (Candidate);
 194 	candidate->backend = g_object_ref (backend);
 195 	candidate->scratch_source = g_object_ref (scratch_source);
 196 
 197 	/* Do not show the page here. */
 198 	candidate->page = g_object_ref_sink (gtk_vbox_new (FALSE, 6));
 199 	gtk_box_pack_start (backend_box, candidate->page, FALSE, FALSE, 0);
 200 
 201 	g_ptr_array_add (config->priv->candidates, candidate);
 202 
 203 	display_name = e_source_get_display_name (parent_source);
 204 	gtk_combo_box_text_append_text (type_combo, display_name);
 205 	gtk_label_set_text (type_label, display_name);
 206 
 207 	/* Make sure the combo box has a valid active item before
 208 	 * adding widgets.  Otherwise we'll get run-time warnings
 209 	 * as property bindings are set up. */
 210 	if (gtk_combo_box_get_active (GTK_COMBO_BOX (type_combo)) == -1)
 211 		gtk_combo_box_set_active (GTK_COMBO_BOX (type_combo), 0);
 212 
 213 	/* Bind the standard widgets to the new scratch source. */
 214 	g_signal_emit (
 215 		config, signals[INIT_CANDIDATE], 0,
 216 		candidate->scratch_source);
 217 
 218 	/* Insert any backend-specific widgets. */
 219 	e_source_config_backend_insert_widgets (
 220 		candidate->backend, candidate->scratch_source);
 221 
 222 	handler_id = g_signal_connect_swapped (
 223 		candidate->scratch_source, "changed",
 224 		G_CALLBACK (e_source_config_check_complete), config);
 225 
 226 	candidate->changed_handler_id = handler_id;
 227 
 228 	/* Trigger the "changed" handler we just connected to set the
 229 	 * initial "complete" state based on the widgets we just added. */
 230 	e_source_changed (candidate->scratch_source);
 231 
 232 	g_object_unref (parent_source);
 233 }
 234 
 235 static void
 236 source_config_free_candidate (Candidate *candidate)
 237 {
 238 	g_signal_handler_disconnect (
 239 		candidate->scratch_source,
 240 		candidate->changed_handler_id);
 241 
 242 	g_object_unref (candidate->page);
 243 	g_object_unref (candidate->scratch_source);
 244 	g_object_unref (candidate->backend);
 245 
 246 	g_slice_free (Candidate, candidate);
 247 }
 248 
 249 static Candidate *
 250 source_config_get_active_candidate (ESourceConfig *config)
 251 {
 252 	GtkComboBox *type_combo;
 253 	gint index;
 254 
 255 	type_combo = GTK_COMBO_BOX (config->priv->type_combo);
 256 	index = gtk_combo_box_get_active (type_combo);
 257 	g_return_val_if_fail (index >= 0, NULL);
 258 
 259 	return g_ptr_array_index (config->priv->candidates, index);
 260 }
 261 
 262 static void
 263 source_config_type_combo_changed_cb (GtkComboBox *type_combo,
 264                                      ESourceConfig *config)
 265 {
 266 	Candidate *candidate;
 267 	GPtrArray *array;
 268 	gint index;
 269 
 270 	array = config->priv->candidates;
 271 
 272 	for (index = 0; index < array->len; index++) {
 273 		candidate = g_ptr_array_index (array, index);
 274 		gtk_widget_hide (candidate->page);
 275 	}
 276 
 277 	index = gtk_combo_box_get_active (type_combo);
 278 	if (index == CLAMP (index, 0, array->len)) {
 279 		candidate = g_ptr_array_index (array, index);
 280 		gtk_widget_show (candidate->page);
 281 	}
 282 
 283 	e_source_config_resize_window (config);
 284 	e_source_config_check_complete (config);
 285 }
 286 
 287 static gboolean
 288 source_config_init_for_adding_source_foreach (gpointer key,
 289                                               gpointer value,
 290                                               gpointer user_data)
 291 {
 292 	ESource *scratch_source;
 293 	ESourceBackend *extension;
 294 	ESourceConfig *config;
 295 	ESourceConfigBackend *backend;
 296 	ESourceConfigBackendClass *class;
 297 	const gchar *extension_name;
 298 
 299 	scratch_source = E_SOURCE (key);
 300 	backend = E_SOURCE_CONFIG_BACKEND (value);
 301 	config = E_SOURCE_CONFIG (user_data);
 302 
 303 	/* This may not be the correct backend name for the child of a
 304 	 * collection.  For example, the "yahoo" collection backend uses
 305 	 * the "caldav" calender backend for calendar children.  But the
 306 	 * ESourceCollectionBackend can override our setting if needed. */
 307 	class = E_SOURCE_CONFIG_BACKEND_GET_CLASS (backend);
 308 	extension_name = e_source_config_get_backend_extension_name (config);
 309 	extension = e_source_get_extension (scratch_source, extension_name);
 310 	e_source_backend_set_backend_name (extension, class->backend_name);
 311 
 312 	source_config_add_candidate (config, scratch_source, backend);
 313 
 314 	return FALSE;  /* don't stop traversal */
 315 }
 316 
 317 static void
 318 source_config_init_for_adding_source (ESourceConfig *config)
 319 {
 320 	GList *list, *link;
 321 	ESourceRegistry *registry;
 322 	GTree *scratch_source_tree;
 323 
 324 	/* Candidates are drawn from two sources:
 325 	 *
 326 	 * ESourceConfigBackend classes that specify a fixed parent UID,
 327 	 * meaning there exists one only possible parent source for any
 328 	 * scratch source created by the backend.  The fixed parent UID
 329 	 * should be a built-in "stub" placeholder ("local-stub", etc).
 330 	 *
 331 	 * -and-
 332 	 *
 333 	 * Collection sources.  We let ESourceConfig subclasses gather
 334 	 * eligible collection sources to serve as parents for scratch
 335 	 * sources.  A scratch source is matched to a backend based on
 336 	 * the collection's backend name.  The "calendar-enabled" and
 337 	 * "contacts-enabled" settings also factor into eligibility.
 338 	 */
 339 
 340 	/* Use a GTree instead of a GHashTable so inserted scratch
 341 	 * sources automatically sort themselves by their parent's
 342 	 * display name. */
 343 	scratch_source_tree = g_tree_new_full (
 344 		source_config_compare_sources, config,
 345 		(GDestroyNotify) g_object_unref,
 346 		(GDestroyNotify) g_object_unref);
 347 
 348 	registry = e_source_config_get_registry (config);
 349 
 350 	/* First pick out the backends with a fixed parent UID. */
 351 
 352 	list = g_hash_table_get_values (config->priv->backends);
 353 
 354 	for (link = list; link != NULL; link = g_list_next (link)) {
 355 		ESourceConfigBackend *backend;
 356 		ESourceConfigBackendClass *class;
 357 		ESource *scratch_source;
 358 		ESource *parent_source;
 359 		gboolean parent_is_disabled;
 360 
 361 		backend = E_SOURCE_CONFIG_BACKEND (link->data);
 362 		class = E_SOURCE_CONFIG_BACKEND_GET_CLASS (backend);
 363 
 364 		if (class->parent_uid == NULL)
 365 			continue;
 366 
 367 		/* Verify the fixed parent UID is valid. */
 368 		parent_source = e_source_registry_ref_source (
 369 			registry, class->parent_uid);
 370 		if (parent_source == NULL) {
 371 			g_warning (
 372 				"%s: %sClass specifies "
 373 				"an invalid parent_uid '%s'",
 374 				G_STRFUNC,
 375 				G_OBJECT_TYPE_NAME (backend),
 376 				class->parent_uid);
 377 			continue;
 378 		}
 379 		parent_is_disabled = !e_source_get_enabled (parent_source);
 380 		g_object_unref (parent_source);
 381 
 382 		/* It's unusual for a fixed parent source to be disabled.
 383 		 * A user would have to go out of his way to do this, but
 384 		 * we should honor it regardless. */
 385 		if (parent_is_disabled)
 386 			continue;
 387 
 388 		/* Some backends don't allow new sources to be created.
 389 		 * The "contacts" calendar backend is one such example. */
 390 		if (!e_source_config_backend_allow_creation (backend))
 391 			continue;
 392 
 393 		scratch_source = e_source_new (NULL, NULL, NULL);
 394 		g_return_if_fail (scratch_source != NULL);
 395 
 396 		e_source_set_parent (scratch_source, class->parent_uid);
 397 
 398 		g_tree_insert (
 399 			scratch_source_tree,
 400 			g_object_ref (scratch_source),
 401 			g_object_ref (backend));
 402 
 403 		g_object_unref (scratch_source);
 404 	}
 405 
 406 	g_list_free (list);
 407 
 408 	/* Next gather eligible collection sources to serve as parents. */
 409 
 410 	list = e_source_config_list_eligible_collections (config);
 411 
 412 	for (link = list; link != NULL; link = g_list_next (link)) {
 413 		ESource *parent_source;
 414 		ESource *scratch_source;
 415 		ESourceBackend *extension;
 416 		ESourceConfigBackend *backend = NULL;
 417 		const gchar *backend_name;
 418 		const gchar *parent_uid;
 419 
 420 		parent_source = E_SOURCE (link->data);
 421 		parent_uid = e_source_get_uid (parent_source);
 422 
 423 		extension = e_source_get_extension (
 424 			parent_source, E_SOURCE_EXTENSION_COLLECTION);
 425 		backend_name = e_source_backend_get_backend_name (extension);
 426 
 427 		if (backend_name != NULL)
 428 			backend = g_hash_table_lookup (
 429 				config->priv->backends, backend_name);
 430 
 431 		if (backend == NULL)
 432 			continue;
 433 
 434 		/* Some backends disallow creating certain types of
 435 		 * resources.  For example, the Exchange Web Services
 436 		 * backend disallows creating new memo lists. */
 437 		if (!e_source_config_backend_allow_creation (backend))
 438 			continue;
 439 
 440 		scratch_source = e_source_new (NULL, NULL, NULL);
 441 		g_return_if_fail (scratch_source != NULL);
 442 
 443 		e_source_set_parent (scratch_source, parent_uid);
 444 
 445 		g_tree_insert (
 446 			scratch_source_tree,
 447 			g_object_ref (scratch_source),
 448 			g_object_ref (backend));
 449 
 450 		g_object_unref (scratch_source);
 451 	}
 452 
 453 	g_list_free_full (list, (GDestroyNotify) g_object_unref);
 454 
 455 	/* XXX GTree doesn't get as much love as GHashTable.
 456 	 *     It's missing an equivalent to GHashTableIter. */
 457 	g_tree_foreach (
 458 		scratch_source_tree,
 459 		source_config_init_for_adding_source_foreach, config);
 460 
 461 	g_tree_unref (scratch_source_tree);
 462 }
 463 
 464 static void
 465 source_config_init_for_editing_source (ESourceConfig *config)
 466 {
 467 	ESource *original_source;
 468 	ESource *scratch_source;
 469 	ESourceBackend *extension;
 470 	ESourceConfigBackend *backend;
 471 	GDBusObject *dbus_object;
 472 	const gchar *backend_name;
 473 	const gchar *extension_name;
 474 
 475 	original_source = e_source_config_get_original_source (config);
 476 	g_return_if_fail (original_source != NULL);
 477 
 478 	extension_name = e_source_config_get_backend_extension_name (config);
 479 	extension = e_source_get_extension (original_source, extension_name);
 480 	backend_name = e_source_backend_get_backend_name (extension);
 481 	g_return_if_fail (backend_name != NULL);
 482 
 483 	backend = g_hash_table_lookup (config->priv->backends, backend_name);
 484 	g_return_if_fail (backend != NULL);
 485 
 486 	dbus_object = e_source_ref_dbus_object (original_source);
 487 	g_return_if_fail (dbus_object != NULL);
 488 
 489 	scratch_source = e_source_new (dbus_object, NULL, NULL);
 490 	g_return_if_fail (scratch_source != NULL);
 491 
 492 	source_config_add_candidate (config, scratch_source, backend);
 493 
 494 	g_object_unref (scratch_source);
 495 	g_object_unref (dbus_object);
 496 }
 497 
 498 static void
 499 source_config_set_original_source (ESourceConfig *config,
 500                                    ESource *original_source)
 501 {
 502 	g_return_if_fail (config->priv->original_source == NULL);
 503 
 504 	if (original_source != NULL)
 505 		g_object_ref (original_source);
 506 
 507 	config->priv->original_source = original_source;
 508 }
 509 
 510 static void
 511 source_config_set_registry (ESourceConfig *config,
 512                             ESourceRegistry *registry)
 513 {
 514 	g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
 515 	g_return_if_fail (config->priv->registry == NULL);
 516 
 517 	config->priv->registry = g_object_ref (registry);
 518 }
 519 
 520 static void
 521 source_config_set_property (GObject *object,
 522                             guint property_id,
 523                             const GValue *value,
 524                             GParamSpec *pspec)
 525 {
 526 	switch (property_id) {
 527 		case PROP_ORIGINAL_SOURCE:
 528 			source_config_set_original_source (
 529 				E_SOURCE_CONFIG (object),
 530 				g_value_get_object (value));
 531 			return;
 532 
 533 		case PROP_REGISTRY:
 534 			source_config_set_registry (
 535 				E_SOURCE_CONFIG (object),
 536 				g_value_get_object (value));
 537 			return;
 538 	}
 539 
 540 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 541 }
 542 
 543 static void
 544 source_config_get_property (GObject *object,
 545                             guint property_id,
 546                             GValue *value,
 547                             GParamSpec *pspec)
 548 {
 549 	switch (property_id) {
 550 		case PROP_COLLECTION_SOURCE:
 551 			g_value_set_object (
 552 				value,
 553 				e_source_config_get_collection_source (
 554 				E_SOURCE_CONFIG (object)));
 555 			return;
 556 
 557 		case PROP_COMPLETE:
 558 			g_value_set_boolean (
 559 				value,
 560 				e_source_config_check_complete (
 561 				E_SOURCE_CONFIG (object)));
 562 			return;
 563 
 564 		case PROP_ORIGINAL_SOURCE:
 565 			g_value_set_object (
 566 				value,
 567 				e_source_config_get_original_source (
 568 				E_SOURCE_CONFIG (object)));
 569 			return;
 570 
 571 		case PROP_REGISTRY:
 572 			g_value_set_object (
 573 				value,
 574 				e_source_config_get_registry (
 575 				E_SOURCE_CONFIG (object)));
 576 			return;
 577 	}
 578 
 579 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 580 }
 581 
 582 static void
 583 source_config_dispose (GObject *object)
 584 {
 585 	ESourceConfigPrivate *priv;
 586 
 587 	priv = E_SOURCE_CONFIG_GET_PRIVATE (object);
 588 
 589 	if (priv->original_source != NULL) {
 590 		g_object_unref (priv->original_source);
 591 		priv->original_source = NULL;
 592 	}
 593 
 594 	if (priv->collection_source != NULL) {
 595 		g_object_unref (priv->collection_source);
 596 		priv->collection_source = NULL;
 597 	}
 598 
 599 	if (priv->registry != NULL) {
 600 		g_object_unref (priv->registry);
 601 		priv->registry = NULL;
 602 	}
 603 
 604 	if (priv->type_label != NULL) {
 605 		g_object_unref (priv->type_label);
 606 		priv->type_label = NULL;
 607 	}
 608 
 609 	if (priv->type_combo != NULL) {
 610 		g_object_unref (priv->type_combo);
 611 		priv->type_combo = NULL;
 612 	}
 613 
 614 	if (priv->name_label != NULL) {
 615 		g_object_unref (priv->name_label);
 616 		priv->name_label = NULL;
 617 	}
 618 
 619 	if (priv->name_entry != NULL) {
 620 		g_object_unref (priv->name_entry);
 621 		priv->name_entry = NULL;
 622 	}
 623 
 624 	if (priv->backend_box != NULL) {
 625 		g_object_unref (priv->backend_box);
 626 		priv->backend_box = NULL;
 627 	}
 628 
 629 	if (priv->size_group != NULL) {
 630 		g_object_unref (priv->size_group);
 631 		priv->size_group = NULL;
 632 	}
 633 
 634 	g_hash_table_remove_all (priv->backends);
 635 	g_ptr_array_set_size (priv->candidates, 0);
 636 
 637 	/* Chain up to parent's dispose() method. */
 638 	G_OBJECT_CLASS (e_source_config_parent_class)->dispose (object);
 639 }
 640 
 641 static void
 642 source_config_finalize (GObject *object)
 643 {
 644 	ESourceConfigPrivate *priv;
 645 
 646 	priv = E_SOURCE_CONFIG_GET_PRIVATE (object);
 647 
 648 	g_hash_table_destroy (priv->backends);
 649 	g_ptr_array_free (priv->candidates, TRUE);
 650 
 651 	/* Chain up to parent's finalize() method. */
 652 	G_OBJECT_CLASS (e_source_config_parent_class)->finalize (object);
 653 }
 654 
 655 static void
 656 source_config_constructed (GObject *object)
 657 {
 658 	ESourceConfig *config;
 659 	ESourceRegistry *registry;
 660 	ESource *original_source;
 661 	ESource *collection_source = NULL;
 662 
 663 	config = E_SOURCE_CONFIG (object);
 664 	registry = e_source_config_get_registry (config);
 665 	original_source = e_source_config_get_original_source (config);
 666 
 667 	/* If we have an original source, see if it's part
 668 	 * of a collection and note the collection source. */
 669 	if (original_source != NULL) {
 670 		const gchar *extension_name;
 671 
 672 		extension_name = E_SOURCE_EXTENSION_COLLECTION;
 673 		collection_source = e_source_registry_find_extension (
 674 			registry, original_source, extension_name);
 675 		config->priv->collection_source = collection_source;
 676 	}
 677 
 678 	if (original_source != NULL)
 679 		e_source_config_insert_widget (
 680 			config, NULL, _("Type:"),
 681 			config->priv->type_label);
 682 	else
 683 		e_source_config_insert_widget (
 684 			config, NULL, _("Type:"),
 685 			config->priv->type_combo);
 686 
 687 	/* If the original source is part of a collection then we assume
 688 	 * the display name is server-assigned and not user-assigned, at
 689 	 * least not assigned through Evolution. */
 690 	if (collection_source != NULL)
 691 		e_source_config_insert_widget (
 692 			config, NULL, _("Name:"),
 693 			config->priv->name_label);
 694 	else
 695 		e_source_config_insert_widget (
 696 			config, NULL, _("Name:"),
 697 			config->priv->name_entry);
 698 
 699 	source_config_init_backends (config);
 700 }
 701 
 702 static void
 703 source_config_realize (GtkWidget *widget)
 704 {
 705 	ESourceConfig *config;
 706 	ESource *original_source;
 707 
 708 	/* Chain up to parent's realize() method. */
 709 	GTK_WIDGET_CLASS (e_source_config_parent_class)->realize (widget);
 710 
 711 	/* Do this after constructed() so subclasses can fully
 712 	 * initialize themselves before we add candidates. */
 713 
 714 	config = E_SOURCE_CONFIG (widget);
 715 	original_source = e_source_config_get_original_source (config);
 716 
 717 	if (original_source == NULL)
 718 		source_config_init_for_adding_source (config);
 719 	else
 720 		source_config_init_for_editing_source (config);
 721 }
 722 
 723 static GList *
 724 source_config_list_eligible_collections (ESourceConfig *config)
 725 {
 726 	ESourceRegistry *registry;
 727 	GQueue trash = G_QUEUE_INIT;
 728 	GList *list, *link;
 729 	const gchar *extension_name;
 730 
 731 	extension_name = E_SOURCE_EXTENSION_COLLECTION;
 732 	registry = e_source_config_get_registry (config);
 733 
 734 	list = e_source_registry_list_sources (registry, extension_name);
 735 
 736 	for (link = list; link != NULL; link = g_list_next (link)) {
 737 		ESource *source = E_SOURCE (link->data);
 738 		gboolean elligible;
 739 
 740 		elligible =
 741 			e_source_get_enabled (source) &&
 742 			e_source_get_remote_creatable (source);
 743 
 744 		if (!elligible)
 745 			g_queue_push_tail (&trash, link);
 746 	}
 747 
 748 	/* Remove ineligible collections from the list. */
 749 	while ((link = g_queue_pop_head (&trash)) != NULL) {
 750 		g_object_unref (link->data);
 751 		list = g_list_delete_link (list, link);
 752 	}
 753 
 754 	return list;
 755 }
 756 
 757 static void
 758 source_config_init_candidate (ESourceConfig *config,
 759                               ESource *scratch_source)
 760 {
 761 	g_object_bind_property (
 762 		scratch_source, "display-name",
 763 		config->priv->name_label, "label",
 764 		G_BINDING_SYNC_CREATE);
 765 
 766 	g_object_bind_property (
 767 		scratch_source, "display-name",
 768 		config->priv->name_entry, "text",
 769 		G_BINDING_BIDIRECTIONAL |
 770 		G_BINDING_SYNC_CREATE);
 771 }
 772 
 773 static gboolean
 774 source_config_check_complete (ESourceConfig *config,
 775                               ESource *scratch_source)
 776 {
 777 	GtkEntry *name_entry;
 778 	GtkComboBox *type_combo;
 779 	const gchar *text;
 780 
 781 	/* Make sure the Type: combo box has a valid item. */
 782 	type_combo = GTK_COMBO_BOX (config->priv->type_combo);
 783 	if (gtk_combo_box_get_active (type_combo) < 0)
 784 		return FALSE;
 785 
 786 	/* Make sure the Name: entry field is not empty. */
 787 	name_entry = GTK_ENTRY (config->priv->name_entry);
 788 	text = gtk_entry_get_text (name_entry);
 789 	if (text == NULL || *text == '\0')
 790 		return FALSE;
 791 
 792 	return TRUE;
 793 }
 794 
 795 static void
 796 source_config_commit_changes (ESourceConfig *config,
 797                               ESource *scratch_source)
 798 {
 799 	/* Placeholder so subclasses can safely chain up. */
 800 }
 801 
 802 static void
 803 source_config_resize_window (ESourceConfig *config)
 804 {
 805 	GtkWidget *toplevel;
 806 
 807 	/* Expand or shrink our parent window vertically to accommodate
 808 	 * the newly selected backend's options.  Some backends have tons
 809 	 * of options, some have few.  This avoids the case where you
 810 	 * select a backend with tons of options and then a backend with
 811 	 * few options and wind up with lots of unused vertical space. */
 812 
 813 	toplevel = gtk_widget_get_toplevel (GTK_WIDGET (config));
 814 
 815 	if (GTK_IS_WINDOW (toplevel)) {
 816 		GtkWindow *window = GTK_WINDOW (toplevel);
 817 		GtkAllocation allocation;
 818 
 819 		gtk_widget_get_allocation (toplevel, &allocation);
 820 		gtk_window_resize (window, allocation.width, 1);
 821 	}
 822 }
 823 
 824 static gboolean
 825 source_config_check_complete_accumulator (GSignalInvocationHint *ihint,
 826                                           GValue *return_accu,
 827                                           const GValue *handler_return,
 828                                           gpointer unused)
 829 {
 830 	gboolean v_boolean;
 831 
 832 	/* Abort emission if a handler returns FALSE. */
 833 	v_boolean = g_value_get_boolean (handler_return);
 834 	g_value_set_boolean (return_accu, v_boolean);
 835 
 836 	return v_boolean;
 837 }
 838 
 839 static void
 840 e_source_config_class_init (ESourceConfigClass *class)
 841 {
 842 	GObjectClass *object_class;
 843 	GtkWidgetClass *widget_class;
 844 
 845 	g_type_class_add_private (class, sizeof (ESourceConfigPrivate));
 846 
 847 	object_class = G_OBJECT_CLASS (class);
 848 	object_class->set_property = source_config_set_property;
 849 	object_class->get_property = source_config_get_property;
 850 	object_class->dispose = source_config_dispose;
 851 	object_class->finalize = source_config_finalize;
 852 	object_class->constructed = source_config_constructed;
 853 
 854 	widget_class = GTK_WIDGET_CLASS (class);
 855 	widget_class->realize = source_config_realize;
 856 
 857 	class->list_eligible_collections =
 858 		source_config_list_eligible_collections;
 859 	class->init_candidate = source_config_init_candidate;
 860 	class->check_complete = source_config_check_complete;
 861 	class->commit_changes = source_config_commit_changes;
 862 	class->resize_window = source_config_resize_window;
 863 
 864 	g_object_class_install_property (
 865 		object_class,
 866 		PROP_COLLECTION_SOURCE,
 867 		g_param_spec_object (
 868 			"collection-source",
 869 			"Collection Source",
 870 			"The collection ESource to which "
 871 			"the ESource being edited belongs",
 872 			E_TYPE_SOURCE,
 873 			G_PARAM_READABLE |
 874 			G_PARAM_STATIC_STRINGS));
 875 
 876 	g_object_class_install_property (
 877 		object_class,
 878 		PROP_COMPLETE,
 879 		g_param_spec_boolean (
 880 			"complete",
 881 			"Complete",
 882 			"Are the required fields complete?",
 883 			FALSE,
 884 			G_PARAM_READABLE |
 885 			G_PARAM_STATIC_STRINGS));
 886 
 887 	g_object_class_install_property (
 888 		object_class,
 889 		PROP_ORIGINAL_SOURCE,
 890 		g_param_spec_object (
 891 			"original-source",
 892 			"Original Source",
 893 			"The original ESource",
 894 			E_TYPE_SOURCE,
 895 			G_PARAM_READWRITE |
 896 			G_PARAM_CONSTRUCT_ONLY |
 897 			G_PARAM_STATIC_STRINGS));
 898 
 899 	g_object_class_install_property (
 900 		object_class,
 901 		PROP_REGISTRY,
 902 		g_param_spec_object (
 903 			"registry",
 904 			"Registry",
 905 			"Registry of ESources",
 906 			E_TYPE_SOURCE_REGISTRY,
 907 			G_PARAM_READWRITE |
 908 			G_PARAM_CONSTRUCT_ONLY |
 909 			G_PARAM_STATIC_STRINGS));
 910 
 911 	signals[CHECK_COMPLETE] = g_signal_new (
 912 		"check-complete",
 913 		G_TYPE_FROM_CLASS (class),
 914 		G_SIGNAL_RUN_LAST,
 915 		G_STRUCT_OFFSET (ESourceConfigClass, check_complete),
 916 		source_config_check_complete_accumulator, NULL,
 917 		e_marshal_BOOLEAN__OBJECT,
 918 		G_TYPE_BOOLEAN, 1,
 919 		E_TYPE_SOURCE);
 920 
 921 	signals[COMMIT_CHANGES] = g_signal_new (
 922 		"commit-changes",
 923 		G_TYPE_FROM_CLASS (class),
 924 		G_SIGNAL_RUN_LAST,
 925 		G_STRUCT_OFFSET (ESourceConfigClass, commit_changes),
 926 		NULL, NULL,
 927 		g_cclosure_marshal_VOID__OBJECT,
 928 		G_TYPE_NONE, 1,
 929 		E_TYPE_SOURCE);
 930 
 931 	signals[INIT_CANDIDATE] = g_signal_new (
 932 		"init-candidate",
 933 		G_TYPE_FROM_CLASS (class),
 934 		G_SIGNAL_RUN_LAST,
 935 		G_STRUCT_OFFSET (ESourceConfigClass, init_candidate),
 936 		NULL, NULL,
 937 		g_cclosure_marshal_VOID__OBJECT,
 938 		G_TYPE_NONE, 1,
 939 		E_TYPE_SOURCE);
 940 
 941 	signals[RESIZE_WINDOW] = g_signal_new (
 942 		"resize-window",
 943 		G_TYPE_FROM_CLASS (class),
 944 		G_SIGNAL_RUN_LAST,
 945 		G_STRUCT_OFFSET (ESourceConfigClass, resize_window),
 946 		NULL, NULL,
 947 		g_cclosure_marshal_VOID__VOID,
 948 		G_TYPE_NONE, 0);
 949 }
 950 
 951 static void
 952 e_source_config_init (ESourceConfig *config)
 953 {
 954 	GPtrArray *candidates;
 955 	GtkSizeGroup *size_group;
 956 	PangoAttribute *attr;
 957 	PangoAttrList *attr_list;
 958 	GtkWidget *widget;
 959 
 960 	/* The candidates array holds scratch ESources, one for each
 961 	 * item in the "type" combo box.  Scratch ESources are never
 962 	 * added to the registry, so backend extensions can make any
 963 	 * changes they want to them.  Whichever scratch ESource is
 964 	 * "active" (selected in the "type" combo box) when the user
 965 	 * clicks OK wins and is written to disk.  The others are
 966 	 * discarded. */
 967 	candidates = g_ptr_array_new_with_free_func (
 968 		(GDestroyNotify) source_config_free_candidate);
 969 
 970 	/* The size group is used for caption labels. */
 971 	size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
 972 
 973 	gtk_box_set_spacing (GTK_BOX (config), 6);
 974 
 975 	gtk_orientable_set_orientation (
 976 		GTK_ORIENTABLE (config), GTK_ORIENTATION_VERTICAL);
 977 
 978 	config->priv = E_SOURCE_CONFIG_GET_PRIVATE (config);
 979 	config->priv->candidates = candidates;
 980 	config->priv->size_group = size_group;
 981 
 982 	attr_list = pango_attr_list_new ();
 983 
 984 	attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
 985 	pango_attr_list_insert (attr_list, attr);
 986 
 987 	/* Either the source type combo box or the label is shown,
 988 	 * never both.  But we create both widgets and keep them
 989 	 * both up-to-date because it makes the logic simpler. */
 990 
 991 	widget = gtk_label_new (NULL);
 992 	gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
 993 	gtk_label_set_attributes (GTK_LABEL (widget), attr_list);
 994 	config->priv->type_label = g_object_ref_sink (widget);
 995 	gtk_widget_show (widget);
 996 
 997 	widget = gtk_combo_box_text_new ();
 998 	config->priv->type_combo = g_object_ref_sink (widget);
 999 	gtk_widget_show (widget);
1000 
1001 	/* Similarly for the display name.  Either the text entry
1002 	 * or the label is shown, depending on whether the source
1003 	 * is a collection member (new sources never are). */
1004 
1005 	widget = gtk_label_new (NULL);
1006 	gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5);
1007 	gtk_label_set_attributes (GTK_LABEL (widget), attr_list);
1008 	config->priv->name_label = g_object_ref_sink (widget);
1009 	gtk_widget_show (widget);
1010 
1011 	widget = gtk_entry_new ();
1012 	gtk_entry_set_activates_default (GTK_ENTRY (widget), TRUE);
1013 	config->priv->name_entry = g_object_ref_sink (widget);
1014 	gtk_widget_show (widget);
1015 
1016 	/* The backend box holds backend-specific options.  Each backend
1017 	 * gets a child widget.  Only one child widget is visible at once. */
1018 	widget = gtk_vbox_new (FALSE, 12);
1019 	gtk_box_pack_end (GTK_BOX (config), widget, TRUE, TRUE, 0);
1020 	config->priv->backend_box = g_object_ref (widget);
1021 	gtk_widget_show (widget);
1022 
1023 	pango_attr_list_unref (attr_list);
1024 
1025 	g_signal_connect (
1026 		config->priv->type_combo, "changed",
1027 		G_CALLBACK (source_config_type_combo_changed_cb), config);
1028 }
1029 
1030 GtkWidget *
1031 e_source_config_new (ESourceRegistry *registry,
1032                      ESource *original_source)
1033 {
1034 	g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
1035 
1036 	if (original_source != NULL)
1037 		g_return_val_if_fail (E_IS_SOURCE (original_source), NULL);
1038 
1039 	return g_object_new (
1040 		E_TYPE_SOURCE_CONFIG, "registry", registry,
1041 		"original-source", original_source, NULL);
1042 }
1043 
1044 void
1045 e_source_config_insert_widget (ESourceConfig *config,
1046                                ESource *scratch_source,
1047                                const gchar *caption,
1048                                GtkWidget *widget)
1049 {
1050 	GtkWidget *hbox;
1051 	GtkWidget *vbox;
1052 	GtkWidget *label;
1053 
1054 	g_return_if_fail (E_IS_SOURCE_CONFIG (config));
1055 	g_return_if_fail (GTK_IS_WIDGET (widget));
1056 
1057 	if (scratch_source == NULL)
1058 		vbox = GTK_WIDGET (config);
1059 	else
1060 		vbox = e_source_config_get_page (config, scratch_source);
1061 
1062 	hbox = gtk_hbox_new (FALSE, 12);
1063 	gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
1064 
1065 	g_object_bind_property (
1066 		widget, "visible",
1067 		hbox, "visible",
1068 		G_BINDING_SYNC_CREATE);
1069 
1070 	label = gtk_label_new (caption);
1071 	gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
1072 	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
1073 	gtk_size_group_add_widget (config->priv->size_group, label);
1074 	gtk_widget_show (label);
1075 
1076 	gtk_box_pack_start (GTK_BOX (hbox), widget, TRUE, TRUE, 0);
1077 }
1078 
1079 GtkWidget *
1080 e_source_config_get_page (ESourceConfig *config,
1081                           ESource *scratch_source)
1082 {
1083 	Candidate *candidate;
1084 	GtkWidget *page = NULL;
1085 	GPtrArray *array;
1086 	gint index;
1087 
1088 	g_return_val_if_fail (E_IS_SOURCE_CONFIG (config), NULL);
1089 	g_return_val_if_fail (E_IS_SOURCE (scratch_source), NULL);
1090 
1091 	array = config->priv->candidates;
1092 
1093 	for (index = 0; page == NULL && index < array->len; index++) {
1094 		candidate = g_ptr_array_index (array, index);
1095 		if (e_source_equal (scratch_source, candidate->scratch_source))
1096 			page = candidate->page;
1097 	}
1098 
1099 	g_return_val_if_fail (GTK_IS_BOX (page), NULL);
1100 
1101 	return page;
1102 }
1103 
1104 const gchar *
1105 e_source_config_get_backend_extension_name (ESourceConfig *config)
1106 {
1107 	ESourceConfigClass *class;
1108 
1109 	g_return_val_if_fail (E_IS_SOURCE_CONFIG (config), NULL);
1110 
1111 	class = E_SOURCE_CONFIG_GET_CLASS (config);
1112 	g_return_val_if_fail (class->get_backend_extension_name != NULL, NULL);
1113 
1114 	return class->get_backend_extension_name (config);
1115 }
1116 
1117 GList *
1118 e_source_config_list_eligible_collections (ESourceConfig *config)
1119 {
1120 	ESourceConfigClass *class;
1121 
1122 	g_return_val_if_fail (E_IS_SOURCE_CONFIG (config), NULL);
1123 
1124 	class = E_SOURCE_CONFIG_GET_CLASS (config);
1125 	g_return_val_if_fail (class->list_eligible_collections != NULL, NULL);
1126 
1127 	return class->list_eligible_collections (config);
1128 }
1129 
1130 gboolean
1131 e_source_config_check_complete (ESourceConfig *config)
1132 {
1133 	Candidate *candidate;
1134 	gboolean complete;
1135 
1136 	g_return_val_if_fail (E_IS_SOURCE_CONFIG (config), FALSE);
1137 
1138 	candidate = source_config_get_active_candidate (config);
1139 	g_return_val_if_fail (candidate != NULL, FALSE);
1140 
1141 	g_signal_emit (
1142 		config, signals[CHECK_COMPLETE], 0,
1143 		candidate->scratch_source, &complete);
1144 
1145 	complete &= e_source_config_backend_check_complete (
1146 		candidate->backend, candidate->scratch_source);
1147 
1148 	/* XXX Emitting "notify::complete" may cause this function
1149 	 *     to be called repeatedly by signal handlers.  The IF
1150 	 *     check below should break any recursive cycles.  Not
1151 	 *     very efficient but I think we can live with it. */
1152 
1153 	if (complete != config->priv->complete) {
1154 		config->priv->complete = complete;
1155 		g_object_notify (G_OBJECT (config), "complete");
1156 	}
1157 
1158 	return complete;
1159 }
1160 
1161 ESource *
1162 e_source_config_get_original_source (ESourceConfig *config)
1163 {
1164 	g_return_val_if_fail (E_IS_SOURCE_CONFIG (config), NULL);
1165 
1166 	return config->priv->original_source;
1167 }
1168 
1169 ESource *
1170 e_source_config_get_collection_source (ESourceConfig *config)
1171 {
1172 	g_return_val_if_fail (E_IS_SOURCE_CONFIG (config), NULL);
1173 
1174 	return config->priv->collection_source;
1175 }
1176 
1177 ESourceRegistry *
1178 e_source_config_get_registry (ESourceConfig *config)
1179 {
1180 	g_return_val_if_fail (E_IS_SOURCE_CONFIG (config), NULL);
1181 
1182 	return config->priv->registry;
1183 }
1184 
1185 void
1186 e_source_config_resize_window (ESourceConfig *config)
1187 {
1188 	g_return_if_fail (E_IS_SOURCE_CONFIG (config));
1189 
1190 	g_signal_emit (config, signals[RESIZE_WINDOW], 0);
1191 }
1192 
1193 /* Helper for e_source_config_commit() */
1194 static void
1195 source_config_commit_cb (GObject *object,
1196                          GAsyncResult *result,
1197                          gpointer user_data)
1198 {
1199 	GSimpleAsyncResult *simple;
1200 	GError *error = NULL;
1201 
1202 	simple = G_SIMPLE_ASYNC_RESULT (user_data);
1203 
1204 	e_source_registry_commit_source_finish (
1205 		E_SOURCE_REGISTRY (object), result, &error);
1206 
1207 	if (error != NULL)
1208 		g_simple_async_result_take_error (simple, error);
1209 
1210 	g_simple_async_result_complete (simple);
1211 	g_object_unref (simple);
1212 }
1213 
1214 void
1215 e_source_config_commit (ESourceConfig *config,
1216                         GCancellable *cancellable,
1217                         GAsyncReadyCallback callback,
1218                         gpointer user_data)
1219 {
1220 	GSimpleAsyncResult *simple;
1221 	ESourceRegistry *registry;
1222 	Candidate *candidate;
1223 
1224 	g_return_if_fail (E_IS_SOURCE_CONFIG (config));
1225 
1226 	registry = e_source_config_get_registry (config);
1227 
1228 	candidate = source_config_get_active_candidate (config);
1229 	g_return_if_fail (candidate != NULL);
1230 
1231 	e_source_config_backend_commit_changes (
1232 		candidate->backend, candidate->scratch_source);
1233 
1234 	g_signal_emit (
1235 		config, signals[COMMIT_CHANGES], 0,
1236 		candidate->scratch_source);
1237 
1238 	simple = g_simple_async_result_new (
1239 		G_OBJECT (config), callback,
1240 		user_data, e_source_config_commit);
1241 
1242 	e_source_registry_commit_source (
1243 		registry, candidate->scratch_source,
1244 		cancellable, source_config_commit_cb, simple);
1245 }
1246 
1247 gboolean
1248 e_source_config_commit_finish (ESourceConfig *config,
1249                                GAsyncResult *result,
1250                                GError **error)
1251 {
1252 	GSimpleAsyncResult *simple;
1253 
1254 	g_return_val_if_fail (
1255 		g_simple_async_result_is_valid (
1256 		result, G_OBJECT (config),
1257 		e_source_config_commit), FALSE);
1258 
1259 	simple = G_SIMPLE_ASYNC_RESULT (result);
1260 
1261 	/* Assume success unless a GError is set. */
1262 	return !g_simple_async_result_propagate_error (simple, error);
1263 }
1264 
1265 void
1266 e_source_config_add_refresh_interval (ESourceConfig *config,
1267                                       ESource *scratch_source)
1268 {
1269 	GtkWidget *widget;
1270 	GtkWidget *container;
1271 	ESourceExtension *extension;
1272 	const gchar *extension_name;
1273 
1274 	g_return_if_fail (E_IS_SOURCE_CONFIG (config));
1275 	g_return_if_fail (E_IS_SOURCE (scratch_source));
1276 
1277 	extension_name = E_SOURCE_EXTENSION_REFRESH;
1278 	extension = e_source_get_extension (scratch_source, extension_name);
1279 
1280 	widget = gtk_alignment_new (0.0, 0.5, 0.0, 0.0);
1281 	e_source_config_insert_widget (config, scratch_source, NULL, widget);
1282 	gtk_widget_show (widget);
1283 
1284 	container = widget;
1285 
1286 	widget = gtk_hbox_new (FALSE, 6);
1287 	gtk_container_add (GTK_CONTAINER (container), widget);
1288 	gtk_widget_show (widget);
1289 
1290 	container = widget;
1291 
1292 	/* Translators: This is the first of a sequence of widgets:
1293 	 * "Refresh every [NUMERIC_ENTRY] [TIME_UNITS_COMBO]" */
1294 	widget = gtk_label_new (_("Refresh every"));
1295 	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
1296 	gtk_widget_show (widget);
1297 
1298 	widget = e_interval_chooser_new ();
1299 	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
1300 	gtk_widget_show (widget);
1301 
1302 	g_object_bind_property (
1303 		extension, "interval-minutes",
1304 		widget, "interval-minutes",
1305 		G_BINDING_BIDIRECTIONAL |
1306 		G_BINDING_SYNC_CREATE);
1307 }
1308 
1309 void
1310 e_source_config_add_secure_connection (ESourceConfig *config,
1311                                        ESource *scratch_source)
1312 {
1313 	GtkWidget *widget;
1314 	ESourceExtension *extension;
1315 	const gchar *extension_name;
1316 	const gchar *label;
1317 
1318 	g_return_if_fail (E_IS_SOURCE_CONFIG (config));
1319 	g_return_if_fail (E_IS_SOURCE (scratch_source));
1320 
1321 	extension_name = E_SOURCE_EXTENSION_SECURITY;
1322 	extension = e_source_get_extension (scratch_source, extension_name);
1323 
1324 	label = _("Use a secure connection");
1325 	widget = gtk_check_button_new_with_label (label);
1326 	e_source_config_insert_widget (config, scratch_source, NULL, widget);
1327 	gtk_widget_show (widget);
1328 
1329 	g_object_bind_property (
1330 		extension, "secure",
1331 		widget, "active",
1332 		G_BINDING_BIDIRECTIONAL |
1333 		G_BINDING_SYNC_CREATE);
1334 }
1335 
1336 static gboolean
1337 secure_to_port_cb (GBinding *binding,
1338                    const GValue *source_value,
1339                    GValue *target_value,
1340                    gpointer user_data)
1341 {
1342 	GObject *authentication_extension;
1343 	guint16 port;
1344 
1345 	authentication_extension = g_binding_get_target (binding);
1346 	g_object_get (authentication_extension, "port", &port, NULL);
1347 
1348 	if (port == 80 || port == 443 || port == 0)
1349 		port = g_value_get_boolean (source_value) ? 443 : 80;
1350 
1351 	g_value_set_uint (target_value, port);
1352 
1353 	return TRUE;
1354 }
1355 
1356 void
1357 e_source_config_add_secure_connection_for_webdav (ESourceConfig *config,
1358                                                   ESource *scratch_source)
1359 {
1360 	GtkWidget *widget1;
1361 	GtkWidget *widget2;
1362 	ESourceExtension *extension;
1363 	ESourceAuthentication *authentication_extension;
1364 	const gchar *extension_name;
1365 	const gchar *label;
1366 
1367 	g_return_if_fail (E_IS_SOURCE_CONFIG (config));
1368 	g_return_if_fail (E_IS_SOURCE (scratch_source));
1369 
1370 	extension_name = E_SOURCE_EXTENSION_SECURITY;
1371 	extension = e_source_get_extension (scratch_source, extension_name);
1372 
1373 	label = _("Use a secure connection");
1374 	widget1 = gtk_check_button_new_with_label (label);
1375 	e_source_config_insert_widget (config, scratch_source, NULL, widget1);
1376 	gtk_widget_show (widget1);
1377 
1378 	g_object_bind_property (
1379 		extension, "secure",
1380 		widget1, "active",
1381 		G_BINDING_BIDIRECTIONAL |
1382 		G_BINDING_SYNC_CREATE);
1383 
1384 	extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
1385 	authentication_extension = e_source_get_extension (scratch_source, extension_name);
1386 
1387 	g_object_bind_property_full (
1388 		extension, "secure",
1389 		authentication_extension, "port",
1390 		G_BINDING_DEFAULT,
1391 		secure_to_port_cb,
1392 		NULL, NULL, NULL);
1393 
1394 	extension_name = E_SOURCE_EXTENSION_WEBDAV_BACKEND;
1395 	extension = e_source_get_extension (scratch_source, extension_name);
1396 
1397 	label = _("Ignore invalid SSL certificate");
1398 	widget2 = gtk_check_button_new_with_label (label);
1399 	gtk_widget_set_margin_left (widget2, 24);
1400 	e_source_config_insert_widget (config, scratch_source, NULL, widget2);
1401 	gtk_widget_show (widget2);
1402 
1403 	g_object_bind_property (
1404 		widget1, "active",
1405 		widget2, "sensitive",
1406 		G_BINDING_SYNC_CREATE);
1407 
1408 	g_object_bind_property (
1409 		extension, "ignore-invalid-cert",
1410 		widget2, "active",
1411 		G_BINDING_BIDIRECTIONAL |
1412 		G_BINDING_SYNC_CREATE);
1413 }
1414 
1415 void
1416 e_source_config_add_user_entry (ESourceConfig *config,
1417                                 ESource *scratch_source)
1418 {
1419 	GtkWidget *widget;
1420 	ESource *original_source;
1421 	ESourceExtension *extension;
1422 	const gchar *extension_name;
1423 
1424 	g_return_if_fail (E_IS_SOURCE_CONFIG (config));
1425 	g_return_if_fail (E_IS_SOURCE (scratch_source));
1426 
1427 	extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
1428 	extension = e_source_get_extension (scratch_source, extension_name);
1429 
1430 	original_source = e_source_config_get_original_source (config);
1431 
1432 	widget = gtk_entry_new ();
1433 	e_source_config_insert_widget (
1434 		config, scratch_source, _("User"), widget);
1435 	gtk_widget_show (widget);
1436 
1437 	g_object_bind_property (
1438 		extension, "user",
1439 		widget, "text",
1440 		G_BINDING_BIDIRECTIONAL |
1441 		G_BINDING_SYNC_CREATE);
1442 
1443 	/* If this is a new data source, initialize the
1444 	 * GtkEntry to the user name of the current user. */
1445 	if (original_source == NULL)
1446 		gtk_entry_set_text (GTK_ENTRY (widget), g_get_user_name ());
1447 }