1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 
3 /* e-name-selector.c - Unified context for contact/destination selection UI.
4  *
5  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as published by
9  * the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  *
19  * Authors: Hans Petter Jansson <hpj@novell.com>
20  */
21 
22 #include "evolution-config.h"
23 
24 #include <string.h>
25 #include <gtk/gtk.h>
26 #include <glib/gi18n-lib.h>
27 
28 #include <libebook/libebook.h>
29 
30 #include "e-name-selector.h"
31 
32 #include "e-contact-store.h"
33 #include "e-destination-store.h"
34 
35 #define E_NAME_SELECTOR_GET_PRIVATE(obj) \
36 	(G_TYPE_INSTANCE_GET_PRIVATE \
37 	((obj), E_TYPE_NAME_SELECTOR, ENameSelectorPrivate))
38 
39 typedef struct {
40 	gchar *name;
41 	ENameSelectorEntry *entry;
42 } Section;
43 
44 typedef struct {
45 	EBookClient *client;
46 	guint is_completion_book : 1;
47 } SourceBook;
48 
49 struct _ENameSelectorPrivate {
50 	EClientCache *client_cache;
51 	ENameSelectorModel *model;
52 	ENameSelectorDialog *dialog;
53 
54 	GArray *sections;
55 
56 	gboolean books_loaded;
57 	GCancellable *cancellable;
58 	GArray *source_books;
59 };
60 
61 enum {
62 	PROP_0,
63 	PROP_CLIENT_CACHE
64 };
65 
G_DEFINE_TYPE(ENameSelector,e_name_selector,G_TYPE_OBJECT)66 G_DEFINE_TYPE (ENameSelector, e_name_selector, G_TYPE_OBJECT)
67 
68 static void
69 reset_pointer_cb (gpointer data,
70                   GObject *where_was)
71 {
72 	ENameSelector *name_selector = data;
73 	ENameSelectorPrivate *priv;
74 	guint ii;
75 
76 	g_return_if_fail (E_IS_NAME_SELECTOR (name_selector));
77 
78 	priv = E_NAME_SELECTOR_GET_PRIVATE (name_selector);
79 
80 	for (ii = 0; ii < priv->sections->len; ii++) {
81 		Section *section;
82 
83 		section = &g_array_index (priv->sections, Section, ii);
84 		if (section->entry == (ENameSelectorEntry *) where_was)
85 			section->entry = NULL;
86 	}
87 }
88 
89 static void
name_selector_get_client_cb(GObject * source_object,GAsyncResult * result,gpointer user_data)90 name_selector_get_client_cb (GObject *source_object,
91                              GAsyncResult *result,
92                              gpointer user_data)
93 {
94 	ENameSelector *name_selector = user_data;
95 	EBookClient *book_client;
96 	EClient *client;
97 	GArray *sections;
98 	SourceBook source_book;
99 	guint ii;
100 	gboolean ignore_error;
101 	GError *error = NULL;
102 
103 	client = e_client_cache_get_client_finish (
104 		E_CLIENT_CACHE (source_object), result, &error);
105 
106 	/* Sanity check. */
107 	g_return_if_fail (
108 		((client != NULL) && (error == NULL)) ||
109 		((client == NULL) && (error != NULL)));
110 
111 	ignore_error =
112 		g_error_matches (
113 			error, E_CLIENT_ERROR,
114 			E_CLIENT_ERROR_REPOSITORY_OFFLINE) ||
115 		g_error_matches (
116 			error, E_CLIENT_ERROR,
117 			E_CLIENT_ERROR_OFFLINE_UNAVAILABLE) ||
118 		g_error_matches (
119 			error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
120 
121 	if (error != NULL) {
122 		if (!ignore_error)
123 			g_warning ("%s: %s", G_STRFUNC, error->message);
124 		g_error_free (error);
125 		goto exit;
126 	}
127 
128 	book_client = E_BOOK_CLIENT (client);
129 	g_return_if_fail (E_IS_BOOK_CLIENT (book_client));
130 
131 	source_book.client = book_client;
132 	source_book.is_completion_book = TRUE;
133 
134 	g_array_append_val (name_selector->priv->source_books, source_book);
135 
136 	sections = name_selector->priv->sections;
137 
138 	for (ii = 0; ii < sections->len; ii++) {
139 		EContactStore *store;
140 		Section *section;
141 
142 		section = &g_array_index (sections, Section, ii);
143 		if (section->entry == NULL)
144 			continue;
145 
146 		store = e_name_selector_entry_peek_contact_store (
147 			section->entry);
148 		if (store != NULL)
149 			e_contact_store_add_client (store, book_client);
150 	}
151 
152  exit:
153 	g_object_unref (name_selector);
154 }
155 
156 /**
157  * e_name_selector_load_books:
158  * @name_selector: an #ENameSelector
159  *
160  * Loads address books available for the @name_selector.
161  * This can be called only once and it can be cancelled
162  * by e_name_selector_cancel_loading().
163  *
164  * Since: 3.2
165  **/
166 void
e_name_selector_load_books(ENameSelector * name_selector)167 e_name_selector_load_books (ENameSelector *name_selector)
168 {
169 	EClientCache *client_cache;
170 	ESourceRegistry *registry;
171 	GList *list, *iter;
172 	const gchar *extension_name;
173 
174 	g_return_if_fail (E_IS_NAME_SELECTOR (name_selector));
175 
176 	extension_name = E_SOURCE_EXTENSION_ADDRESS_BOOK;
177 	client_cache = e_name_selector_ref_client_cache (name_selector);
178 	registry = e_client_cache_ref_registry (client_cache);
179 
180 	list = e_source_registry_list_enabled (registry, extension_name);
181 
182 	for (iter = list; iter != NULL; iter = g_list_next (iter)) {
183 		ESource *source = E_SOURCE (iter->data);
184 		ESourceAutocomplete *extension;
185 		const gchar *extension_name;
186 
187 		extension_name = E_SOURCE_EXTENSION_AUTOCOMPLETE;
188 		extension = e_source_get_extension (source, extension_name);
189 
190 		/* Only load address books with autocomplete enabled,
191 		 * so as to avoid unnecessary authentication prompts. */
192 		if (!e_source_autocomplete_get_include_me (extension))
193 			continue;
194 
195 		/* FIXME GCancellable is only to be used for one
196 		 *       operation at a time, not for multiple
197 		 *       concurrent operations like this. */
198 		e_client_cache_get_client (
199 			client_cache, source,
200 			E_SOURCE_EXTENSION_ADDRESS_BOOK, (guint32) -1,
201 			name_selector->priv->cancellable,
202 			name_selector_get_client_cb,
203 			g_object_ref (name_selector));
204 	}
205 
206 	g_list_free_full (list, (GDestroyNotify) g_object_unref);
207 
208 	g_object_unref (registry);
209 	g_object_unref (client_cache);
210 }
211 
212 /**
213  * e_name_selector_cancel_loading:
214  * @name_selector: an #ENameSelector
215  *
216  * Cancels any pending address book load operations. This might be called
217  * before an owner unrefs this @name_selector.
218  *
219  * Since: 3.2
220  **/
221 void
e_name_selector_cancel_loading(ENameSelector * name_selector)222 e_name_selector_cancel_loading (ENameSelector *name_selector)
223 {
224 	g_return_if_fail (E_IS_NAME_SELECTOR (name_selector));
225 	g_return_if_fail (name_selector->priv->cancellable != NULL);
226 
227 	g_cancellable_cancel (name_selector->priv->cancellable);
228 }
229 
230 static void
name_selector_set_client_cache(ENameSelector * name_selector,EClientCache * client_cache)231 name_selector_set_client_cache (ENameSelector *name_selector,
232                                 EClientCache *client_cache)
233 {
234 	g_return_if_fail (E_IS_CLIENT_CACHE (client_cache));
235 	g_return_if_fail (name_selector->priv->client_cache == NULL);
236 
237 	name_selector->priv->client_cache = g_object_ref (client_cache);
238 }
239 
240 static void
name_selector_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)241 name_selector_set_property (GObject *object,
242                             guint property_id,
243                             const GValue *value,
244                             GParamSpec *pspec)
245 {
246 	switch (property_id) {
247 		case PROP_CLIENT_CACHE:
248 			name_selector_set_client_cache (
249 				E_NAME_SELECTOR (object),
250 				g_value_get_object (value));
251 			return;
252 	}
253 
254 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
255 }
256 
257 static void
name_selector_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)258 name_selector_get_property (GObject *object,
259                             guint property_id,
260                             GValue *value,
261                             GParamSpec *pspec)
262 {
263 	switch (property_id) {
264 		case PROP_CLIENT_CACHE:
265 			g_value_take_object (
266 				value,
267 				e_name_selector_ref_client_cache (
268 				E_NAME_SELECTOR (object)));
269 			return;
270 	}
271 
272 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
273 }
274 
275 static void
name_selector_dispose(GObject * object)276 name_selector_dispose (GObject *object)
277 {
278 	ENameSelectorPrivate *priv;
279 	guint ii;
280 
281 	priv = E_NAME_SELECTOR_GET_PRIVATE (object);
282 
283 	if (priv->cancellable) {
284 		g_cancellable_cancel (priv->cancellable);
285 		g_object_unref (priv->cancellable);
286 		priv->cancellable = NULL;
287 	}
288 
289 	for (ii = 0; ii < priv->source_books->len; ii++) {
290 		SourceBook *source_book;
291 
292 		source_book = &g_array_index (
293 			priv->source_books, SourceBook, ii);
294 		if (source_book->client != NULL)
295 			g_object_unref (source_book->client);
296 	}
297 
298 	for (ii = 0; ii < priv->sections->len; ii++) {
299 		Section *section;
300 
301 		section = &g_array_index (priv->sections, Section, ii);
302 		if (section->entry)
303 			g_object_weak_unref (
304 				G_OBJECT (section->entry),
305 				reset_pointer_cb, object);
306 		g_free (section->name);
307 	}
308 
309 	g_array_set_size (priv->source_books, 0);
310 	g_array_set_size (priv->sections, 0);
311 
312 	if (priv->dialog) {
313 		gtk_widget_destroy (GTK_WIDGET (priv->dialog));
314 		priv->dialog = NULL;
315 	}
316 
317 	g_clear_object (&priv->model);
318 
319 	/* Chain up to parent's dispose() method. */
320 	G_OBJECT_CLASS (e_name_selector_parent_class)->dispose (object);
321 }
322 
323 static void
name_selector_finalize(GObject * object)324 name_selector_finalize (GObject *object)
325 {
326 	ENameSelectorPrivate *priv;
327 
328 	priv = E_NAME_SELECTOR_GET_PRIVATE (object);
329 
330 	g_array_free (priv->source_books, TRUE);
331 	g_array_free (priv->sections, TRUE);
332 
333 	/* Chain up to parent's finalize() method. */
334 	G_OBJECT_CLASS (e_name_selector_parent_class)->finalize (object);
335 }
336 
337 static void
e_name_selector_class_init(ENameSelectorClass * class)338 e_name_selector_class_init (ENameSelectorClass *class)
339 {
340 	GObjectClass *object_class;
341 
342 	g_type_class_add_private (class, sizeof (ENameSelectorPrivate));
343 
344 	object_class = G_OBJECT_CLASS (class);
345 	object_class->set_property = name_selector_set_property;
346 	object_class->get_property = name_selector_get_property;
347 	object_class->dispose = name_selector_dispose;
348 	object_class->finalize = name_selector_finalize;
349 
350 	/**
351 	 * ENameSelector:client-cache:
352 	 *
353 	 * Cache of shared #EClient instances.
354 	 **/
355 	g_object_class_install_property (
356 		object_class,
357 		PROP_CLIENT_CACHE,
358 		g_param_spec_object (
359 			"client-cache",
360 			"Client Cache",
361 			"Cache of shared EClient instances",
362 			E_TYPE_CLIENT_CACHE,
363 			G_PARAM_READWRITE |
364 			G_PARAM_CONSTRUCT_ONLY |
365 			G_PARAM_STATIC_STRINGS));
366 }
367 
368 static void
e_name_selector_init(ENameSelector * name_selector)369 e_name_selector_init (ENameSelector *name_selector)
370 {
371 	GArray *sections;
372 	GArray *source_books;
373 
374 	sections = g_array_new (FALSE, FALSE, sizeof (Section));
375 	source_books = g_array_new (FALSE, FALSE, sizeof (SourceBook));
376 
377 	name_selector->priv = E_NAME_SELECTOR_GET_PRIVATE (name_selector);
378 	name_selector->priv->sections = sections;
379 	name_selector->priv->model = e_name_selector_model_new ();
380 	name_selector->priv->source_books = source_books;
381 	name_selector->priv->cancellable = g_cancellable_new ();
382 	name_selector->priv->books_loaded = FALSE;
383 }
384 
385 /**
386  * e_name_selector_new:
387  * @client_cache: an #EClientCache
388  *
389  * Creates a new #ENameSelector.
390  *
391  * Returns: A new #ENameSelector.
392  **/
393 ENameSelector *
e_name_selector_new(EClientCache * client_cache)394 e_name_selector_new (EClientCache *client_cache)
395 {
396 	g_return_val_if_fail (E_IS_CLIENT_CACHE (client_cache), NULL);
397 
398 	return g_object_new (
399 		E_TYPE_NAME_SELECTOR,
400 		"client-cache", client_cache, NULL);
401 }
402 
403 /**
404  * e_name_selector_ref_client_cache:
405  * @name_selector: an #ENameSelector
406  *
407  * Returns the #EClientCache passed to e_name_selector_new().
408  *
409  * The returned #EClientCache is referenced for thread-safety and must be
410  * unreferenced with g_object_unref() when finished with it.
411  *
412  * Returns: an #EClientCache
413  *
414  * Since: 3.8
415  **/
416 EClientCache *
e_name_selector_ref_client_cache(ENameSelector * name_selector)417 e_name_selector_ref_client_cache (ENameSelector *name_selector)
418 {
419 	g_return_val_if_fail (E_IS_NAME_SELECTOR (name_selector), NULL);
420 
421 	return g_object_ref (name_selector->priv->client_cache);
422 }
423 
424 /* ------- *
425  * Helpers *
426  * ------- */
427 
428 static gint
add_section(ENameSelector * name_selector,const gchar * name)429 add_section (ENameSelector *name_selector,
430              const gchar *name)
431 {
432 	GArray *array;
433 	Section section;
434 
435 	g_return_val_if_fail (name != NULL, -1);
436 
437 	memset (&section, 0, sizeof (Section));
438 	section.name = g_strdup (name);
439 
440 	array = name_selector->priv->sections;
441 	g_array_append_val (array, section);
442 	return array->len - 1;
443 }
444 
445 static gint
find_section_by_name(ENameSelector * name_selector,const gchar * name)446 find_section_by_name (ENameSelector *name_selector,
447                       const gchar *name)
448 {
449 	GArray *array;
450 	gint i;
451 
452 	g_return_val_if_fail (name != NULL, -1);
453 
454 	array = name_selector->priv->sections;
455 
456 	for (i = 0; i < array->len; i++) {
457 		Section *section = &g_array_index (array, Section, i);
458 
459 		if (!strcmp (name, section->name))
460 			return i;
461 	}
462 
463 	return -1;
464 }
465 
466 /* ----------------- *
467  * ENameSelector API *
468  * ----------------- */
469 
470 /**
471  * e_name_selector_peek_model:
472  * @name_selector: an #ENameSelector
473  *
474  * Gets the #ENameSelectorModel used by @name_selector.
475  *
476  * Returns: The #ENameSelectorModel used by @name_selector.
477  **/
478 ENameSelectorModel *
e_name_selector_peek_model(ENameSelector * name_selector)479 e_name_selector_peek_model (ENameSelector *name_selector)
480 {
481 	g_return_val_if_fail (E_IS_NAME_SELECTOR (name_selector), NULL);
482 
483 	return name_selector->priv->model;
484 }
485 
486 /**
487  * e_name_selector_peek_dialog:
488  * @name_selector: an #ENameSelector
489  *
490  * Gets the #ENameSelectorDialog used by @name_selector.
491  *
492  * Returns: The #ENameSelectorDialog used by @name_selector.
493  **/
494 ENameSelectorDialog *
e_name_selector_peek_dialog(ENameSelector * name_selector)495 e_name_selector_peek_dialog (ENameSelector *name_selector)
496 {
497 	g_return_val_if_fail (E_IS_NAME_SELECTOR (name_selector), NULL);
498 
499 	if (name_selector->priv->dialog == NULL) {
500 		EClientCache *client_cache;
501 		ENameSelectorDialog *dialog;
502 		ENameSelectorModel *model;
503 
504 		client_cache = e_name_selector_ref_client_cache (name_selector);
505 		dialog = e_name_selector_dialog_new (client_cache);
506 		name_selector->priv->dialog = dialog;
507 		g_object_unref (client_cache);
508 
509 		model = e_name_selector_peek_model (name_selector);
510 		e_name_selector_dialog_set_model (dialog, model);
511 
512 		g_signal_connect (
513 			dialog, "delete-event",
514 			G_CALLBACK (gtk_widget_hide_on_delete), name_selector);
515 	}
516 
517 	return name_selector->priv->dialog;
518 }
519 
520 /**
521  * e_name_selector_show_dialog:
522  * @name_selector: an #ENameSelector
523  * @for_transient_widget: a widget parent or %NULL
524  *
525  * Shows the associated dialog, and sets the transient parent to the
526  * GtkWindow top-level of "for_transient_widget if set (it should be)
527  *
528  * Since: 2.32
529  **/
530 void
e_name_selector_show_dialog(ENameSelector * name_selector,GtkWidget * for_transient_widget)531 e_name_selector_show_dialog (ENameSelector *name_selector,
532                              GtkWidget *for_transient_widget)
533 {
534 	GtkWindow *top = NULL;
535 	ENameSelectorDialog *dialog;
536 
537 	g_return_if_fail (E_IS_NAME_SELECTOR (name_selector));
538 
539 	dialog = e_name_selector_peek_dialog (name_selector);
540 	if (for_transient_widget)
541 		top = GTK_WINDOW (gtk_widget_get_toplevel (for_transient_widget));
542 	if (top)
543 		gtk_window_set_transient_for (GTK_WINDOW (dialog), top);
544 
545 	gtk_widget_show (GTK_WIDGET (dialog));
546 }
547 
548 /**
549  * e_name_selector_peek_section_entry:
550  * @name_selector: an #ENameSelector
551  * @name: the name of the section to peek
552  *
553  * Gets the #ENameSelectorEntry for the section specified by @name.
554  *
555  * Returns: The #ENameSelectorEntry for the named section, or %NULL if it
556  * doesn't exist in the #ENameSelectorModel.
557  **/
558 ENameSelectorEntry *
e_name_selector_peek_section_entry(ENameSelector * name_selector,const gchar * name)559 e_name_selector_peek_section_entry (ENameSelector *name_selector,
560                                     const gchar *name)
561 {
562 	ENameSelectorPrivate *priv;
563 	ENameSelectorModel *model;
564 	EDestinationStore *destination_store;
565 	Section *section;
566 	gint     n;
567 
568 	g_return_val_if_fail (E_IS_NAME_SELECTOR (name_selector), NULL);
569 	g_return_val_if_fail (name != NULL, NULL);
570 
571 	priv = E_NAME_SELECTOR_GET_PRIVATE (name_selector);
572 	model = e_name_selector_peek_model (name_selector);
573 
574 	if (!e_name_selector_model_peek_section (
575 		model, name, NULL, &destination_store))
576 		return NULL;
577 
578 	n = find_section_by_name (name_selector, name);
579 	if (n < 0)
580 		n = add_section (name_selector, name);
581 
582 	section = &g_array_index (name_selector->priv->sections, Section, n);
583 
584 	if (!section->entry) {
585 		EClientCache *client_cache;
586 		EContactStore *contact_store;
587 		GtkWidget *widget;
588 		gchar         *text;
589 		gint           i;
590 
591 		client_cache = e_name_selector_ref_client_cache (name_selector);
592 		widget = e_name_selector_entry_new (client_cache);
593 		section->entry = E_NAME_SELECTOR_ENTRY (widget);
594 		g_object_unref (client_cache);
595 
596 		g_object_weak_ref (G_OBJECT (section->entry), reset_pointer_cb, name_selector);
597 		if (pango_parse_markup (name, -1, '_', NULL,
598 					&text, NULL, NULL))  {
599 			atk_object_set_name (gtk_widget_get_accessible (GTK_WIDGET (section->entry)), text);
600 			g_free (text);
601 		}
602 		e_name_selector_entry_set_destination_store (section->entry, destination_store);
603 
604 		/* Create a contact store for the entry and assign our already-open books to it */
605 
606 		contact_store = e_contact_store_new ();
607 
608 		for (i = 0; i < priv->source_books->len; i++) {
609 			SourceBook *source_book = &g_array_index (priv->source_books, SourceBook, i);
610 
611 			if (source_book->is_completion_book && source_book->client)
612 				e_contact_store_add_client (contact_store, source_book->client);
613 		}
614 
615 		e_name_selector_entry_set_contact_store (section->entry, contact_store);
616 		g_object_unref (contact_store);
617 	}
618 
619 	return section->entry;
620 }
621 
622 /**
623  * e_name_selector_peek_section_list:
624  * @name_selector: an #ENameSelector
625  * @name: the name of the section to peek
626  *
627  * Gets the #ENameSelectorList for the section specified by @name.
628  *
629  * Returns: The #ENameSelectorList for the named section, or %NULL if it
630  * doesn't exist in the #ENameSelectorModel.
631  **/
632 
633 ENameSelectorList *
e_name_selector_peek_section_list(ENameSelector * name_selector,const gchar * name)634 e_name_selector_peek_section_list (ENameSelector *name_selector,
635                                    const gchar *name)
636 {
637 	ENameSelectorPrivate *priv;
638 	ENameSelectorModel *model;
639 	EDestinationStore *destination_store;
640 	Section *section;
641 	gint     n;
642 
643 	g_return_val_if_fail (E_IS_NAME_SELECTOR (name_selector), NULL);
644 	g_return_val_if_fail (name != NULL, NULL);
645 
646 	priv = E_NAME_SELECTOR_GET_PRIVATE (name_selector);
647 	model = e_name_selector_peek_model (name_selector);
648 
649 	if (!e_name_selector_model_peek_section (
650 		model, name, NULL, &destination_store))
651 		return NULL;
652 
653 	n = find_section_by_name (name_selector, name);
654 	if (n < 0)
655 		n = add_section (name_selector, name);
656 
657 	section = &g_array_index (name_selector->priv->sections, Section, n);
658 
659 	if (!section->entry) {
660 		EContactStore *contact_store;
661 		EClientCache *client_cache;
662 		GtkWidget *widget;
663 		gchar         *text;
664 		gint           i;
665 
666 		client_cache = e_name_selector_ref_client_cache (name_selector);
667 		widget = e_name_selector_list_new (client_cache);
668 		section->entry = E_NAME_SELECTOR_ENTRY (widget);
669 		g_object_unref (client_cache);
670 
671 		g_object_weak_ref (G_OBJECT (section->entry), reset_pointer_cb, name_selector);
672 		if (pango_parse_markup (name, -1, '_', NULL,
673 					&text, NULL, NULL))  {
674 			atk_object_set_name (gtk_widget_get_accessible (GTK_WIDGET (section->entry)), text);
675 			g_free (text);
676 		}
677 		e_name_selector_entry_set_destination_store (section->entry, destination_store);
678 
679 		/* Create a contact store for the entry and assign our already-open books to it */
680 
681 		contact_store = e_contact_store_new ();
682 		for (i = 0; i < priv->source_books->len; i++) {
683 			SourceBook *source_book = &g_array_index (priv->source_books, SourceBook, i);
684 
685 			if (source_book->is_completion_book && source_book->client)
686 				e_contact_store_add_client (contact_store, source_book->client);
687 		}
688 
689 		e_name_selector_entry_set_contact_store (section->entry, contact_store);
690 		g_object_unref (contact_store);
691 	}
692 
693 	return (ENameSelectorList *) section->entry;
694 }
695