1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 
3 /* e-source-backend-summary-setup.c - Backend Summary Data Configuration.
4  *
5  * Copyright (C) 2012 Intel Corporation
6  *
7  * This library 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 library 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 Lesser 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 library. If not, see <http://www.gnu.org/licenses/>.
18  *
19  * Authors: Tristan Van Berkom <tristanvb@openismus.com>
20  */
21 
22 /**
23  * SECTION: e-source-backend-summary-setup
24  * @include: libebook-contacts/libebook-contacts.h
25  * @short_description: #ESource extension to configure summary fields
26  *
27  * The #ESourceBackendSummarySetup extension configures which #EContactFields
28  * should be in the summary and which of those fields should be optimized for
29  * quicker search results.
30  *
31  * Access the extension as follows:
32  *
33  * |[
34  *   #include <libebook-contacts/libebook-contacts.h>
35  *
36  *   ESourceBackendSummarySetup *extension;
37  *
38  *   extension = e_source_get_extension (source, E_SOURCE_EXTENSION_BACKEND_SUMMARY_SETUP);
39  * ]|
40  *
41  * <note><para>The summary configuration is expected to be setup in only one way for
42  * a given #ESource at creation time. Any configurations made after creation of the
43  * book in question will be ignored.</para></note>
44  *
45  **/
46 
47 #include "e-source-backend-summary-setup.h"
48 #include "e-book-contacts-enumtypes.h"
49 
50 struct _ESourceBackendSummarySetupPrivate {
51 	GMutex  property_lock;
52 	gchar  *summary_fields;
53 	gchar  *indexed_fields;
54 };
55 
56 enum {
57 	PROP_0,
58 	PROP_SUMMARY_FIELDS,
59 	PROP_INDEXED_FIELDS
60 };
61 
G_DEFINE_TYPE_WITH_PRIVATE(ESourceBackendSummarySetup,e_source_backend_summary_setup,E_TYPE_SOURCE_EXTENSION)62 G_DEFINE_TYPE_WITH_PRIVATE (
63 	ESourceBackendSummarySetup,
64 	e_source_backend_summary_setup,
65 	E_TYPE_SOURCE_EXTENSION)
66 
67 static gchar *
68 source_backend_summary_setup_dup_literal_fields (ESourceBackendSummarySetup *extension,
69                                                  gint which)
70 {
71 	gchar *duplicate = NULL;
72 
73 	g_mutex_lock (&extension->priv->property_lock);
74 
75 	switch (which) {
76 		case PROP_SUMMARY_FIELDS:
77 			duplicate = g_strdup (extension->priv->summary_fields);
78 			break;
79 		case PROP_INDEXED_FIELDS:
80 			duplicate = g_strdup (extension->priv->indexed_fields);
81 			break;
82 		default:
83 			g_return_val_if_reached (NULL);
84 			break;
85 	}
86 
87 	g_mutex_unlock (&extension->priv->property_lock);
88 
89 	return duplicate;
90 }
91 
92 static void
source_backend_summary_setup_set_literal_fields(ESourceBackendSummarySetup * extension,const gchar * literal_fields,gint which)93 source_backend_summary_setup_set_literal_fields (ESourceBackendSummarySetup *extension,
94                                                  const gchar *literal_fields,
95                                                  gint which)
96 {
97 	const gchar *property_name;
98 	gchar **target;
99 
100 	switch (which) {
101 		case PROP_SUMMARY_FIELDS:
102 			target = &(extension->priv->summary_fields);
103 			property_name = "summary-fields";
104 			break;
105 		case PROP_INDEXED_FIELDS:
106 			target = &(extension->priv->indexed_fields);
107 			property_name = "indexed-fields";
108 			break;
109 		default:
110 			g_return_if_reached ();
111 			break;
112 	}
113 
114 	g_mutex_lock (&extension->priv->property_lock);
115 
116 	if (e_util_strcmp0 (*target, literal_fields) == 0) {
117 		g_mutex_unlock (&extension->priv->property_lock);
118 		return;
119 	}
120 
121 	g_free (*target);
122 	*target = e_util_strdup_strip (literal_fields);
123 
124 	g_mutex_unlock (&extension->priv->property_lock);
125 
126 	g_object_notify (G_OBJECT (extension), property_name);
127 }
128 
129 static void
source_backend_summary_setup_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)130 source_backend_summary_setup_set_property (GObject *object,
131                                          guint property_id,
132                                          const GValue *value,
133                                          GParamSpec *pspec)
134 {
135 	switch (property_id) {
136 		case PROP_SUMMARY_FIELDS:
137 		case PROP_INDEXED_FIELDS:
138 			source_backend_summary_setup_set_literal_fields (
139 				E_SOURCE_BACKEND_SUMMARY_SETUP (object),
140 				g_value_get_string (value), property_id);
141 			return;
142 	}
143 
144 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
145 }
146 
147 static void
source_backend_summary_setup_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)148 source_backend_summary_setup_get_property (GObject *object,
149                                          guint property_id,
150                                          GValue *value,
151                                          GParamSpec *pspec)
152 {
153 	switch (property_id) {
154 		case PROP_SUMMARY_FIELDS:
155 		case PROP_INDEXED_FIELDS:
156 			g_value_take_string (
157 				value,
158 				source_backend_summary_setup_dup_literal_fields (
159 				E_SOURCE_BACKEND_SUMMARY_SETUP (object),
160 				property_id));
161 			return;
162 	}
163 
164 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
165 }
166 
167 static void
source_backend_summary_setup_finalize(GObject * object)168 source_backend_summary_setup_finalize (GObject *object)
169 {
170 	ESourceBackendSummarySetupPrivate *priv;
171 
172 	priv = E_SOURCE_BACKEND_SUMMARY_SETUP (object)->priv;
173 
174 	g_mutex_clear (&priv->property_lock);
175 	g_free (priv->summary_fields);
176 	g_free (priv->indexed_fields);
177 
178 	/* Chain up to parent's finalize() method. */
179 	G_OBJECT_CLASS (e_source_backend_summary_setup_parent_class)->
180 		finalize (object);
181 }
182 
183 static void
e_source_backend_summary_setup_class_init(ESourceBackendSummarySetupClass * class)184 e_source_backend_summary_setup_class_init (ESourceBackendSummarySetupClass *class)
185 {
186 	GObjectClass *object_class;
187 	ESourceExtensionClass *extension_class;
188 
189 	object_class = G_OBJECT_CLASS (class);
190 	object_class->get_property = source_backend_summary_setup_get_property;
191 	object_class->set_property = source_backend_summary_setup_set_property;
192 	object_class->finalize = source_backend_summary_setup_finalize;
193 
194 	extension_class = E_SOURCE_EXTENSION_CLASS (class);
195 	extension_class->name = E_SOURCE_EXTENSION_BACKEND_SUMMARY_SETUP;
196 
197 	g_object_class_install_property (
198 		object_class,
199 		PROP_SUMMARY_FIELDS,
200 		g_param_spec_string (
201 			"summary-fields",
202 			"Summary Fields",
203 			"The list of quick reference summary fields",
204 			NULL,
205 			G_PARAM_READWRITE |
206 			G_PARAM_CONSTRUCT |
207 			G_PARAM_EXPLICIT_NOTIFY |
208 			G_PARAM_STATIC_STRINGS |
209 			E_SOURCE_PARAM_SETTING));
210 
211 	g_object_class_install_property (
212 		object_class,
213 		PROP_INDEXED_FIELDS,
214 		g_param_spec_string (
215 			"indexed-fields",
216 			"Indexed Fields",
217 			"The list of summary fields which are to be "
218 			"given indexes in the underlying database",
219 			NULL,
220 			G_PARAM_READWRITE |
221 			G_PARAM_CONSTRUCT |
222 			G_PARAM_EXPLICIT_NOTIFY |
223 			G_PARAM_STATIC_STRINGS |
224 			E_SOURCE_PARAM_SETTING));
225 }
226 
227 static void
e_source_backend_summary_setup_init(ESourceBackendSummarySetup * extension)228 e_source_backend_summary_setup_init (ESourceBackendSummarySetup *extension)
229 {
230 	extension->priv = e_source_backend_summary_setup_get_instance_private (extension);
231 	g_mutex_init (&extension->priv->property_lock);
232 }
233 
234 static EContactField *
source_backend_summary_setup_get_fields_array(ESourceBackendSummarySetup * extension,gint * n_fields,gint which)235 source_backend_summary_setup_get_fields_array (ESourceBackendSummarySetup *extension,
236                                                gint *n_fields,
237                                                gint which)
238 {
239 	EContactField field;
240 	EContactField *fields = NULL;
241 	gchar *literal_fields;
242 	gchar **split = NULL;
243 	gint n_ret_fields = 0, i;
244 
245 	literal_fields = source_backend_summary_setup_dup_literal_fields (extension, which);
246 
247 	if (literal_fields)
248 		split = g_strsplit (literal_fields, ":", 0);
249 
250 	if (split) {
251 		n_ret_fields = g_strv_length (split);
252 		fields = g_new (EContactField, n_ret_fields);
253 
254 		for (i = 0; i < n_ret_fields; i++) {
255 			field = e_contact_field_id (split[i]);
256 
257 			if (field == 0)
258 				g_warning ("Unrecognized field '%s' in ESourceBackendSummarySetup fields", split[i]);
259 
260 			fields[i] = field;
261 		}
262 
263 		g_strfreev (split);
264 	}
265 
266 	g_free (literal_fields);
267 
268 	*n_fields = n_ret_fields;
269 
270 	return fields;
271 }
272 
273 static void
e_source_backend_summary_setup_set_fields_array(ESourceBackendSummarySetup * extension,EContactField * fields,gint n_fields,gint which)274 e_source_backend_summary_setup_set_fields_array (ESourceBackendSummarySetup *extension,
275                                                  EContactField *fields,
276                                                  gint n_fields,
277                                                  gint which)
278 {
279 	gint i;
280 	GString *string;
281 	gboolean malformed = FALSE;
282 
283 	string = g_string_new ("");
284 
285 	for (i = 0; i < n_fields; i++) {
286 		const gchar *field_name = e_contact_field_name (fields[i]);
287 
288 		if (field_name == NULL) {
289 			g_warning ("Invalid EContactField given to ESourceBackendSummarySetup");
290 			malformed = TRUE;
291 			break;
292 		}
293 
294 		if (i > 0)
295 			g_string_append_c (string, ':');
296 
297 		g_string_append (string, field_name);
298 	}
299 
300 	if (malformed == FALSE)
301 		source_backend_summary_setup_set_literal_fields (extension, string->str, which);
302 
303 	g_string_free (string, TRUE);
304 }
305 
306 static void
e_source_backend_summary_setup_set_fields_va_list(ESourceBackendSummarySetup * extension,va_list var_args,gint which)307 e_source_backend_summary_setup_set_fields_va_list (ESourceBackendSummarySetup *extension,
308                                                    va_list var_args,
309                                                    gint which)
310 {
311 	GString *string;
312 	gboolean malformed = FALSE, first_field = TRUE;
313 	EContactField field;
314 
315 	string = g_string_new ("");
316 
317 	field = va_arg (var_args, EContactField);
318 	while (field > 0) {
319 		const gchar *field_name = e_contact_field_name (field);
320 
321 		if (field_name == NULL) {
322 			g_warning ("Invalid EContactField given to ESourceBackendSummarySetup");
323 			malformed = TRUE;
324 			break;
325 		}
326 
327 		if (!first_field)
328 			g_string_append_c (string, ':');
329 		else
330 			first_field = FALSE;
331 
332 		g_string_append (string, field_name);
333 
334 		field = va_arg (var_args, EContactField);
335 	}
336 
337 	if (malformed == FALSE)
338 		source_backend_summary_setup_set_literal_fields (extension, string->str, which);
339 
340 	g_string_free (string, TRUE);
341 }
342 
343 /**
344  * e_source_backend_summary_setup_get_summary_fields:
345  * @extension: An #ESourceBackendSummarySetup
346  * @n_fields: (out): A return location for the number of #EContactFields in the returned array.
347  *
348  * Fetches the #EContactFields which are configured to be a part of the summary.
349  *
350  * <note><para>If there are no configured summary fields, the default configuration is assumed</para></note>
351  *
352  * Returns: (transfer full): An array of #EContactFields @n_fields long, should be freed with g_free() when done.
353  *
354  * Since: 3.8
355  */
356 EContactField *
e_source_backend_summary_setup_get_summary_fields(ESourceBackendSummarySetup * extension,gint * n_fields)357 e_source_backend_summary_setup_get_summary_fields (ESourceBackendSummarySetup *extension,
358                                                    gint *n_fields)
359 {
360 	g_return_val_if_fail (E_IS_SOURCE_BACKEND_SUMMARY_SETUP (extension), NULL);
361 	g_return_val_if_fail (n_fields != NULL, NULL);
362 
363 	return source_backend_summary_setup_get_fields_array (extension, n_fields, PROP_SUMMARY_FIELDS);
364 }
365 
366 /**
367  * e_source_backend_summary_setup_set_summary_fieldsv:
368  * @extension: An #ESourceBackendSummarySetup
369  * @fields: The array of #EContactFields to set as summary fields
370  * @n_fields: The number of #EContactFields in @fields
371  *
372  * Sets the summary fields configured for the given addressbook.
373  *
374  * The fields %E_CONTACT_UID and %E_CONTACT_REV are not optional,
375  * they will be stored in the summary regardless of the configured summary.
376  *
377  * An empty summary configuration is assumed to be the default summary
378  * configuration.
379  *
380  * <note><para>Only #EContactFields with the type #G_TYPE_STRING or #G_TYPE_BOOLEAN
381  * are currently supported as summary fields.</para></note>
382  *
383  * Since: 3.8
384  */
385 void
e_source_backend_summary_setup_set_summary_fieldsv(ESourceBackendSummarySetup * extension,EContactField * fields,gint n_fields)386 e_source_backend_summary_setup_set_summary_fieldsv (ESourceBackendSummarySetup *extension,
387                                                     EContactField *fields,
388                                                     gint n_fields)
389 {
390 	g_return_if_fail (E_IS_SOURCE_BACKEND_SUMMARY_SETUP (extension));
391 	g_return_if_fail (n_fields >= 0);
392 
393 	e_source_backend_summary_setup_set_fields_array (extension, fields, n_fields, PROP_SUMMARY_FIELDS);
394 }
395 
396 /**
397  * e_source_backend_summary_setup_set_summary_fields:
398  * @extension: An #ESourceBackendSummarySetup
399  * @...: A 0 terminated list of #EContactFields to set as summary fields
400  *
401  * Like e_source_backend_summary_setup_set_summary_fieldsv(), but takes a literal
402  * list of #EContactFields for convenience.
403  *
404  * To configure the address book summary fields with main phone nubmer fields:
405  *
406  * |[
407  *   #include <libebook/libebook.h>
408  *
409  *   ESourceBackendSummarySetup *extension;
410  *
411  *   extension = e_source_get_extension (source, E_SOURCE_EXTENSION_BACKEND_SUMMARY_SETUP);
412  *
413  *   e_source_backend_summary_setup_set_summary_fields (extension, E_CONTACT_FULL_NAME, E_CONTACT_EMAIL, 0);
414  * ]|
415  *
416  * Since: 3.8
417  */
418 void
e_source_backend_summary_setup_set_summary_fields(ESourceBackendSummarySetup * extension,...)419 e_source_backend_summary_setup_set_summary_fields (ESourceBackendSummarySetup *extension,
420                                                    ...)
421 {
422 	va_list var_args;
423 
424 	g_return_if_fail (E_IS_SOURCE_BACKEND_SUMMARY_SETUP (extension));
425 
426 	va_start (var_args, extension);
427 	e_source_backend_summary_setup_set_fields_va_list (extension, var_args, PROP_SUMMARY_FIELDS);
428 	va_end (var_args);
429 }
430 
431 /**
432  * e_source_backend_summary_setup_get_indexed_fields:
433  * @extension: An #ESourceBackendSummarySetup
434  * @types: (out) (transfer full): A return location for the set of #EBookIndexTypes corresponding
435  *                                to each returned field,  should be freed with g_free() when no longer needed.
436  * @n_fields: (out): The number of elements in the returned arrays.
437  *
438  * Fetches the #EContactFields configured to be indexed, with thier respective #EBookIndexTypes.
439  *
440  * Returns: (transfer full): The array of indexed #EContactFields.
441  *
442  * Since: 3.8
443  */
444 EContactField  *
e_source_backend_summary_setup_get_indexed_fields(ESourceBackendSummarySetup * extension,EBookIndexType ** types,gint * n_fields)445 e_source_backend_summary_setup_get_indexed_fields (ESourceBackendSummarySetup *extension,
446                                                    EBookIndexType **types,
447                                                    gint *n_fields)
448 {
449 	EContactField *ret_fields;
450 	EBookIndexType *ret_types;
451 	gboolean malformed = FALSE;
452 	gchar **split, **index_split;
453 	gchar *literal_indexes;
454 	gint ret_n_fields;
455 	gint i;
456 
457 	g_return_val_if_fail (E_IS_SOURCE_BACKEND_SUMMARY_SETUP (extension), NULL);
458 	g_return_val_if_fail (types != NULL, NULL);
459 	g_return_val_if_fail (n_fields != NULL, NULL);
460 
461 	literal_indexes = source_backend_summary_setup_dup_literal_fields (extension, PROP_INDEXED_FIELDS);
462 	if (!literal_indexes) {
463 		*types = NULL;
464 		*n_fields = 0;
465 		return NULL;
466 	}
467 
468 	split = g_strsplit (literal_indexes, ":", 0);
469 	ret_n_fields = g_strv_length (split);
470 
471 	ret_fields = g_new0 (EContactField, ret_n_fields);
472 	ret_types = g_new0 (EBookIndexType, ret_n_fields);
473 
474 	for (i = 0; i < ret_n_fields && malformed == FALSE; i++) {
475 
476 		index_split = g_strsplit (split[i], ",", 2);
477 
478 		if (index_split[0] && index_split[1]) {
479 			gint interpreted_enum = 0;
480 
481 			ret_fields[i] = e_contact_field_id (index_split[0]);
482 
483 			if (!e_enum_from_string (E_TYPE_BOOK_INDEX_TYPE,
484 						 index_split[1], &interpreted_enum)) {
485 				g_warning ("Unknown index type '%s' encountered in indexed fields", index_split[1]);
486 				malformed = TRUE;
487 			}
488 
489 			if (ret_fields[i] <= 0 || ret_fields[i] >= E_CONTACT_FIELD_LAST) {
490 				g_warning ("Unknown contact field '%s' encountered in indexed fields", index_split[0]);
491 				malformed = TRUE;
492 			}
493 
494 			ret_types[i] = interpreted_enum;
495 		} else {
496 			g_warning ("Malformed index definition '%s'", split[i]);
497 			malformed = TRUE;
498 		}
499 
500 		g_strfreev (index_split);
501 	}
502 
503 	if (malformed) {
504 		g_free (ret_fields);
505 		g_free (ret_types);
506 
507 		ret_n_fields = 0;
508 		ret_fields = NULL;
509 		ret_types = NULL;
510 	}
511 
512 	g_strfreev (split);
513 	g_free (literal_indexes);
514 
515 	*n_fields = ret_n_fields;
516 	*types = ret_types;
517 
518 	return ret_fields;
519 }
520 
521 /**
522  * e_source_backend_summary_setup_set_indexed_fieldsv:
523  * @extension: An #ESourceBackendSummarySetup
524  * @fields: The array of #EContactFields to set indexes for
525  * @types: The array of #EBookIndexTypes defining what types of indexes to create
526  * @n_fields: The number elements in the passed @fields, @rule_types and @rules arrays.
527  *
528  * Defines indexes for quick reference for the given given #EContactFields in the addressbook.
529  *
530  * The same #EContactField may be specified multiple times to create multiple indexes
531  * with different characteristics. If an #E_BOOK_INDEX_PREFIX index is created it will
532  * be used for #E_BOOK_QUERY_BEGINS_WITH queries. An #E_BOOK_INDEX_SUFFIX index
533  * will be constructed efficiently for suffix matching and will be used for
534  * #E_BOOK_QUERY_ENDS_WITH queries. Similar an #E_BOOK_INDEX_PHONE index will optimize
535  * #E_BOOK_QUERY_EQUALS_PHONE_NUMBER searches.
536  *
537  * <note><para>The specified indexed fields must also be a part of the summary, any indexed fields
538  * specified that are not already a part of the summary will be ignored.</para></note>
539  *
540  * Since: 3.8
541  */
542 void
e_source_backend_summary_setup_set_indexed_fieldsv(ESourceBackendSummarySetup * extension,EContactField * fields,EBookIndexType * types,gint n_fields)543 e_source_backend_summary_setup_set_indexed_fieldsv (ESourceBackendSummarySetup *extension,
544                                                     EContactField *fields,
545                                                     EBookIndexType *types,
546                                                     gint n_fields)
547 {
548 	GString *string;
549 	gboolean malformed = FALSE;
550 	gint i;
551 
552 	g_return_if_fail (E_IS_SOURCE_BACKEND_SUMMARY_SETUP (extension));
553 	g_return_if_fail (types != NULL || n_fields <= 0);
554 	g_return_if_fail (fields != NULL || n_fields <= 0);
555 
556 	if (n_fields <= 0) {
557 		source_backend_summary_setup_set_literal_fields (extension, NULL, PROP_INDEXED_FIELDS);
558 		return;
559 	}
560 
561 	string = g_string_new (NULL);
562 
563 	for (i = 0; i < n_fields && malformed == FALSE; i++) {
564 		const gchar *field;
565 		const gchar *type;
566 
567 		field = e_contact_field_name (fields[i]);
568 		type = e_enum_to_string (E_TYPE_BOOK_INDEX_TYPE, types[i]);
569 
570 		if (!field) {
571 			g_warning ("Invalid contact field specified in indexed fields");
572 			malformed = TRUE;
573 		} else if (!type) {
574 			g_warning ("Invalid index type specified in indexed fields");
575 			malformed = TRUE;
576 		} else {
577 			if (i > 0)
578 				g_string_append_c (string, ':');
579 			g_string_append_printf (string, "%s,%s", field, type);
580 		}
581 	}
582 
583 	if (!malformed)
584 		source_backend_summary_setup_set_literal_fields (extension, string->str, PROP_INDEXED_FIELDS);
585 
586 	g_string_free (string, TRUE);
587 }
588 
589 /**
590  * e_source_backend_summary_setup_set_indexed_fields:
591  * @extension: An #ESourceBackendSummarySetup
592  * @...: A list of #EContactFields, #EBookIndexType pairs terminated by 0.
593  *
594  * Like e_source_backend_summary_setup_set_indexed_fieldsv(), but takes a literal list of
595  * of indexes.
596  *
597  * To give the 'fullname' field an index for prefix and suffix searches:
598  *
599  * |[
600  *   #include <libebook/libebook.h>
601  *
602  *   ESourceBackendSummarySetup *extension;
603  *
604  *   extension = e_source_get_extension (source, E_SOURCE_EXTENSION_BACKEND_SUMMARY_SETUP);
605  *
606  *   e_source_backend_summary_setup_set_indexed_fields (extension,
607  *                                                      E_CONTACT_FULL_NAME, E_BOOK_INDEX_PREFIX,
608  *                                                      E_CONTACT_FULL_NAME, E_BOOK_INDEX_SUFFIX,
609  *                                                      0);
610  * ]|
611  *
612  * Since: 3.8
613  */
614 void
e_source_backend_summary_setup_set_indexed_fields(ESourceBackendSummarySetup * extension,...)615 e_source_backend_summary_setup_set_indexed_fields (ESourceBackendSummarySetup *extension,
616                                                    ...)
617 {
618 	GString *string;
619 	gboolean malformed = FALSE, first = TRUE;
620 	va_list var_args;
621 	EContactField field_in;
622 	EBookIndexType type_in;
623 
624 	g_return_if_fail (E_IS_SOURCE_BACKEND_SUMMARY_SETUP (extension));
625 
626 	string = g_string_new (NULL);
627 
628 	va_start (var_args, extension);
629 
630 	field_in = va_arg (var_args, EContactField);
631 	while (field_in > 0 && malformed == FALSE) {
632 		const gchar *field;
633 		const gchar *type;
634 
635 		field = e_contact_field_name (field_in);
636 		if (field == NULL) {
637 			g_warning ("Invalid contact field specified in "
638 				"e_source_backend_summary_setup_set_indexed_fields()");
639 			malformed = TRUE;
640 			break;
641 		}
642 
643 		type_in = va_arg (var_args, EBookIndexType);
644 		type = e_enum_to_string (E_TYPE_BOOK_INDEX_TYPE, type_in);
645 		if (type == NULL) {
646 			g_warning ("Invalid index type "
647 				"e_source_backend_summary_setup_set_indexed_fields()");
648 			malformed = TRUE;
649 			break;
650 		}
651 
652 		if (!first)
653 			g_string_append_c (string, ':');
654 		else
655 			first = FALSE;
656 
657 		g_string_append_printf (string, "%s,%s", field, type);
658 
659 		/* Continue loop until first 0 found... */
660 		field_in = va_arg (var_args, EContactField);
661 	}
662 	va_end (var_args);
663 
664 	if (!malformed)
665 		source_backend_summary_setup_set_literal_fields (extension, string->str, PROP_INDEXED_FIELDS);
666 
667 	g_string_free (string, TRUE);
668 }
669