1 /*-*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* e-book-sqlite.c
3  *
4  * Copyright (C) 2013 Intel Corporation
5  *
6  * This library is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation.
9  *
10  * This library is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
13  * for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this library. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * Authors: Tristan Van Berkom <tristanvb@openismus.com>
19  */
20 
21 /**
22  * SECTION: e-book-sqlite
23  * @include: libedata-book/libedata-book.h
24  * @short_description: An SQLite storage facility for addressbooks
25  *
26  * The #EBookSqlite is an API for storing and looking up #EContact(s)
27  * in an SQLite database. It also supports a lean index mode via
28  * the #EbSqlVCardCallback, if you are in a situation where it is
29  * not convenient to store the vCards directly in the SQLite. It is
30  * however recommended to avoid storing contacts in separate storage
31  * if at all possible, as this will decrease performance of searches
32  * an also contribute to flash wear.
33  *
34  * The API is thread safe, with special considerations to be made
35  * around e_book_sqlite_lock() and e_book_sqlite_unlock() for
36  * the sake of isolating transactions across threads.
37  *
38  * Any operations which can take a lot of time to complete (depending
39  * on the size of your addressbook) can be cancelled using a #GCancellable.
40  *
41  * Depending on your summary configuration, your mileage will vary. Refer
42  * to the #ESourceBackendSummarySetup for configuring your addressbook
43  * for the type of usage you mean to make of it.
44  */
45 
46 #include "e-book-sqlite.h"
47 
48 #include <locale.h>
49 #include <string.h>
50 #include <errno.h>
51 
52 #include <glib/gi18n.h>
53 #include <glib/gstdio.h>
54 
55 #include <sqlite3.h>
56 
57 /* For e_sqlite3_vfs_init() */
58 #include <libebackend/libebackend.h>
59 
60 #include "e-book-backend-sexp.h"
61 
62 /******************************************************
63  *                 Debugging Macros                   *
64  ******************************************************
65  * Run EDS with EBSQL_DEBUG=statements:explain to print
66  * all statements and explain query plans.
67  *
68  * Use any of the values below to select which debug
69  * to enable.
70  */
71 #define EBSQL_ENV_DEBUG   "EBSQL_DEBUG"
72 
73 typedef enum {
74 	EBSQL_DEBUG_STATEMENTS    = 1 << 0,  /* Output all executed statements */
75 	EBSQL_DEBUG_EXPLAIN       = 1 << 1,  /* Output SQLite's query plan for SELECT statements */
76 	EBSQL_DEBUG_LOCKS         = 1 << 2,  /* Print which function locks and unlocks the mutex */
77 	EBSQL_DEBUG_ERRORS        = 1 << 3,  /* Print all errors which are set */
78 	EBSQL_DEBUG_SCHEMA        = 1 << 4,  /* Debugging the schema building / upgrading */
79 	EBSQL_DEBUG_INSERT        = 1 << 5,  /* Debugging contact insertions */
80 	EBSQL_DEBUG_FETCH_VCARD   = 1 << 6,  /* Print invocations of the EbSqlVCardCallback fallback */
81 	EBSQL_DEBUG_CURSOR        = 1 << 7,  /* Print information about EbSqlCursor operations */
82 	EBSQL_DEBUG_CONVERT_E164  = 1 << 8,  /* Print information e164 phone number conversions in vcards */
83 	EBSQL_DEBUG_REF_COUNTS    = 1 << 9,  /* Print about shared EBookSqlite instances, print when finalized */
84 	EBSQL_DEBUG_CANCEL        = 1 << 10, /* Print information about GCancellable cancellations */
85 	EBSQL_DEBUG_PREFLIGHT     = 1 << 11, /* Print information about query preflighting */
86 	EBSQL_DEBUG_TIMING        = 1 << 12, /* Print information about timing */
87 } EbSqlDebugFlag;
88 
89 static const GDebugKey ebsql_debug_keys[] = {
90 	{ "statements",     EBSQL_DEBUG_STATEMENTS   },
91 	{ "explain",        EBSQL_DEBUG_EXPLAIN      },
92 	{ "locks",          EBSQL_DEBUG_LOCKS        },
93 	{ "errors",         EBSQL_DEBUG_ERRORS       },
94 	{ "schema",         EBSQL_DEBUG_SCHEMA       },
95 	{ "insert",         EBSQL_DEBUG_INSERT       },
96 	{ "fetch-vcard",    EBSQL_DEBUG_FETCH_VCARD  },
97 	{ "cursor",         EBSQL_DEBUG_CURSOR       },
98 	{ "e164",           EBSQL_DEBUG_CONVERT_E164 },
99 	{ "ref-counts",     EBSQL_DEBUG_REF_COUNTS   },
100 	{ "cancel",         EBSQL_DEBUG_CANCEL       },
101 	{ "preflight",      EBSQL_DEBUG_PREFLIGHT    },
102 	{ "timing",         EBSQL_DEBUG_TIMING       },
103 };
104 
105 static EbSqlDebugFlag ebsql_debug_flags = 0;
106 
107 static void
ebsql_init_debug(void)108 ebsql_init_debug (void)
109 {
110 	static gboolean initialized = FALSE;
111 
112 	if (G_UNLIKELY (!initialized)) {
113 		const gchar *env_string;
114 
115 		env_string = g_getenv (EBSQL_ENV_DEBUG);
116 
117 		if (env_string != NULL)
118 			ebsql_debug_flags =
119 				g_parse_debug_string (
120 					env_string,
121 					ebsql_debug_keys,
122 					G_N_ELEMENTS (ebsql_debug_keys));
123 	}
124 }
125 
126 static const gchar *
ebsql_error_str(EBookSqliteError code)127 ebsql_error_str (EBookSqliteError code)
128 {
129 	switch (code) {
130 		case E_BOOK_SQLITE_ERROR_ENGINE:
131 			return "engine";
132 		case E_BOOK_SQLITE_ERROR_CONSTRAINT:
133 			return "constraint";
134 		case E_BOOK_SQLITE_ERROR_CONTACT_NOT_FOUND:
135 			return "contact not found";
136 		case E_BOOK_SQLITE_ERROR_INVALID_QUERY:
137 			return "invalid query";
138 		case E_BOOK_SQLITE_ERROR_UNSUPPORTED_QUERY:
139 			return "unsupported query";
140 		case E_BOOK_SQLITE_ERROR_UNSUPPORTED_FIELD:
141 			return "unsupported field";
142 		case E_BOOK_SQLITE_ERROR_END_OF_LIST:
143 			return "end of list";
144 		case E_BOOK_SQLITE_ERROR_LOAD:
145 			return "load";
146 	}
147 
148 	return "(unknown)";
149 }
150 
151 static const gchar *
ebsql_origin_str(EbSqlCursorOrigin origin)152 ebsql_origin_str (EbSqlCursorOrigin origin)
153 {
154 	switch (origin) {
155 		case EBSQL_CURSOR_ORIGIN_CURRENT:
156 			return "current";
157 		case EBSQL_CURSOR_ORIGIN_BEGIN:
158 			return "begin";
159 		case EBSQL_CURSOR_ORIGIN_END:
160 			return "end";
161 	}
162 
163 	return "(invalid)";
164 }
165 
166 #define EBSQL_NOTE(type,action) \
167 	G_STMT_START { \
168 		if (ebsql_debug_flags & EBSQL_DEBUG_##type) \
169 			{ action; }; \
170 	} G_STMT_END
171 
172 #define EBSQL_LOCK_MUTEX(mutex) \
173 	G_STMT_START { \
174 		if (ebsql_debug_flags & EBSQL_DEBUG_LOCKS) { \
175 			g_printerr ("%s: Locking %s\n", G_STRFUNC, #mutex); \
176 			g_mutex_lock (mutex); \
177 			g_printerr ("%s: Locked %s\n", G_STRFUNC, #mutex); \
178 		} else { \
179 			g_mutex_lock (mutex); \
180 		} \
181 	} G_STMT_END
182 
183 #define EBSQL_UNLOCK_MUTEX(mutex) \
184 	G_STMT_START { \
185 		if (ebsql_debug_flags & EBSQL_DEBUG_LOCKS) { \
186 			g_printerr ("%s: Unlocking %s\n", G_STRFUNC, #mutex); \
187 			g_mutex_unlock (mutex); \
188 			g_printerr ("%s: Unlocked %s\n", G_STRFUNC, #mutex); \
189 		} else { \
190 			g_mutex_unlock (mutex); \
191 		} \
192 	} G_STMT_END
193 
194 /* Format strings are passed through dgettext(), need to be reformatted */
195 #define EBSQL_SET_ERROR(error, code, fmt, args...) \
196 	G_STMT_START { \
197 		if (ebsql_debug_flags & EBSQL_DEBUG_ERRORS) { \
198 			gchar *format = g_strdup_printf ( \
199 				"ERR [%%s]: Set error code '%%s': %s\n", fmt); \
200 			g_printerr (format, G_STRFUNC, \
201 				    ebsql_error_str (code), ## args); \
202 			g_free (format); \
203 		} \
204 		g_set_error (error, E_BOOK_SQLITE_ERROR, code, fmt, ## args); \
205 	} G_STMT_END
206 
207 #define EBSQL_SET_ERROR_LITERAL(error, code, detail) \
208 	G_STMT_START { \
209 		if (ebsql_debug_flags & EBSQL_DEBUG_ERRORS) { \
210 			g_printerr ("ERR [%s]: " \
211 				    "Set error code %s: %s\n", \
212 				    G_STRFUNC, \
213 				    ebsql_error_str (code), detail); \
214 		} \
215 		g_set_error_literal (error, E_BOOK_SQLITE_ERROR, code, detail); \
216 	} G_STMT_END
217 
218 /* EBSQL_LOCK_OR_RETURN:
219  * @ebsql: The #EBookSqlite
220  * @cancellable: A #GCancellable passed into an API
221  * @val: Value to return if this check fails
222  *
223  * This will first lock the mutex and then check if
224  * the passed cancellable is valid or invalid, it can
225  * be invalid if it differs from a cancellable passed
226  * to a toplevel transaction via e_book_sqlite_lock().
227  *
228  * If the check fails, the lock is released and then
229  * @val is returned.
230  */
231 #define EBSQL_LOCK_OR_RETURN(ebsql, cancellable, val) \
232 	G_STMT_START { \
233 		EBSQL_LOCK_MUTEX (&(ebsql)->priv->lock); \
234 		if (cancellable != NULL && (ebsql)->priv->cancel &&	    \
235 		    (ebsql)->priv->cancel != cancellable) { \
236 			g_warning ("The GCancellable passed to `%s' " \
237 				   "is not the same as the cancel object " \
238 				   "passed to e_book_sqlite_lock()", \
239 				   G_STRFUNC); \
240 			EBSQL_UNLOCK_MUTEX (&(ebsql)->priv->lock); \
241 			return val; \
242 		} \
243 	} G_STMT_END
244 
245 /* Set an error code from an sqlite_exec() or sqlite_step() return value & error message */
246 #define EBSQL_SET_ERROR_FROM_SQLITE(error, code, message) \
247 	G_STMT_START { \
248 		if (code == SQLITE_CONSTRAINT) { \
249 			EBSQL_SET_ERROR_LITERAL (error, \
250 						 E_BOOK_SQLITE_ERROR_CONSTRAINT, \
251 						 errmsg); \
252 		} else if (code == SQLITE_ABORT) { \
253 			if (ebsql_debug_flags & EBSQL_DEBUG_ERRORS) { \
254 				g_printerr ("ERR [%s]: Set cancelled error\n", \
255 					    G_STRFUNC); \
256 			} \
257 			g_set_error (error, \
258 				     G_IO_ERROR, \
259 				     G_IO_ERROR_CANCELLED, \
260 				     "Operation cancelled: %s", errmsg); \
261 		} else { \
262 			EBSQL_SET_ERROR (error, \
263 					 E_BOOK_SQLITE_ERROR_ENGINE, \
264 					 "SQLite error code `%d': %s", \
265 					 code, errmsg); \
266 		} \
267 	} G_STMT_END
268 
269 #define FOLDER_VERSION                12
270 #define INSERT_MULTI_STMT_BYTES       128
271 #define COLUMN_DEFINITION_BYTES       32
272 #define GENERATED_QUERY_BYTES         1024
273 
274 #define DEFAULT_FOLDER_ID            "folder_id"
275 
276 /* We use a 64 bitmask to track which auxiliary tables
277  * are needed to satisfy a query, it's doubtful that
278  * anyone will need an addressbook with 64 fields configured
279  * in the summary.
280  */
281 #define EBSQL_MAX_SUMMARY_FIELDS      64
282 
283 /* The number of SQLite virtual machine instructions that are
284  * evaluated at a time, the user passed GCancellable is
285  * checked between each batch of evaluated instructions.
286  */
287 #define EBSQL_CANCEL_BATCH_SIZE       200
288 
289 /* Number of contacts to relocalize at a time
290  * while relocalizing the whole database
291  */
292 #define EBSQL_UPGRADE_BATCH_SIZE      20
293 
294 #define EBSQL_ESCAPE_SEQUENCE        "ESCAPE '^'"
295 
296 /* Names for custom functions */
297 #define EBSQL_FUNC_COMPARE_VCARD     "compare_vcard"
298 #define EBSQL_FUNC_FETCH_VCARD       "fetch_vcard"
299 #define EBSQL_FUNC_EQPHONE_EXACT     "eqphone_exact"
300 #define EBSQL_FUNC_EQPHONE_NATIONAL  "eqphone_national"
301 #define EBSQL_FUNC_EQPHONE_SHORT     "eqphone_short"
302 
303 /* Fallback collations are generated as with a prefix and an EContactField name */
304 #define EBSQL_COLLATE_PREFIX         "ebsql_"
305 
306 /* A special vcard attribute that we use only for private vcards */
307 #define EBSQL_VCARD_SORT_KEY         "X-EVOLUTION-SORT-KEY"
308 
309 /* Suffixes for column names used to store specialized data */
310 #define EBSQL_SUFFIX_REVERSE         "reverse"
311 #define EBSQL_SUFFIX_SORT_KEY        "localized"
312 #define EBSQL_SUFFIX_PHONE           "phone"
313 #define EBSQL_SUFFIX_COUNTRY         "country"
314 
315 /* Track EBookIndexType's in a bit mask  */
316 #define INDEX_FLAG(type)  (1 << E_BOOK_INDEX_##type)
317 
318 /* This macro is used to reffer to vcards in statements */
319 #define EBSQL_VCARD_FRAGMENT(ebsql) \
320 	((ebsql)->priv->vcard_callback ? \
321 	 EBSQL_FUNC_FETCH_VCARD " (summary.uid, summary.bdata)" : \
322 	 "summary.vcard")
323 
324 /* Signatures for some of the SQLite callbacks which we pass around */
325 typedef void	(*EbSqlCustomFunc)		(sqlite3_context *context,
326 						 gint argc,
327 						 sqlite3_value **argv);
328 typedef gint	(*EbSqlRowFunc)			(gpointer ref,
329 						 gint n_cols,
330 						 gchar **cols,
331 						 gchar **names);
332 
333 /* Some forward declarations */
334 static gboolean		ebsql_init_statements	(EBookSqlite *ebsql,
335 						 GError **error);
336 static gboolean		ebsql_insert_contact	(EBookSqlite *ebsql,
337 						 EbSqlChangeType change_type,
338 						 EContact *contact,
339 						 const gchar *original_vcard,
340 						 const gchar *extra,
341 						 gboolean replace,
342 						 GError **error);
343 static gboolean		ebsql_exec		(EBookSqlite *ebsql,
344 						 const gchar *stmt,
345 						 EbSqlRowFunc callback,
346 						 gpointer data,
347 						 GCancellable *cancellable,
348 						 GError **error);
349 
350 typedef struct {
351 	EContactField field_id;           /* The EContact field */
352 	GType         type;               /* The GType (only support string or gboolean) */
353 	const gchar  *dbname;             /* The key for this field in the sqlite3 table */
354 	gint          index;              /* Types of searches this field should support (see EBookIndexType) */
355 	gchar        *aux_table;          /* Name of auxiliary table for this field, for multivalued fields only */
356 	gchar        *aux_table_symbolic; /* Symolic name of auxiliary table used in queries */
357 } SummaryField;
358 
359 struct _EBookSqlitePrivate {
360 
361 	/* Parameters and settings */
362 	gchar          *path;            /* Full file name of the file we're operating on (used for hash table entries) */
363 	gchar          *locale;          /* The current locale */
364 	gchar          *region_code;     /* Region code (for phone number parsing) */
365 	gchar          *folderid;        /* The summary table name (configurable, for support of legacy
366 					  * databases created by EBookSqliteDB) */
367 
368 	EbSqlVCardCallback  vcard_callback;     /* User callback to fetch vcards instead of storing them */
369 	EbSqlChangeCallback change_callback;    /* User callback to catch change notifications  */
370 	gpointer            user_data;          /* Data & Destroy notifier for the above callbacks */
371 	GDestroyNotify      user_data_destroy;
372 
373 	/* Summary configuration */
374 	SummaryField   *summary_fields;
375 	gint            n_summary_fields;
376 
377 	GMutex          lock;            /* Main API lock */
378 	GMutex          updates_lock;    /* Lock used for calls to e_book_sqlite_lock_updates () */
379 	guint32         in_transaction;  /* Nested transaction counter */
380 	EbSqlLockType   lock_type;       /* The lock type acquired for the current transaction */
381 	GCancellable   *cancel;          /* User passed GCancellable, we abort an operation if cancelled */
382 
383 	ECollator      *collator;        /* The ECollator to create sort keys for any sortable fields */
384 
385 	/* SQLite resources  */
386 	sqlite3        *db;
387 	sqlite3_stmt   *insert_stmt;     /* Insert statement for main summary table */
388 	sqlite3_stmt   *replace_stmt;    /* Replace statement for main summary table */
389 	GHashTable     *multi_deletes;   /* Delete statement for each auxiliary table */
390 	GHashTable     *multi_inserts;   /* Insert statement for each auxiliary table */
391 
392 	ESource        *source;
393 };
394 
395 enum {
396 	BEFORE_INSERT_CONTACT,
397 	BEFORE_REMOVE_CONTACT,
398 	LAST_SIGNAL
399 };
400 
401 static guint signals[LAST_SIGNAL];
402 
403 G_DEFINE_TYPE_WITH_CODE (EBookSqlite, e_book_sqlite, G_TYPE_OBJECT,
404 			 G_ADD_PRIVATE (EBookSqlite)
405 			 G_IMPLEMENT_INTERFACE (E_TYPE_EXTENSIBLE, NULL))
406 
407 G_DEFINE_QUARK (e-book-backend-sqlite-error-quark,
408 		e_book_sqlite_error)
409 
410 /* The ColumnInfo struct is used to constant data
411  * and dynamically allocated data, the 'type' and
412  * 'extra' members are however always constant.
413  */
414 typedef struct {
415 	gchar       *name;
416 	const gchar *type;
417 	const gchar *extra;
418 	gchar       *index;
419 } ColumnInfo;
420 
421 static ColumnInfo main_table_columns[] = {
422 	{ (gchar *) "folder_id",       "TEXT",      "PRIMARY KEY", NULL },
423 	{ (gchar *) "version",         "INTEGER",    NULL,         NULL },
424 	{ (gchar *) "multivalues",     "TEXT",       NULL,         NULL },
425 	{ (gchar *) "lc_collate",      "TEXT",       NULL,         NULL },
426 	{ (gchar *) "countrycode",     "VARCHAR(2)", NULL,         NULL },
427 };
428 
429 /* Default summary configuration */
430 static EContactField default_summary_fields[] = {
431 	E_CONTACT_UID,
432 	E_CONTACT_REV,
433 	E_CONTACT_FILE_AS,
434 	E_CONTACT_NICKNAME,
435 	E_CONTACT_FULL_NAME,
436 	E_CONTACT_GIVEN_NAME,
437 	E_CONTACT_FAMILY_NAME,
438 	E_CONTACT_EMAIL,
439 	E_CONTACT_TEL,
440 	E_CONTACT_IS_LIST,
441 	E_CONTACT_LIST_SHOW_ADDRESSES,
442 	E_CONTACT_WANTS_HTML,
443 	E_CONTACT_X509_CERT,
444 	E_CONTACT_PGP_CERT
445 };
446 
447 /* Create indexes on full_name and email fields as autocompletion
448  * queries would mainly rely on this.
449  *
450  * Add sort keys for name fields as those are likely targets for
451  * cursor usage.
452  */
453 static EContactField default_indexed_fields[] = {
454 	E_CONTACT_FULL_NAME,
455 	E_CONTACT_NICKNAME,
456 	E_CONTACT_FILE_AS,
457 	E_CONTACT_GIVEN_NAME,
458 	E_CONTACT_FAMILY_NAME,
459 	E_CONTACT_EMAIL,
460 	E_CONTACT_FILE_AS,
461 	E_CONTACT_FAMILY_NAME,
462 	E_CONTACT_GIVEN_NAME
463 };
464 
465 static EBookIndexType default_index_types[] = {
466 	E_BOOK_INDEX_PREFIX,
467 	E_BOOK_INDEX_PREFIX,
468 	E_BOOK_INDEX_PREFIX,
469 	E_BOOK_INDEX_PREFIX,
470 	E_BOOK_INDEX_PREFIX,
471 	E_BOOK_INDEX_PREFIX,
472 	E_BOOK_INDEX_SORT_KEY,
473 	E_BOOK_INDEX_SORT_KEY,
474 	E_BOOK_INDEX_SORT_KEY
475 };
476 
477 /******************************************************
478  *                  Summary Fields                    *
479  ******************************************************/
480 static ColumnInfo *
column_info_new(SummaryField * field,const gchar * folderid,const gchar * column_suffix,const gchar * column_type,const gchar * column_extra,const gchar * idx_prefix)481 column_info_new (SummaryField *field,
482                  const gchar *folderid,
483                  const gchar *column_suffix,
484                  const gchar *column_type,
485                  const gchar *column_extra,
486                  const gchar *idx_prefix)
487 {
488 	ColumnInfo *info;
489 
490 	info = g_slice_new0 (ColumnInfo);
491 	info->type = column_type;
492 	info->extra = column_extra;
493 
494 	if (!info->type) {
495 		if (field->type == G_TYPE_STRING)
496 			info->type = "TEXT";
497 		else if (field->type == G_TYPE_BOOLEAN || field->type == E_TYPE_CONTACT_CERT)
498 			info->type = "INTEGER";
499 		else if (field->type == E_TYPE_CONTACT_ATTR_LIST)
500 			info->type = "TEXT";
501 		else
502 			g_warn_if_reached ();
503 	}
504 
505 	if (field->type == E_TYPE_CONTACT_ATTR_LIST)
506 		/* Attribute lists are on their own table  */
507 		info->name = g_strconcat (
508 			"value",
509 			column_suffix ? "_" : NULL,
510 			column_suffix,
511 			NULL);
512 	else
513 		/* Regular fields are named by their 'dbname' */
514 		info->name = g_strconcat (
515 			field->dbname,
516 			column_suffix ? "_" : NULL,
517 			column_suffix,
518 			NULL);
519 
520 	if (idx_prefix)
521 		info->index = g_strconcat (
522 			idx_prefix,
523 			"_", field->dbname,
524 			"_", folderid,
525 			NULL);
526 
527 	return info;
528 }
529 
530 static void
column_info_free(ColumnInfo * info)531 column_info_free (ColumnInfo *info)
532 {
533 	if (info) {
534 		g_free (info->name);
535 		g_free (info->index);
536 		g_slice_free (ColumnInfo, info);
537 	}
538 }
539 
540 static gint
summary_field_array_index(GArray * array,EContactField field)541 summary_field_array_index (GArray *array,
542                            EContactField field)
543 {
544 	gint i;
545 
546 	for (i = 0; i < array->len; i++) {
547 		SummaryField *iter = &g_array_index (array, SummaryField, i);
548 		if (field == iter->field_id)
549 			return i;
550 	}
551 
552 	return -1;
553 }
554 
555 static SummaryField *
summary_field_append(GArray * array,const gchar * folderid,EContactField field_id,GError ** error)556 summary_field_append (GArray *array,
557                       const gchar *folderid,
558                       EContactField field_id,
559                       GError **error)
560 {
561 	const gchar *dbname = NULL;
562 	GType        type = G_TYPE_INVALID;
563 	gint         idx;
564 	SummaryField new_field = { 0, };
565 
566 	if (field_id < 1 || field_id >= E_CONTACT_FIELD_LAST) {
567 		EBSQL_SET_ERROR (
568 			error, E_BOOK_SQLITE_ERROR_UNSUPPORTED_FIELD,
569 			_("Unsupported contact field “%d” specified in summary"),
570 			field_id);
571 		return NULL;
572 	}
573 
574 	/* Avoid including the same field twice in the summary */
575 	idx = summary_field_array_index (array, field_id);
576 	if (idx >= 0)
577 		return &g_array_index (array, SummaryField, idx);
578 
579 	/* Resolve some exceptions, we store these
580 	 * specific contact fields with different names
581 	 * than those found in the EContactField table
582 	 */
583 	switch (field_id) {
584 	case E_CONTACT_UID:
585 		dbname = "uid";
586 		break;
587 	case E_CONTACT_IS_LIST:
588 		dbname = "is_list";
589 		break;
590 	default:
591 		dbname = e_contact_field_name (field_id);
592 		break;
593 	}
594 
595 	type = e_contact_field_type (field_id);
596 
597 	if (type != G_TYPE_STRING &&
598 	    type != G_TYPE_BOOLEAN &&
599 	    type != E_TYPE_CONTACT_CERT &&
600 	    type != E_TYPE_CONTACT_ATTR_LIST) {
601 		EBSQL_SET_ERROR (
602 			error, E_BOOK_SQLITE_ERROR_UNSUPPORTED_FIELD,
603 			_("Contact field “%s” of type “%s” specified in summary, "
604 			"but only boolean, string and string list field types are supported"),
605 			e_contact_pretty_name (field_id), g_type_name (type));
606 		return NULL;
607 	}
608 
609 	if (type == E_TYPE_CONTACT_ATTR_LIST) {
610 		new_field.aux_table = g_strconcat (folderid, "_", dbname, "_list", NULL);
611 		new_field.aux_table_symbolic = g_strconcat (dbname, "_list", NULL);
612 	}
613 
614 	new_field.field_id = field_id;
615 	new_field.dbname = dbname;
616 	new_field.type = type;
617 	new_field.index = 0;
618 	g_array_append_val (array, new_field);
619 
620 	return &g_array_index (array, SummaryField, array->len - 1);
621 }
622 
623 static gboolean
summary_field_remove(GArray * array,EContactField field)624 summary_field_remove (GArray *array,
625                       EContactField field)
626 {
627 	gint idx;
628 
629 	idx = summary_field_array_index (array, field);
630 	if (idx < 0)
631 		return FALSE;
632 
633 	g_array_remove_index_fast (array, idx);
634 	return TRUE;
635 }
636 
637 static void
summary_fields_add_indexes(GArray * array,EContactField * indexes,EBookIndexType * index_types,gint n_indexes)638 summary_fields_add_indexes (GArray *array,
639                             EContactField *indexes,
640                             EBookIndexType *index_types,
641                             gint n_indexes)
642 {
643 	gint i, j;
644 
645 	for (i = 0; i < array->len; i++) {
646 		SummaryField *sfield = &g_array_index (array, SummaryField, i);
647 
648 		for (j = 0; j < n_indexes; j++) {
649 			if (sfield->field_id == indexes[j])
650 				sfield->index |= (1 << index_types[j]);
651 
652 		}
653 	}
654 }
655 
656 static inline gint
summary_field_get_index(EBookSqlite * ebsql,EContactField field_id)657 summary_field_get_index (EBookSqlite *ebsql,
658                          EContactField field_id)
659 {
660 	gint i;
661 
662 	for (i = 0; i < ebsql->priv->n_summary_fields; i++) {
663 		if (ebsql->priv->summary_fields[i].field_id == field_id)
664 			return i;
665 	}
666 
667 	return -1;
668 }
669 
670 static inline SummaryField *
summary_field_get(EBookSqlite * ebsql,EContactField field_id)671 summary_field_get (EBookSqlite *ebsql,
672                    EContactField field_id)
673 {
674 	gint index;
675 
676 	index = summary_field_get_index (ebsql, field_id);
677 	if (index >= 0)
678 		return &(ebsql->priv->summary_fields[index]);
679 
680 	return NULL;
681 }
682 
683 static GSList *
summary_field_list_columns(SummaryField * field,const gchar * folderid)684 summary_field_list_columns (SummaryField *field,
685                             const gchar *folderid)
686 {
687 	GSList *columns = NULL;
688 	ColumnInfo *info;
689 
690 	/* Doesn't hurt to verify a bit more here, this shouldn't happen though */
691 	g_return_val_if_fail (
692 		field->type == G_TYPE_STRING ||
693 		field->type == G_TYPE_BOOLEAN ||
694 		field->type == E_TYPE_CONTACT_CERT ||
695 		field->type == E_TYPE_CONTACT_ATTR_LIST,
696 		NULL);
697 
698 	/* Normal / default column */
699 	info = column_info_new (
700 		field, folderid, NULL, NULL,
701 		(field->field_id == E_CONTACT_UID) ? "PRIMARY KEY" : NULL,
702 		(field->index & INDEX_FLAG (PREFIX)) != 0 ? "INDEX" : NULL);
703 	columns = g_slist_prepend (columns, info);
704 
705 	/* Localized column, for storing sort keys */
706 	if (field->type == G_TYPE_STRING && (field->index & INDEX_FLAG (SORT_KEY))) {
707 		info = column_info_new (field, folderid, EBSQL_SUFFIX_SORT_KEY, "TEXT", NULL, "SINDEX");
708 		columns = g_slist_prepend (columns, info);
709 	}
710 
711 	/* Suffix match column */
712 	if (field->type != G_TYPE_BOOLEAN && field->type != E_TYPE_CONTACT_CERT &&
713 	    (field->index & INDEX_FLAG (SUFFIX)) != 0) {
714 		info = column_info_new (field, folderid, EBSQL_SUFFIX_REVERSE, "TEXT", NULL, "RINDEX");
715 		columns = g_slist_prepend (columns, info);
716 	}
717 
718 	/* Phone match columns */
719 	if (field->type != G_TYPE_BOOLEAN && field->type != E_TYPE_CONTACT_CERT &&
720 	    (field->index & INDEX_FLAG (PHONE)) != 0) {
721 
722 		/* One indexed column for storing the national number */
723 		info = column_info_new (field, folderid, EBSQL_SUFFIX_PHONE, "TEXT", NULL, "PINDEX");
724 		columns = g_slist_prepend (columns, info);
725 
726 		/* One integer column for storing the country code */
727 		info = column_info_new (field, folderid, EBSQL_SUFFIX_COUNTRY, "INTEGER", "DEFAULT 0", NULL);
728 		columns = g_slist_prepend (columns, info);
729 	}
730 
731 	return g_slist_reverse (columns);
732 }
733 
734 static void
summary_fields_array_free(SummaryField * fields,gint n_fields)735 summary_fields_array_free (SummaryField *fields,
736                            gint n_fields)
737 {
738 	gint i;
739 
740 	for (i = 0; i < n_fields; i++) {
741 		g_free (fields[i].aux_table);
742 		g_free (fields[i].aux_table_symbolic);
743 	}
744 
745 	g_free (fields);
746 }
747 
748 /******************************************************
749  *        Sharing EBookSqlite instances        *
750  ******************************************************/
751 static GHashTable *db_connections = NULL;
752 static GMutex dbcon_lock;
753 
754 static EBookSqlite *
ebsql_ref_from_hash(const gchar * path)755 ebsql_ref_from_hash (const gchar *path)
756 {
757 	EBookSqlite *ebsql = NULL;
758 
759 	if (db_connections != NULL) {
760 		ebsql = g_hash_table_lookup (db_connections, path);
761 	}
762 
763 	if (ebsql) {
764 		EBSQL_NOTE (REF_COUNTS, g_printerr ("EBookSqlite ref count increased from hash table reference\n"));
765 		g_object_ref (ebsql);
766 	}
767 
768 	return ebsql;
769 }
770 
771 static void
ebsql_register_to_hash(EBookSqlite * ebsql,const gchar * path)772 ebsql_register_to_hash (EBookSqlite *ebsql,
773                         const gchar *path)
774 {
775 	if (db_connections == NULL)
776 		db_connections = g_hash_table_new_full (
777 			(GHashFunc) g_str_hash,
778 			(GEqualFunc) g_str_equal,
779 			(GDestroyNotify) g_free,
780 			(GDestroyNotify) NULL);
781 	g_hash_table_insert (db_connections, g_strdup (path), ebsql);
782 }
783 
784 static void
ebsql_unregister_from_hash(EBookSqlite * ebsql)785 ebsql_unregister_from_hash (EBookSqlite *ebsql)
786 {
787 	EBookSqlitePrivate *priv = ebsql->priv;
788 
789 	EBSQL_LOCK_MUTEX (&dbcon_lock);
790 	if (db_connections != NULL) {
791 		if (priv->path != NULL) {
792 			g_hash_table_remove (db_connections, priv->path);
793 
794 			if (g_hash_table_size (db_connections) == 0) {
795 				g_hash_table_destroy (db_connections);
796 				db_connections = NULL;
797 			}
798 
799 		}
800 	}
801 	EBSQL_UNLOCK_MUTEX (&dbcon_lock);
802 }
803 
804 /************************************************************
805  *                SQLite helper functions                   *
806  ************************************************************/
807 
808 /* For EBSQL_DEBUG_EXPLAIN */
809 static gint
ebsql_debug_query_plan_cb(gpointer ref,gint n_cols,gchar ** cols,gchar ** name)810 ebsql_debug_query_plan_cb (gpointer ref,
811                            gint n_cols,
812                            gchar **cols,
813                            gchar **name)
814 {
815 	gint i;
816 
817 	for (i = 0; i < n_cols; i++) {
818 		if (strcmp (name[i], "detail") == 0) {
819 			g_printerr ("  PLAN: %s\n", cols[i]);
820 			break;
821 		}
822 	}
823 
824 	return 0;
825 }
826 
827 /* Collect a GList of column names in the main summary table */
828 static gint
get_columns_cb(gpointer ref,gint col,gchar ** cols,gchar ** name)829 get_columns_cb (gpointer ref,
830                 gint col,
831                 gchar **cols,
832                 gchar **name)
833 {
834 	GSList **columns = (GSList **) ref;
835 	gint i;
836 
837 	for (i = 0; i < col; i++) {
838 		if (strcmp (name[i], "name") == 0) {
839 
840 			/* Keep comparing for the legacy 'bdata' column */
841 			if (strcmp (cols[i], "vcard") != 0 &&
842 			    strcmp (cols[i], "bdata") != 0) {
843 				gchar *column = g_strdup (cols[i]);
844 
845 				*columns = g_slist_prepend (*columns, column);
846 			}
847 			break;
848 		}
849 	}
850 	return 0;
851 }
852 
853 /* Collect the first string result */
854 static gint
get_string_cb(gpointer ref,gint col,gchar ** cols,gchar ** name)855 get_string_cb (gpointer ref,
856                gint col,
857                gchar **cols,
858                gchar **name)
859 {
860 	gchar **ret = ref;
861 
862 	*ret = g_strdup (cols [0]);
863 
864 	return 0;
865 }
866 
867 /* Collect the first integer result */
868 static gint
get_int_cb(gpointer ref,gint col,gchar ** cols,gchar ** name)869 get_int_cb (gpointer ref,
870             gint col,
871             gchar **cols,
872             gchar **name)
873 {
874 	gint *ret = ref;
875 
876 	*ret = cols [0] ? g_ascii_strtoll (cols[0], NULL, 10) : 0;
877 
878 	return 0;
879 }
880 
881 /* Collect the result of a SELECT count(*) statement */
882 static gint
get_count_cb(gpointer ref,gint n_cols,gchar ** cols,gchar ** name)883 get_count_cb (gpointer ref,
884               gint n_cols,
885               gchar **cols,
886               gchar **name)
887 {
888 	gint64 count = 0;
889 	gint *ret = ref;
890 	gint i;
891 
892 	for (i = 0; i < n_cols; i++) {
893 		if (name[i] && strncmp (name[i], "count", 5) == 0) {
894 			count = g_ascii_strtoll (cols[i], NULL, 10);
895 
896 			break;
897 		}
898 	}
899 
900 	*ret = count;
901 
902 	return 0;
903 }
904 
905 /* Report if there was at least one result */
906 static gint
get_exists_cb(gpointer ref,gint col,gchar ** cols,gchar ** name)907 get_exists_cb (gpointer ref,
908                gint col,
909                gchar **cols,
910                gchar **name)
911 {
912 	gboolean *exists = ref;
913 
914 	*exists = TRUE;
915 
916 	return 0;
917 }
918 
919 static EbSqlSearchData *
search_data_from_results(gint ncol,gchar ** cols,gchar ** names)920 search_data_from_results (gint ncol,
921                           gchar **cols,
922                           gchar **names)
923 {
924 	EbSqlSearchData *data = g_slice_new0 (EbSqlSearchData);
925 	gint i;
926 	const gchar *name;
927 
928 	for (i = 0; i < ncol; i++) {
929 
930 		if (!names[i] || !cols[i])
931 			continue;
932 
933 		name = names[i];
934 		if (!strncmp (name, "summary.", 8))
935 			name += 8;
936 
937 		/* These come through differently depending on the configuration,
938 		 * search within text is good enough
939 		 */
940 		if (!g_ascii_strcasecmp (name, "uid")) {
941 			data->uid = g_strdup (cols[i]);
942 		} else if (!g_ascii_strcasecmp (name, "vcard") ||
943 			   !g_ascii_strncasecmp (name, "fetch_vcard", 11)) {
944 			data->vcard = g_strdup (cols[i]);
945 		} else if (!g_ascii_strcasecmp (name, "bdata")) {
946 			data->extra = g_strdup (cols[i]);
947 		}
948 	}
949 
950 	return data;
951 }
952 
953 static gint
collect_full_results_cb(gpointer ref,gint ncol,gchar ** cols,gchar ** names)954 collect_full_results_cb (gpointer ref,
955                          gint ncol,
956                          gchar **cols,
957                          gchar **names)
958 {
959 	EbSqlSearchData *data;
960 	GSList **vcard_data = ref;
961 
962 	data = search_data_from_results (ncol, cols, names);
963 
964 	*vcard_data = g_slist_prepend (*vcard_data, data);
965 
966 	return 0;
967 }
968 
969 static gint
collect_uid_results_cb(gpointer ref,gint ncol,gchar ** cols,gchar ** names)970 collect_uid_results_cb (gpointer ref,
971                         gint ncol,
972                         gchar **cols,
973                         gchar **names)
974 {
975 	GSList **uids = ref;
976 
977 	if (cols[0])
978 		*uids = g_slist_prepend (*uids, g_strdup (cols [0]));
979 
980 	return 0;
981 }
982 
983 static gint
collect_lean_results_cb(gpointer ref,gint ncol,gchar ** cols,gchar ** names)984 collect_lean_results_cb (gpointer ref,
985                          gint ncol,
986                          gchar **cols,
987                          gchar **names)
988 {
989 	GSList **vcard_data = ref;
990 	EbSqlSearchData *search_data = g_slice_new0 (EbSqlSearchData);
991 	EContact *contact = e_contact_new ();
992 	gchar *vcard;
993 	gint i;
994 
995 	/* parse through cols, this will be useful if the api starts supporting field restrictions */
996 	for (i = 0; i < ncol; i++) {
997 		if (!names[i] || !cols[i])
998 			continue;
999 
1000 		/* Only UID & REV can be used to create contacts from the summary columns */
1001 		if (!g_ascii_strcasecmp (names[i], "uid")) {
1002 			e_contact_set (contact, E_CONTACT_UID, cols[i]);
1003 			search_data->uid = g_strdup (cols[i]);
1004 		} else if (!g_ascii_strcasecmp (names[i], "Rev")) {
1005 			e_contact_set (contact, E_CONTACT_REV, cols[i]);
1006 		} else if (!g_ascii_strcasecmp (names[i], "bdata")) {
1007 			search_data->extra = g_strdup (cols[i]);
1008 		}
1009 	}
1010 
1011 	vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
1012 	search_data->vcard = vcard;
1013 	*vcard_data = g_slist_prepend (*vcard_data, search_data);
1014 
1015 	g_object_unref (contact);
1016 	return 0;
1017 }
1018 
1019 static void
ebsql_string_append_vprintf(GString * string,const gchar * fmt,va_list args)1020 ebsql_string_append_vprintf (GString *string,
1021                              const gchar *fmt,
1022                              va_list args)
1023 {
1024 	gchar *stmt;
1025 
1026 	/* Unfortunately, sqlite3_vsnprintf() doesnt tell us
1027 	 * how many bytes it would have needed if it doesnt fit
1028 	 * into the target buffer, so we can't avoid this
1029 	 * really disgusting memory dup.
1030 	 */
1031 	stmt = sqlite3_vmprintf (fmt, args);
1032 	g_string_append (string, stmt);
1033 	sqlite3_free (stmt);
1034 }
1035 
1036 static void
ebsql_string_append_printf(GString * string,const gchar * fmt,...)1037 ebsql_string_append_printf (GString *string,
1038                             const gchar *fmt,
1039                             ...)
1040 {
1041 	va_list args;
1042 
1043 	va_start (args, fmt);
1044 	ebsql_string_append_vprintf (string, fmt, args);
1045 	va_end (args);
1046 }
1047 
1048 /* Appends an identifier suitable to identify the
1049  * column to test in the context of a query.
1050  *
1051  * The suffix is for special indexed columns (such as
1052  * reverse values, sort keys, phone numbers, etc).
1053  */
1054 static void
ebsql_string_append_column(GString * string,SummaryField * field,const gchar * suffix)1055 ebsql_string_append_column (GString *string,
1056                             SummaryField *field,
1057                             const gchar *suffix)
1058 {
1059 	if (field->aux_table) {
1060 		g_string_append (string, field->aux_table_symbolic);
1061 		g_string_append (string, ".value");
1062 	} else {
1063 		g_string_append (string, "summary.");
1064 		g_string_append (string, field->dbname);
1065 	}
1066 
1067 	if (suffix) {
1068 		g_string_append_c (string, '_');
1069 		g_string_append (string, suffix);
1070 	}
1071 }
1072 
1073 static gboolean
ebsql_exec_vprintf(EBookSqlite * ebsql,const gchar * fmt,EbSqlRowFunc callback,gpointer data,GCancellable * cancellable,GError ** error,va_list args)1074 ebsql_exec_vprintf (EBookSqlite *ebsql,
1075                     const gchar *fmt,
1076                     EbSqlRowFunc callback,
1077                     gpointer data,
1078                     GCancellable *cancellable,
1079                     GError **error,
1080                     va_list args)
1081 {
1082 	gboolean success;
1083 	gchar *stmt;
1084 
1085 	stmt = sqlite3_vmprintf (fmt, args);
1086 	success = ebsql_exec (ebsql, stmt, callback, data, cancellable, error);
1087 	sqlite3_free (stmt);
1088 
1089 	return success;
1090 }
1091 
1092 static gboolean
ebsql_exec_printf(EBookSqlite * ebsql,const gchar * fmt,EbSqlRowFunc callback,gpointer data,GCancellable * cancellable,GError ** error,...)1093 ebsql_exec_printf (EBookSqlite *ebsql,
1094                    const gchar *fmt,
1095                    EbSqlRowFunc callback,
1096                    gpointer data,
1097                    GCancellable *cancellable,
1098                    GError **error,
1099                    ...)
1100 {
1101 	gboolean success;
1102 	va_list args;
1103 
1104 	va_start (args, error);
1105 	success = ebsql_exec_vprintf (ebsql, fmt, callback, data, cancellable, error, args);
1106 	va_end (args);
1107 
1108 	return success;
1109 }
1110 
1111 static inline void
ebsql_exec_maybe_debug(EBookSqlite * ebsql,const gchar * stmt)1112 ebsql_exec_maybe_debug (EBookSqlite *ebsql,
1113                         const gchar *stmt)
1114 {
1115 	if (ebsql_debug_flags & EBSQL_DEBUG_EXPLAIN &&
1116 	    strncmp (stmt, "SELECT", 6) == 0) {
1117 		    g_printerr ("EXPLAIN BEGIN\n  STMT: %s\n", stmt);
1118 		    ebsql_exec_printf (ebsql, "EXPLAIN QUERY PLAN %s",
1119 				       ebsql_debug_query_plan_cb,
1120 				       NULL, NULL, NULL, stmt);
1121 		    g_printerr ("EXPLAIN END\n");
1122 	} else {
1123 		EBSQL_NOTE (STATEMENTS, g_printerr ("STMT: %s\n", stmt));
1124 	}
1125 }
1126 
1127 static gboolean
ebsql_exec(EBookSqlite * ebsql,const gchar * stmt,EbSqlRowFunc callback,gpointer data,GCancellable * cancellable,GError ** error)1128 ebsql_exec (EBookSqlite *ebsql,
1129             const gchar *stmt,
1130             EbSqlRowFunc callback,
1131             gpointer data,
1132             GCancellable *cancellable,
1133             GError **error)
1134 {
1135 	gboolean had_cancel;
1136 	gchar *errmsg = NULL;
1137 	gint ret = -1, retries = 0;
1138 	gint64 t1 = 0, t2;
1139 
1140 	g_return_val_if_fail (stmt != NULL, FALSE);
1141 
1142 	/* Debug output for statements and query plans */
1143 	ebsql_exec_maybe_debug (ebsql, stmt);
1144 
1145 	/* Just convenience to set the cancellable on an execution
1146 	 * without a transaction, error checking on the cancellable
1147 	 * is done with EBSQL_LOCK_OR_RETURN()
1148 	 */
1149 	if (ebsql->priv->cancel) {
1150 		had_cancel = TRUE;
1151 	} else {
1152 		ebsql->priv->cancel = cancellable;
1153 		had_cancel = FALSE;
1154 	}
1155 
1156 	if ((ebsql_debug_flags & EBSQL_DEBUG_TIMING) != 0 &&
1157 	    strncmp (stmt, "EXPLAIN QUERY PLAN ", 19) != 0)
1158 		t1 = g_get_monotonic_time();
1159 
1160 	ret = sqlite3_exec (ebsql->priv->db, stmt, callback, data, &errmsg);
1161 
1162 	while (ret == SQLITE_BUSY || ret == SQLITE_LOCKED || ret == -1) {
1163 		/* try for ~15 seconds, then give up */
1164 		if (retries > 150)
1165 			break;
1166 		retries++;
1167 
1168 		g_clear_pointer (&errmsg, sqlite3_free);
1169 		g_thread_yield ();
1170 		g_usleep (100 * 1000); /* Sleep for 100 ms */
1171 
1172 		if (t1)
1173 			t1 = g_get_monotonic_time();
1174 
1175 		ret = sqlite3_exec (ebsql->priv->db, stmt, callback, data, &errmsg);
1176 	}
1177 
1178 	if (!had_cancel)
1179 		ebsql->priv->cancel = NULL;
1180 
1181 	if (t1) {
1182 		t2 = g_get_monotonic_time();
1183 		g_printerr ("TIME: %" G_GINT64_FORMAT " ms\n", (t2 - t1) / 1000);
1184 	}
1185 	if (ret != SQLITE_OK) {
1186 		EBSQL_SET_ERROR_FROM_SQLITE (error, ret, errmsg);
1187 		sqlite3_free (errmsg);
1188 		return FALSE;
1189 	}
1190 
1191 	if (errmsg)
1192 		sqlite3_free (errmsg);
1193 
1194 	return TRUE;
1195 }
1196 
1197 static gboolean
ebsql_start_transaction(EBookSqlite * ebsql,EbSqlLockType lock_type,GCancellable * cancel,GError ** error)1198 ebsql_start_transaction (EBookSqlite *ebsql,
1199                          EbSqlLockType lock_type,
1200                          GCancellable *cancel,
1201                          GError **error)
1202 {
1203 	gboolean success = TRUE;
1204 
1205 	g_return_val_if_fail (ebsql != NULL, FALSE);
1206 	g_return_val_if_fail (ebsql->priv != NULL, FALSE);
1207 	g_return_val_if_fail (ebsql->priv->db != NULL, FALSE);
1208 
1209 	ebsql->priv->in_transaction++;
1210 	g_return_val_if_fail (ebsql->priv->in_transaction > 0, FALSE);
1211 
1212 	if (ebsql->priv->in_transaction == 1) {
1213 
1214 		/* No cancellable should be set at transaction start time */
1215 		if (ebsql->priv->cancel) {
1216 			g_warning (
1217 				"Starting a transaction with a cancellable already set. "
1218 				"Clearing previously set cancellable");
1219 			g_clear_object (&ebsql->priv->cancel);
1220 		}
1221 
1222 		/* Hold on to the cancel object until the end of the transaction */
1223 		if (cancel)
1224 			ebsql->priv->cancel = g_object_ref (cancel);
1225 
1226 		/* It's important to make the distinction between a
1227 		 * transaction which will read or one which will write.
1228 		 *
1229 		 * While it's not well documented, when receiving the SQLITE_BUSY
1230 		 * error status, one can only safely retry at the beginning of
1231 		 * the transaction.
1232 		 *
1233 		 * If a transaction is 'upgraded' to require a writer lock
1234 		 * half way through the transaction and SQLITE_BUSY is returned,
1235 		 * the whole transaction would need to be retried from the beginning.
1236 		 */
1237 		ebsql->priv->lock_type = lock_type;
1238 
1239 		switch (lock_type) {
1240 		case EBSQL_LOCK_READ:
1241 			success = ebsql_exec (ebsql, "BEGIN", NULL, NULL, NULL, error);
1242 			break;
1243 		case EBSQL_LOCK_WRITE:
1244 			success = ebsql_exec (ebsql, "BEGIN IMMEDIATE", NULL, NULL, NULL, error);
1245 			break;
1246 		}
1247 
1248 	} else {
1249 
1250 		/* Warn about cases where where a read transaction might be upgraded */
1251 		if (lock_type == EBSQL_LOCK_WRITE && ebsql->priv->lock_type == EBSQL_LOCK_READ)
1252 			g_warning (
1253 				"A nested transaction wants to write, "
1254 				"but the outermost transaction was started "
1255 				"without a writer lock.");
1256 	}
1257 
1258 	return success;
1259 }
1260 
1261 static gboolean
ebsql_commit_transaction(EBookSqlite * ebsql,GError ** error)1262 ebsql_commit_transaction (EBookSqlite *ebsql,
1263                           GError **error)
1264 {
1265 	gboolean success = TRUE;
1266 
1267 	g_return_val_if_fail (ebsql != NULL, FALSE);
1268 	g_return_val_if_fail (ebsql->priv != NULL, FALSE);
1269 	g_return_val_if_fail (ebsql->priv->db != NULL, FALSE);
1270 
1271 	g_return_val_if_fail (ebsql->priv->in_transaction > 0, FALSE);
1272 
1273 	ebsql->priv->in_transaction--;
1274 
1275 	if (ebsql->priv->in_transaction == 0) {
1276 		success = ebsql_exec (ebsql, "COMMIT", NULL, NULL, NULL, error);
1277 
1278 		/* The outermost transaction is finished, let's release
1279 		 * our reference to the user's cancel object here */
1280 		g_clear_object (&ebsql->priv->cancel);
1281 	}
1282 
1283 	return success;
1284 }
1285 
1286 static gboolean
ebsql_rollback_transaction(EBookSqlite * ebsql,GError ** error)1287 ebsql_rollback_transaction (EBookSqlite *ebsql,
1288                             GError **error)
1289 {
1290 	gboolean success = TRUE;
1291 
1292 	g_return_val_if_fail (ebsql != NULL, FALSE);
1293 	g_return_val_if_fail (ebsql->priv != NULL, FALSE);
1294 	g_return_val_if_fail (ebsql->priv->db != NULL, FALSE);
1295 
1296 	g_return_val_if_fail (ebsql->priv->in_transaction > 0, FALSE);
1297 
1298 	ebsql->priv->in_transaction--;
1299 
1300 	if (ebsql->priv->in_transaction == 0) {
1301 		success = ebsql_exec (ebsql, "ROLLBACK", NULL, NULL, NULL, error);
1302 
1303 		/* The outermost transaction is finished, let's release
1304 		 * our reference to the user's cancel object here */
1305 		g_clear_object (&ebsql->priv->cancel);
1306 	}
1307 	return success;
1308 }
1309 
1310 static sqlite3_stmt *
ebsql_prepare_statement(EBookSqlite * ebsql,const gchar * stmt_str,GError ** error)1311 ebsql_prepare_statement (EBookSqlite *ebsql,
1312                          const gchar *stmt_str,
1313                          GError **error)
1314 {
1315 	sqlite3_stmt *stmt;
1316 	const gchar *stmt_tail = NULL;
1317 	gint ret;
1318 
1319 	g_return_val_if_fail (stmt_str != NULL, NULL);
1320 
1321 	ret = sqlite3_prepare_v2 (ebsql->priv->db, stmt_str, strlen (stmt_str), &stmt, &stmt_tail);
1322 
1323 	if (ret != SQLITE_OK) {
1324 		const gchar *errmsg = sqlite3_errmsg (ebsql->priv->db);
1325 		EBSQL_SET_ERROR_LITERAL (
1326 			error,
1327 			E_BOOK_SQLITE_ERROR_ENGINE,
1328 			errmsg);
1329 	} else if (stmt == NULL) {
1330 		EBSQL_SET_ERROR_LITERAL (
1331 			error,
1332 			E_BOOK_SQLITE_ERROR_ENGINE,
1333 			"Unknown error preparing SQL statement");
1334 	}
1335 
1336 	if (stmt_tail && stmt_tail[0])
1337 		g_warning ("Part of this statement was not parsed: %s", stmt_tail);
1338 
1339 	return stmt;
1340 }
1341 
1342 /* Convenience for running statements. After successfully
1343  * binding all parameters, just return with this.
1344  */
1345 static gboolean
ebsql_complete_statement(EBookSqlite * ebsql,sqlite3_stmt * stmt,gint ret,GError ** error)1346 ebsql_complete_statement (EBookSqlite *ebsql,
1347                           sqlite3_stmt *stmt,
1348                           gint ret,
1349                           GError **error)
1350 {
1351 	if (ret == SQLITE_OK)
1352 		ret = sqlite3_step (stmt);
1353 
1354 	if (ret != SQLITE_OK && ret != SQLITE_DONE) {
1355 		const gchar *errmsg = sqlite3_errmsg (ebsql->priv->db);
1356 		EBSQL_SET_ERROR_FROM_SQLITE (error, ret, errmsg);
1357 	}
1358 
1359 	/* Reset / Clear at the end, regardless of error state */
1360 	sqlite3_reset (stmt);
1361 	sqlite3_clear_bindings (stmt);
1362 
1363 	return (ret == SQLITE_OK || ret == SQLITE_DONE);
1364 }
1365 
1366 /******************************************************
1367  *       Functions installed into the SQLite          *
1368  ******************************************************/
1369 
1370 /* Implementation for REGEXP keyword */
1371 static void
ebsql_regexp(sqlite3_context * context,gint argc,sqlite3_value ** argv)1372 ebsql_regexp (sqlite3_context *context,
1373               gint argc,
1374               sqlite3_value **argv)
1375 {
1376 	GRegex *regex;
1377 	const gchar *expression;
1378 	const gchar *text;
1379 
1380 	/* Reuse the same GRegex for all REGEXP queries with the same expression */
1381 	regex = sqlite3_get_auxdata (context, 0);
1382 	if (!regex) {
1383 		GError *error = NULL;
1384 
1385 		expression = (const gchar *) sqlite3_value_text (argv[0]);
1386 
1387 		regex = g_regex_new (expression, 0, 0, &error);
1388 
1389 		if (!regex) {
1390 			sqlite3_result_error (
1391 				context,
1392 				error ? error->message :
1393 				_("Error parsing regular expression"),
1394 				-1);
1395 			g_clear_error (&error);
1396 			return;
1397 		}
1398 
1399 		/* SQLite will take care of freeing the GRegex when we're done with the query */
1400 		sqlite3_set_auxdata (context, 0, regex, (GDestroyNotify) g_regex_unref);
1401 	}
1402 
1403 	/* Now perform the comparison */
1404 	text = (const gchar *) sqlite3_value_text (argv[1]);
1405 	if (text != NULL) {
1406 		gboolean match;
1407 
1408 		match = g_regex_match (regex, text, 0, NULL);
1409 		sqlite3_result_int (context, match ? 1 : 0);
1410 	}
1411 }
1412 
1413 /* Implementation of EBSQL_FUNC_COMPARE_VCARD (fallback for non-summary queries) */
1414 static void
ebsql_compare_vcard(sqlite3_context * context,gint argc,sqlite3_value ** argv)1415 ebsql_compare_vcard (sqlite3_context *context,
1416                      gint argc,
1417                      sqlite3_value **argv)
1418 {
1419 	EBookBackendSExp *sexp = NULL;
1420 	const gchar *text;
1421 	const gchar *vcard;
1422 
1423 	/* Reuse the same sexp for all queries with the same search expression */
1424 	sexp = sqlite3_get_auxdata (context, 0);
1425 	if (!sexp) {
1426 
1427 		/* The first argument will be reused for many rows */
1428 		text = (const gchar *) sqlite3_value_text (argv[0]);
1429 		if (text) {
1430 			sexp = e_book_backend_sexp_new (text);
1431 			sqlite3_set_auxdata (
1432 				context, 0,
1433 				sexp,
1434 				g_object_unref);
1435 		}
1436 
1437 		/* This shouldn't happen, catch invalid sexp in preflight */
1438 		if (!sexp) {
1439 			sqlite3_result_int (context, 0);
1440 			return;
1441 		}
1442 
1443 	}
1444 
1445 	/* Reuse the same vcard as much as possible (it can be referred to more than
1446 	 * once in the query, so it can be reused for multiple comparisons on the same row)
1447 	 *
1448 	 * This may look extensive, but as the vcard might be resolved by calling an
1449 	 * EbSqlVCardCallback, it's important to reuse this string as much as possible.
1450 	 *
1451 	 * See ebsql_fetch_vcard() for details.
1452 	 */
1453 	vcard = sqlite3_get_auxdata (context, 1);
1454 	if (!vcard) {
1455 		vcard = (const gchar *) sqlite3_value_text (argv[1]);
1456 
1457 		if (vcard)
1458 			sqlite3_set_auxdata (context, 1, g_strdup (vcard), g_free);
1459 	}
1460 
1461 	/* A NULL vcard can never match */
1462 	if (vcard == NULL || *vcard == '\0') {
1463 		sqlite3_result_int (context, 0);
1464 		return;
1465 	}
1466 
1467 	/* Compare this vcard */
1468 	if (e_book_backend_sexp_match_vcard (sexp, vcard))
1469 		sqlite3_result_int (context, 1);
1470 	else
1471 		sqlite3_result_int (context, 0);
1472 }
1473 
1474 static void
ebsql_eqphone(sqlite3_context * context,gint argc,sqlite3_value ** argv,EPhoneNumberMatch requested_match)1475 ebsql_eqphone (sqlite3_context *context,
1476                gint argc,
1477                sqlite3_value **argv,
1478                EPhoneNumberMatch requested_match)
1479 {
1480 	EBookSqlite *ebsql = sqlite3_user_data (context);
1481 	EPhoneNumber *input_phone = NULL, *row_phone = NULL;
1482 	EPhoneNumberMatch match = E_PHONE_NUMBER_MATCH_NONE;
1483 	const gchar *text;
1484 
1485 	/* Reuse the same phone number for all queries with the same phone number argument */
1486 	input_phone = sqlite3_get_auxdata (context, 0);
1487 	if (!input_phone) {
1488 
1489 		/* The first argument will be reused for many rows */
1490 		text = (const gchar *) sqlite3_value_text (argv[0]);
1491 		if (text) {
1492 
1493 			/* Ignore errors, they are fine for phone numbers */
1494 			input_phone = e_phone_number_from_string (text, ebsql->priv->region_code, NULL);
1495 
1496 			/* SQLite will take care of freeing the EPhoneNumber when we're done with the expression */
1497 			if (input_phone)
1498 				sqlite3_set_auxdata (
1499 					context, 0,
1500 					input_phone,
1501 					(GDestroyNotify) e_phone_number_free);
1502 		}
1503 	}
1504 
1505 	/* This shouldn't happen, as we catch invalid phone number queries in preflight
1506 	 */
1507 	if (!input_phone) {
1508 		sqlite3_result_int (context, 0);
1509 		return;
1510 	}
1511 
1512 	/* Parse the phone number for this row */
1513 	text = (const gchar *) sqlite3_value_text (argv[1]);
1514 	if (text != NULL) {
1515 		row_phone = e_phone_number_from_string (text, ebsql->priv->region_code, NULL);
1516 
1517 		/* And perform the comparison */
1518 		if (row_phone) {
1519 			match = e_phone_number_compare (input_phone, row_phone);
1520 
1521 			e_phone_number_free (row_phone);
1522 		}
1523 	}
1524 
1525 	/* Now report the result */
1526 	if (match != E_PHONE_NUMBER_MATCH_NONE &&
1527 	    match <= requested_match)
1528 		sqlite3_result_int (context, 1);
1529 	else
1530 		sqlite3_result_int (context, 0);
1531 }
1532 
1533 /* Exact phone number match function: EBSQL_FUNC_EQPHONE_EXACT */
1534 static void
ebsql_eqphone_exact(sqlite3_context * context,gint argc,sqlite3_value ** argv)1535 ebsql_eqphone_exact (sqlite3_context *context,
1536                      gint argc,
1537                      sqlite3_value **argv)
1538 {
1539 	ebsql_eqphone (context, argc, argv, E_PHONE_NUMBER_MATCH_EXACT);
1540 }
1541 
1542 /* National phone number match function: EBSQL_FUNC_EQPHONE_NATIONAL */
1543 static void
ebsql_eqphone_national(sqlite3_context * context,gint argc,sqlite3_value ** argv)1544 ebsql_eqphone_national (sqlite3_context *context,
1545                         gint argc,
1546                         sqlite3_value **argv)
1547 {
1548 	ebsql_eqphone (context, argc, argv, E_PHONE_NUMBER_MATCH_NATIONAL);
1549 }
1550 
1551 /* Short phone number match function: EBSQL_FUNC_EQPHONE_SHORT */
1552 static void
ebsql_eqphone_short(sqlite3_context * context,gint argc,sqlite3_value ** argv)1553 ebsql_eqphone_short (sqlite3_context *context,
1554                      gint argc,
1555                      sqlite3_value **argv)
1556 {
1557 	ebsql_eqphone (context, argc, argv, E_PHONE_NUMBER_MATCH_SHORT);
1558 }
1559 
1560 /* Implementation of EBSQL_FUNC_FETCH_VCARD (fallback for shallow addressbooks) */
1561 static void
ebsql_fetch_vcard(sqlite3_context * context,gint argc,sqlite3_value ** argv)1562 ebsql_fetch_vcard (sqlite3_context *context,
1563                    gint argc,
1564                    sqlite3_value **argv)
1565 {
1566 	EBookSqlite *ebsql = sqlite3_user_data (context);
1567 	const gchar *uid;
1568 	const gchar *extra;
1569 	gchar *vcard = NULL;
1570 
1571 	uid = (const gchar *) sqlite3_value_text (argv[0]);
1572 	extra = (const gchar *) sqlite3_value_text (argv[1]);
1573 
1574 	/* Call our delegate to generate the vcard */
1575 	if (ebsql->priv->vcard_callback)
1576 		vcard = ebsql->priv->vcard_callback (
1577 			uid, extra, ebsql->priv->user_data);
1578 
1579 	EBSQL_NOTE (
1580 		FETCH_VCARD,
1581 		g_printerr (
1582 			"fetch_vcard (%s, %s) %s",
1583 			uid, extra, vcard ? "Got VCard" : "No VCard"));
1584 
1585 	sqlite3_result_text (context, vcard, -1, g_free);
1586 }
1587 
1588 typedef struct {
1589 	const gchar     *name;
1590 	EbSqlCustomFunc  func;
1591 	gint             arguments;
1592 } EbSqlCustomFuncTab;
1593 
1594 static EbSqlCustomFuncTab ebsql_custom_functions[] = {
1595 	{ "regexp",                    ebsql_regexp,           2 }, /* regexp (expression, column_data) */
1596 	{ EBSQL_FUNC_COMPARE_VCARD,    ebsql_compare_vcard,    2 }, /* compare_vcard (sexp, vcard) */
1597 	{ EBSQL_FUNC_FETCH_VCARD,      ebsql_fetch_vcard,      2 }, /* fetch_vcard (uid, extra) */
1598 	{ EBSQL_FUNC_EQPHONE_EXACT,    ebsql_eqphone_exact,    2 }, /* eqphone_exact (search_input, column_data) */
1599 	{ EBSQL_FUNC_EQPHONE_NATIONAL, ebsql_eqphone_national, 2 }, /* eqphone_national (search_input, column_data) */
1600 	{ EBSQL_FUNC_EQPHONE_SHORT,    ebsql_eqphone_short,    2 }, /* eqphone_national (search_input, column_data) */
1601 };
1602 
1603 /******************************************************
1604  *            Fallback Collation Sequences            *
1605  ******************************************************
1606  *
1607  * The fallback simply compares vcards, vcards which have been
1608  * stored on the cursor will have a preencoded key (these
1609  * utilities encode & decode that key).
1610  */
1611 static gchar *
ebsql_encode_vcard_sort_key(const gchar * sort_key)1612 ebsql_encode_vcard_sort_key (const gchar *sort_key)
1613 {
1614 	EVCard *vcard = e_vcard_new ();
1615 	gchar *base64;
1616 	gchar *encoded;
1617 
1618 	/* Encode this otherwise e-vcard messes it up */
1619 	base64 = g_base64_encode ((const guchar *) sort_key, strlen (sort_key));
1620 	e_vcard_append_attribute_with_value (
1621 		vcard,
1622 		e_vcard_attribute_new (NULL, EBSQL_VCARD_SORT_KEY),
1623 		base64);
1624 	encoded = e_vcard_to_string (vcard, EVC_FORMAT_VCARD_30);
1625 
1626 	g_free (base64);
1627 	g_object_unref (vcard);
1628 
1629 	return encoded;
1630 }
1631 
1632 static gchar *
ebsql_decode_vcard_sort_key_from_vcard(EVCard * vcard)1633 ebsql_decode_vcard_sort_key_from_vcard (EVCard *vcard)
1634 {
1635 	EVCardAttribute *attr;
1636 	GList *values = NULL;
1637 	gchar *sort_key = NULL;
1638 	gchar *base64 = NULL;
1639 
1640 	attr = e_vcard_get_attribute (vcard, EBSQL_VCARD_SORT_KEY);
1641 	if (attr)
1642 		values = e_vcard_attribute_get_values (attr);
1643 
1644 	if (values && values->data) {
1645 		gsize len;
1646 
1647 		base64 = g_strdup (values->data);
1648 
1649 		sort_key = (gchar *) g_base64_decode (base64, &len);
1650 		g_free (base64);
1651 	}
1652 
1653 	return sort_key;
1654 }
1655 
1656 static gchar *
ebsql_decode_vcard_sort_key(const gchar * encoded)1657 ebsql_decode_vcard_sort_key (const gchar *encoded)
1658 {
1659 	EVCard *vcard;
1660 	gchar *sort_key;
1661 
1662 	vcard = e_vcard_new_from_string (encoded);
1663 	sort_key = ebsql_decode_vcard_sort_key_from_vcard (vcard);
1664 	g_object_unref (vcard);
1665 
1666 	return sort_key;
1667 }
1668 
1669 typedef struct {
1670 	EBookSqlite *ebsql;
1671 	EContactField field;
1672 } EbSqlCollData;
1673 
1674 static gint
ebsql_fallback_collator(gpointer ref,gint len1,gconstpointer data1,gint len2,gconstpointer data2)1675 ebsql_fallback_collator (gpointer ref,
1676                          gint len1,
1677                          gconstpointer data1,
1678                          gint len2,
1679                          gconstpointer data2)
1680 {
1681 	EbSqlCollData *data = (EbSqlCollData *) ref;
1682 	EBookSqlitePrivate *priv;
1683 	EContact *contact1, *contact2;
1684 	const gchar *str1, *str2;
1685 	gchar *key1, *key2;
1686 	gchar *tmp;
1687 	gint result = 0;
1688 
1689 	priv = data->ebsql->priv;
1690 
1691 	str1 = (const gchar *) data1;
1692 	str2 = (const gchar *) data2;
1693 
1694 	/* Construct 2 contacts (we're comparing vcards) */
1695 	contact1 = e_contact_new ();
1696 	contact2 = e_contact_new ();
1697 	e_vcard_construct_full (E_VCARD (contact1), str1, len1, NULL);
1698 	e_vcard_construct_full (E_VCARD (contact2), str2, len2, NULL);
1699 
1700 	/* Extract first key */
1701 	key1 = ebsql_decode_vcard_sort_key_from_vcard (E_VCARD (contact1));
1702 	if (!key1) {
1703 		tmp = e_contact_get (contact1, data->field);
1704 		if (tmp)
1705 			key1 = e_collator_generate_key (priv->collator, tmp, NULL);
1706 		g_free (tmp);
1707 	}
1708 	if (!key1)
1709 		key1 = g_strdup ("");
1710 
1711 	/* Extract second key */
1712 	key2 = ebsql_decode_vcard_sort_key_from_vcard (E_VCARD (contact2));
1713 	if (!key2) {
1714 		tmp = e_contact_get (contact2, data->field);
1715 		if (tmp)
1716 			key2 = e_collator_generate_key (priv->collator, tmp, NULL);
1717 		g_free (tmp);
1718 	}
1719 	if (!key2)
1720 		key2 = g_strdup ("");
1721 
1722 	result = strcmp (key1, key2);
1723 
1724 	g_free (key1);
1725 	g_free (key2);
1726 	g_object_unref (contact1);
1727 	g_object_unref (contact2);
1728 
1729 	return result;
1730 }
1731 
1732 static EbSqlCollData *
ebsql_coll_data_new(EBookSqlite * ebsql,EContactField field)1733 ebsql_coll_data_new (EBookSqlite *ebsql,
1734                      EContactField field)
1735 {
1736 	EbSqlCollData *data = g_slice_new (EbSqlCollData);
1737 
1738 	data->ebsql = ebsql;
1739 	data->field = field;
1740 
1741 	return data;
1742 }
1743 
1744 static void
ebsql_coll_data_free(EbSqlCollData * data)1745 ebsql_coll_data_free (EbSqlCollData *data)
1746 {
1747 	if (data)
1748 		g_slice_free (EbSqlCollData, data);
1749 }
1750 
1751 /* COLLATE functions are generated on demand only */
1752 static void
ebsql_generate_collator(gpointer ref,sqlite3 * db,gint eTextRep,const gchar * coll_name)1753 ebsql_generate_collator (gpointer ref,
1754                          sqlite3 *db,
1755                          gint eTextRep,
1756                          const gchar *coll_name)
1757 {
1758 	EBookSqlite *ebsql = (EBookSqlite *) ref;
1759 	EbSqlCollData *data;
1760 	EContactField field;
1761 	const gchar *field_name;
1762 
1763 	field_name = coll_name + strlen (EBSQL_COLLATE_PREFIX);
1764 	field = e_contact_field_id (field_name);
1765 
1766 	/* This should be caught before reaching here, just an extra check */
1767 	if (field == 0 || field >= E_CONTACT_FIELD_LAST ||
1768 	    e_contact_field_type (field) != G_TYPE_STRING) {
1769 		g_warning ("Specified collation on invalid contact field");
1770 		return;
1771 	}
1772 
1773 	data = ebsql_coll_data_new (ebsql, field);
1774 	sqlite3_create_collation_v2 (
1775 		db, coll_name, SQLITE_UTF8,
1776 		data, ebsql_fallback_collator,
1777 		(GDestroyNotify) ebsql_coll_data_free);
1778 }
1779 
1780 /**********************************************************
1781  *        Cancel long operations with GCancellable        *
1782  **********************************************************/
1783 static gint
ebsql_check_cancel(gpointer ref)1784 ebsql_check_cancel (gpointer ref)
1785 {
1786 	EBookSqlite *ebsql = (EBookSqlite *) ref;
1787 
1788 	if (ebsql->priv->cancel &&
1789 	    g_cancellable_is_cancelled (ebsql->priv->cancel)) {
1790 		EBSQL_NOTE (
1791 			CANCEL,
1792 			g_printerr ("CANCEL: An operation was cancelled\n"));
1793 		return -1;
1794 	}
1795 
1796 	return 0;
1797 }
1798 
1799 /**********************************************************
1800  *                  Database Initialization               *
1801  **********************************************************/
1802 static inline gint
main_table_index_by_name(const gchar * name)1803 main_table_index_by_name (const gchar *name)
1804 {
1805 	gint i;
1806 
1807 	for (i = 0; i < G_N_ELEMENTS (main_table_columns); i++) {
1808 		if (g_strcmp0 (name, main_table_columns[i].name) == 0)
1809 			return i;
1810 	}
1811 
1812 	return -1;
1813 }
1814 
1815 static gint
check_main_table_columns(gpointer data,gint n_cols,gchar ** cols,gchar ** name)1816 check_main_table_columns (gpointer data,
1817                           gint n_cols,
1818                           gchar **cols,
1819                           gchar **name)
1820 {
1821 	guint *columns_mask = (guint *) data;
1822 	gint i;
1823 
1824 	for (i = 0; i < n_cols; i++) {
1825 
1826 		if (g_strcmp0 (name[i], "name") == 0) {
1827 			gint idx = main_table_index_by_name (cols[i]);
1828 
1829 			if (idx >= 0)
1830 				*columns_mask |= (1 << idx);
1831 
1832 			break;
1833 		}
1834 	}
1835 
1836 	return 0;
1837 }
1838 
1839 static gboolean
ebsql_init_sqlite(EBookSqlite * ebsql,const gchar * filename,GError ** error)1840 ebsql_init_sqlite (EBookSqlite *ebsql,
1841                    const gchar *filename,
1842                    GError **error)
1843 {
1844 	gint ret, i;
1845 
1846 	e_sqlite3_vfs_init ();
1847 
1848 	ret = sqlite3_open (filename, &ebsql->priv->db);
1849 
1850 	/* Handle GCancellable */
1851 	sqlite3_progress_handler (
1852 		ebsql->priv->db,
1853 		EBSQL_CANCEL_BATCH_SIZE,
1854 		ebsql_check_cancel,
1855 		ebsql);
1856 
1857 	/* Install our custom functions */
1858 	for (i = 0; ret == SQLITE_OK && i < G_N_ELEMENTS (ebsql_custom_functions); i++)
1859 		ret = sqlite3_create_function (
1860 			ebsql->priv->db,
1861 			ebsql_custom_functions[i].name,
1862 			ebsql_custom_functions[i].arguments,
1863 			SQLITE_UTF8, ebsql,
1864 			ebsql_custom_functions[i].func,
1865 			NULL, NULL);
1866 
1867 	/* Fallback COLLATE implementations generated on demand */
1868 	if (ret == SQLITE_OK)
1869 		ret = sqlite3_collation_needed (
1870 			ebsql->priv->db, ebsql, ebsql_generate_collator);
1871 
1872 	if (ret != SQLITE_OK) {
1873 		if (!ebsql->priv->db) {
1874 			EBSQL_SET_ERROR_LITERAL (
1875 				error,
1876 				E_BOOK_SQLITE_ERROR_LOAD,
1877 				_("Insufficient memory"));
1878 		} else {
1879 			const gchar *errmsg = sqlite3_errmsg (ebsql->priv->db);
1880 
1881 			EBSQL_SET_ERROR (
1882 				error,
1883 				E_BOOK_SQLITE_ERROR_ENGINE,
1884 				"Can't open database %s: %s\n",
1885 				filename, errmsg);
1886 			sqlite3_close (ebsql->priv->db);
1887 		}
1888 		return FALSE;
1889 	}
1890 
1891 	ebsql_exec (ebsql, "ATTACH DATABASE ':memory:' AS mem", NULL, NULL, NULL, NULL);
1892 	ebsql_exec (ebsql, "PRAGMA foreign_keys = ON",          NULL, NULL, NULL, NULL);
1893 	ebsql_exec (ebsql, "PRAGMA case_sensitive_like = ON",   NULL, NULL, NULL, NULL);
1894 
1895 	return TRUE;
1896 }
1897 
1898 static inline void
format_column_declaration(GString * string,ColumnInfo * info)1899 format_column_declaration (GString *string,
1900                            ColumnInfo *info)
1901 {
1902 	g_string_append (string, info->name);
1903 	g_string_append_c (string, ' ');
1904 
1905 	g_string_append (string, info->type);
1906 
1907 	if (info->extra) {
1908 		g_string_append_c (string, ' ');
1909 		g_string_append (string, info->extra);
1910 	}
1911 }
1912 
1913 static inline gboolean
ensure_column_index(EBookSqlite * ebsql,const gchar * table,ColumnInfo * info,GError ** error)1914 ensure_column_index (EBookSqlite *ebsql,
1915                      const gchar *table,
1916                      ColumnInfo *info,
1917                      GError **error)
1918 {
1919 	if (!info->index)
1920 		return TRUE;
1921 
1922 	return ebsql_exec_printf (
1923 		ebsql,
1924 		"CREATE INDEX IF NOT EXISTS %Q ON %Q (%s)",
1925 		NULL, NULL, NULL, error,
1926 		info->index, table, info->name);
1927 }
1928 
1929 /* Called with the lock held and inside a transaction */
1930 static gboolean
ebsql_resolve_folderid(EBookSqlite * ebsql,gint * previous_schema,gint * already_exists,GError ** error)1931 ebsql_resolve_folderid (EBookSqlite *ebsql,
1932                         gint *previous_schema,
1933                         gint *already_exists,
1934                         GError **error)
1935 {
1936 	gint n_folders = 0;
1937 	gint version = 0;
1938 	gchar *loaded_folder_id = NULL;
1939 	gboolean success;
1940 
1941 	success = ebsql_exec (
1942 		ebsql, "SELECT count(*) FROM sqlite_master "
1943 		"WHERE type='table' AND name='folders';",
1944 		get_count_cb, &n_folders, NULL, error);
1945 
1946 	if (success && n_folders > 1) {
1947 		EBSQL_SET_ERROR_LITERAL (
1948 			error,
1949 			E_BOOK_SQLITE_ERROR_LOAD,
1950 			_("Cannot upgrade contacts database from a legacy "
1951 			"database with more than one addressbook. "
1952 			"Delete one of the entries in the “folders” table first."));
1953 		success = FALSE;
1954 	}
1955 
1956 	if (success && n_folders == 1)
1957 		success = ebsql_exec (
1958 			ebsql, "SELECT folder_id FROM folders LIMIT 1",
1959 			get_string_cb, &loaded_folder_id, NULL, error);
1960 
1961 	if (success && n_folders == 1)
1962 		success = ebsql_exec (
1963 			ebsql, "SELECT version FROM folders LIMIT 1",
1964 			get_int_cb, &version, NULL, error);
1965 
1966 	if (success && n_folders == 1) {
1967 		g_free (ebsql->priv->folderid);
1968 		ebsql->priv->folderid = loaded_folder_id;
1969 	} else {
1970 		g_free (loaded_folder_id);
1971 	}
1972 
1973 	if (n_folders == 1)
1974 		*already_exists = TRUE;
1975 	else
1976 		*already_exists = FALSE;
1977 
1978 	EBSQL_NOTE (
1979 		SCHEMA,
1980 		g_printerr (
1981 			"SCHEMA: main folder id resolved as '%s', "
1982 			"already existing tables: %d loaded version: %d (%s)\n",
1983 			ebsql->priv->folderid, n_folders, version,
1984 			success ? "success" : "failed"));
1985 
1986 	*previous_schema = version;
1987 
1988 	return success;
1989 }
1990 
1991 /* Called with the lock held and inside a transaction */
1992 static gboolean
ebsql_init_folders(EBookSqlite * ebsql,gint previous_schema,GError ** error)1993 ebsql_init_folders (EBookSqlite *ebsql,
1994                     gint previous_schema,
1995                     GError **error)
1996 {
1997 	GString *string;
1998 	guint existing_columns_mask = 0, i;
1999 	gboolean success;
2000 
2001 	string = g_string_sized_new (COLUMN_DEFINITION_BYTES * G_N_ELEMENTS (main_table_columns));
2002 	g_string_append (string, "CREATE TABLE IF NOT EXISTS folders (");
2003 	for (i = 0; i < G_N_ELEMENTS (main_table_columns); i++) {
2004 
2005 		if (i > 0)
2006 			g_string_append (string, ", ");
2007 
2008 		format_column_declaration (string, &(main_table_columns[i]));
2009 	}
2010 	g_string_append_c (string, ')');
2011 
2012 	/* Create main folders table */
2013 	success = ebsql_exec (ebsql, string->str, NULL, NULL, NULL, error);
2014 	g_string_free (string, TRUE);
2015 
2016 	/* Check which columns in the main table already exist */
2017 	if (success)
2018 		success = ebsql_exec (
2019 			ebsql, "PRAGMA table_info (folders)",
2020 			check_main_table_columns, &existing_columns_mask,
2021 			NULL, error);
2022 
2023 	/* Add columns which may be missing */
2024 	for (i = 0; success && i < G_N_ELEMENTS (main_table_columns); i++) {
2025 		ColumnInfo *info = &(main_table_columns[i]);
2026 
2027 		if ((existing_columns_mask & (1 << i)) != 0)
2028 			continue;
2029 
2030 		success = ebsql_exec_printf (
2031 			ebsql, "ALTER TABLE folders ADD COLUMN %s %s %s",
2032 			NULL, NULL, NULL, error, info->name, info->type,
2033 			info->extra ? info->extra : "");
2034 	}
2035 
2036 	/* Special case upgrade for schema versions 3 & 4.
2037 	 *
2038 	 * Drops the reverse_multivalues column.
2039 	 */
2040 	if (success && previous_schema >= 3 && previous_schema < 5) {
2041 
2042 		success = ebsql_exec (
2043 			ebsql,
2044 			"UPDATE folders SET "
2045 				"multivalues = REPLACE(RTRIM(REPLACE("
2046 					"multivalues || ':', ':', "
2047 					"CASE reverse_multivalues "
2048 						"WHEN 0 THEN ';prefix ' "
2049 						"ELSE ';prefix;suffix ' "
2050 					"END)), ' ', ':'), "
2051 				"reverse_multivalues = NULL",
2052 			NULL, NULL, NULL, error);
2053 	}
2054 
2055 	/* Finish the eventual upgrade by storing the current schema version.
2056 	 */
2057 	if (success && previous_schema >= 1 && previous_schema < FOLDER_VERSION)
2058 		success = ebsql_exec_printf (
2059 			ebsql, "UPDATE folders SET version = %d",
2060 			NULL, NULL, NULL, error, FOLDER_VERSION);
2061 
2062 	EBSQL_NOTE (
2063 		SCHEMA,
2064 		g_printerr (
2065 			"SCHEMA: Initialized main folders table (%s)\n",
2066 			success ? "success" : "failed"));
2067 
2068 	return success;
2069 }
2070 
2071 /* Called with the lock held and inside a transaction */
2072 static gboolean
ebsql_init_keys(EBookSqlite * ebsql,GError ** error)2073 ebsql_init_keys (EBookSqlite *ebsql,
2074                  GError **error)
2075 {
2076 	gboolean success;
2077 
2078 	/* Create a child table to store key/value pairs for a folder. */
2079 	success = ebsql_exec (
2080 		ebsql,
2081 		"CREATE TABLE IF NOT EXISTS keys ("
2082 		" key TEXT PRIMARY KEY,"
2083 		" value TEXT,"
2084 		" folder_id TEXT REFERENCES folders)",
2085 		NULL, NULL, NULL, error);
2086 
2087 	/* Add an index on the keys */
2088 	if (success)
2089 		success = ebsql_exec (
2090 			ebsql,
2091 			"CREATE INDEX IF NOT EXISTS keysindex ON keys (folder_id)",
2092 			NULL, NULL, NULL, error);
2093 
2094 	EBSQL_NOTE (
2095 		SCHEMA,
2096 		g_printerr (
2097 			"SCHEMA: Initialized keys table (%s)\n",
2098 			success ? "success" : "failed"));
2099 
2100 	return success;
2101 }
2102 
2103 static gchar *
format_multivalues(EBookSqlite * ebsql)2104 format_multivalues (EBookSqlite *ebsql)
2105 {
2106 	gint i;
2107 	GString *string;
2108 	gboolean first = TRUE;
2109 
2110 	string = g_string_new (NULL);
2111 
2112 	for (i = 0; i < ebsql->priv->n_summary_fields; i++) {
2113 		if (ebsql->priv->summary_fields[i].type == E_TYPE_CONTACT_ATTR_LIST) {
2114 			if (first)
2115 				first = FALSE;
2116 			else
2117 				g_string_append_c (string, ':');
2118 
2119 			g_string_append (string, ebsql->priv->summary_fields[i].dbname);
2120 
2121 			/* E_BOOK_INDEX_SORT_KEY is not supported in the multivalue fields */
2122 			if ((ebsql->priv->summary_fields[i].index & INDEX_FLAG (PREFIX)) != 0)
2123 				g_string_append (string, ";prefix");
2124 			if ((ebsql->priv->summary_fields[i].index & INDEX_FLAG (SUFFIX)) != 0)
2125 				g_string_append (string, ";suffix");
2126 			if ((ebsql->priv->summary_fields[i].index & INDEX_FLAG (PHONE)) != 0)
2127 				g_string_append (string, ";phone");
2128 		}
2129 	}
2130 
2131 	return g_string_free (string, string->len == 0);
2132 }
2133 
2134 /* Called with the lock held and inside a transaction */
2135 static gboolean
ebsql_add_folder(EBookSqlite * ebsql,GError ** error)2136 ebsql_add_folder (EBookSqlite *ebsql,
2137                   GError **error)
2138 {
2139 	gboolean success;
2140 	gchar *multivalues;
2141 	const gchar *lc_collate;
2142 
2143 	multivalues = format_multivalues (ebsql);
2144 	lc_collate = setlocale (LC_COLLATE, NULL);
2145 
2146 	success = ebsql_exec_printf (
2147 		ebsql,
2148 		"INSERT OR IGNORE INTO folders"
2149 		" ( folder_id, version, multivalues, lc_collate ) "
2150 		"VALUES ( %Q, %d, %Q, %Q ) ",
2151 		NULL, NULL, NULL, error,
2152 		ebsql->priv->folderid, FOLDER_VERSION, multivalues, lc_collate);
2153 
2154 	g_free (multivalues);
2155 
2156 	EBSQL_NOTE (
2157 		SCHEMA,
2158 		g_printerr (
2159 			"SCHEMA: Added '%s' entry to main folder (%s)\n",
2160 			ebsql->priv->folderid, success ? "success" : "failed"));
2161 
2162 	return success;
2163 }
2164 
2165 static gboolean
ebsql_email_list_exists(EBookSqlite * ebsql)2166 ebsql_email_list_exists (EBookSqlite *ebsql)
2167 {
2168 	gint n_tables = 0;
2169 	gboolean success;
2170 
2171 	success = ebsql_exec_printf (
2172 		ebsql, "SELECT count(*) FROM sqlite_master WHERE type='table' AND name='%q_email_list';",
2173 		get_count_cb, &n_tables, NULL, NULL,
2174 		ebsql->priv->folderid);
2175 
2176 	if (!success)
2177 		return FALSE;
2178 
2179 	return n_tables == 1;
2180 }
2181 
2182 /* Called with the lock held and inside a transaction */
2183 static gboolean
ebsql_introspect_summary(EBookSqlite * ebsql,gint previous_schema,GSList ** introspected_columns,GError ** error)2184 ebsql_introspect_summary (EBookSqlite *ebsql,
2185                           gint previous_schema,
2186                           GSList **introspected_columns,
2187                           GError **error)
2188 {
2189 	gboolean success;
2190 	GSList *summary_columns = NULL, *l;
2191 	GArray *summary_fields = NULL;
2192 	gchar *multivalues = NULL;
2193 	gint i, j;
2194 
2195 	success = ebsql_exec_printf (
2196 		ebsql, "PRAGMA table_info (%Q);",
2197 		get_columns_cb, &summary_columns, NULL, error,
2198 		ebsql->priv->folderid);
2199 
2200 	if (!success)
2201 		goto introspect_summary_finish;
2202 
2203 	summary_columns = g_slist_reverse (summary_columns);
2204 	summary_fields = g_array_new (FALSE, FALSE, sizeof (SummaryField));
2205 
2206 	/* Introspect the normal summary fields */
2207 	for (l = summary_columns; l; l = l->next) {
2208 		EContactField field_id;
2209 		const gchar *col = l->data;
2210 		gchar *p;
2211 		gint computed = 0;
2212 		gchar *freeme = NULL;
2213 
2214 		/* Note that we don't have any way to introspect
2215 		 * E_BOOK_INDEX_PREFIX, this is not important because if
2216 		 * the prefix index is specified, it will be created
2217 		 * the first time the SQLite tables are created, so
2218 		 * it's not important to ensure prefix indexes after
2219 		 * introspecting the summary.
2220 		 */
2221 
2222 		/* Check if we're parsing a reverse field */
2223 		if ((p = strstr (col, "_" EBSQL_SUFFIX_REVERSE)) != NULL) {
2224 			computed = INDEX_FLAG (SUFFIX);
2225 			freeme = g_strndup (col, p - col);
2226 			col = freeme;
2227 		} else if ((p = strstr (col, "_" EBSQL_SUFFIX_PHONE)) != NULL) {
2228 			computed = INDEX_FLAG (PHONE);
2229 			freeme = g_strndup (col, p - col);
2230 			col = freeme;
2231 		} else if ((p = strstr (col, "_" EBSQL_SUFFIX_COUNTRY)) != NULL) {
2232 			computed = INDEX_FLAG (PHONE);
2233 			freeme = g_strndup (col, p - col);
2234 			col = freeme;
2235 		} else if ((p = strstr (col, "_" EBSQL_SUFFIX_SORT_KEY)) != NULL) {
2236 			computed = INDEX_FLAG (SORT_KEY);
2237 			freeme = g_strndup (col, p - col);
2238 			col = freeme;
2239 		}
2240 
2241 		/* First check exception fields */
2242 		if (g_ascii_strcasecmp (col, "uid") == 0)
2243 			field_id = E_CONTACT_UID;
2244 		else if (g_ascii_strcasecmp (col, "is_list") == 0)
2245 			field_id = E_CONTACT_IS_LIST;
2246 		else
2247 			field_id = e_contact_field_id (col);
2248 
2249 		/* Check for parse error */
2250 		if (field_id == 0) {
2251 			EBSQL_SET_ERROR (
2252 				error,
2253 				E_BOOK_SQLITE_ERROR_UNSUPPORTED_FIELD,
2254 				_("Error introspecting unknown summary field “%s”"),
2255 				col);
2256 			success = FALSE;
2257 			g_free (freeme);
2258 			break;
2259 		}
2260 
2261 		/* Computed columns are always declared after the normal columns,
2262 		 * if a reverse field is encountered we need to set the suffix
2263 		 * index on the coresponding summary field
2264 		 */
2265 		if (computed) {
2266 			gint field_idx;
2267 			SummaryField *iter;
2268 
2269 			field_idx = summary_field_array_index (summary_fields, field_id);
2270 			if (field_idx >= 0) {
2271 				iter = &g_array_index (summary_fields, SummaryField, field_idx);
2272 				iter->index |= computed;
2273 			}
2274 
2275 		} else {
2276 			summary_field_append (
2277 				summary_fields, ebsql->priv->folderid,
2278 				field_id, NULL);
2279 		}
2280 
2281 		g_free (freeme);
2282 	}
2283 
2284 	if (!success)
2285 		goto introspect_summary_finish;
2286 
2287 	/* Introspect the multivalied summary fields */
2288 	success = ebsql_exec_printf (
2289 		ebsql,
2290 		"SELECT multivalues FROM folders "
2291 		"WHERE folder_id = %Q",
2292 		get_string_cb, &multivalues, NULL, error,
2293 		ebsql->priv->folderid);
2294 
2295 	if (!success)
2296 		goto introspect_summary_finish;
2297 
2298 	if (!multivalues || !*multivalues) {
2299 		g_free (multivalues);
2300 		multivalues = NULL;
2301 
2302 		/* The migration from a previous version didn't store this default multivalue
2303 		   reference, thus the next backend open (not the immediate one after migration),
2304 		   didn't know about this table, which has a FOREIGN KEY constraint, thus an item
2305 		   delete caused a 'FOREIGN KEY constraint failed' error.
2306 		*/
2307 		if (ebsql_email_list_exists (ebsql))
2308 			multivalues = g_strdup ("email;prefix");
2309 	}
2310 
2311 	if (multivalues) {
2312 		gchar **fields = g_strsplit (multivalues, ":", 0);
2313 
2314 		for (i = 0; fields[i] != NULL; i++) {
2315 			EContactField field_id;
2316 			SummaryField *iter;
2317 			gchar **params;
2318 
2319 			params = g_strsplit (fields[i], ";", 0);
2320 			field_id = e_contact_field_id (params[0]);
2321 			iter = summary_field_append (
2322 				summary_fields,
2323 				ebsql->priv->folderid,
2324 				field_id, NULL);
2325 
2326 			if (iter) {
2327 				for (j = 1; params[j]; ++j) {
2328 					/* Sort keys not supported for multivalued fields */
2329 					if (strcmp (params[j], "prefix") == 0) {
2330 						iter->index |= INDEX_FLAG (PREFIX);
2331 					} else if (strcmp (params[j], "suffix") == 0) {
2332 						iter->index |= INDEX_FLAG (SUFFIX);
2333 					} else if (strcmp (params[j], "phone") == 0) {
2334 						iter->index |= INDEX_FLAG (PHONE);
2335 					}
2336 				}
2337 			}
2338 
2339 			g_strfreev (params);
2340 		}
2341 
2342 		g_strfreev (fields);
2343 	}
2344 
2345 	/* HARD CODE UP AHEAD
2346 	 *
2347 	 * Now we're finished introspecting, if the summary is from a previous version,
2348 	 * we need to add any summary fields which we're added to the default summary
2349 	 * since the schema version which was introduced here
2350 	 */
2351 	if (previous_schema >= 1) {
2352 		SummaryField *summary_field;
2353 
2354 		if (previous_schema < 8) {
2355 
2356 			/* We used to keep 4 email fields in the summary, before we supported
2357 			 * the multivaliued E_CONTACT_EMAIL... convert the old summary to use
2358 			 * the multivaliued field instead.
2359 			 */
2360 			if (summary_field_array_index (summary_fields, E_CONTACT_EMAIL_1) >= 0 &&
2361 			    summary_field_array_index (summary_fields, E_CONTACT_EMAIL_2) >= 0 &&
2362 			    summary_field_array_index (summary_fields, E_CONTACT_EMAIL_3) >= 0 &&
2363 			    summary_field_array_index (summary_fields, E_CONTACT_EMAIL_4) >= 0) {
2364 
2365 				summary_field_remove (summary_fields, E_CONTACT_EMAIL_1);
2366 				summary_field_remove (summary_fields, E_CONTACT_EMAIL_2);
2367 				summary_field_remove (summary_fields, E_CONTACT_EMAIL_3);
2368 				summary_field_remove (summary_fields, E_CONTACT_EMAIL_4);
2369 
2370 				summary_field = summary_field_append (
2371 					summary_fields,
2372 					ebsql->priv->folderid,
2373 					E_CONTACT_EMAIL, NULL);
2374 				summary_field->index |= INDEX_FLAG (PREFIX);
2375 			}
2376 
2377 			/* Regardless of whether it was a default summary or not, add the sort
2378 			 * keys to anything less than Schema 8 (as long as those fields are at least
2379 			 * in the summary)
2380 			 */
2381 			if ((i = summary_field_array_index (summary_fields, E_CONTACT_FILE_AS)) >= 0) {
2382 				summary_field = &g_array_index (summary_fields, SummaryField, i);
2383 				summary_field->index |= INDEX_FLAG (SORT_KEY);
2384 			}
2385 
2386 			if ((i = summary_field_array_index (summary_fields, E_CONTACT_GIVEN_NAME)) >= 0) {
2387 				summary_field = &g_array_index (summary_fields, SummaryField, i);
2388 				summary_field->index |= INDEX_FLAG (SORT_KEY);
2389 			}
2390 
2391 			if ((i = summary_field_array_index (summary_fields, E_CONTACT_FAMILY_NAME)) >= 0) {
2392 				summary_field = &g_array_index (summary_fields, SummaryField, i);
2393 				summary_field->index |= INDEX_FLAG (SORT_KEY);
2394 			}
2395 		}
2396 
2397 		if (previous_schema < 9) {
2398 			if (summary_field_array_index (summary_fields, E_CONTACT_X509_CERT) < 0) {
2399 				summary_field_append (summary_fields, ebsql->priv->folderid,
2400 						      E_CONTACT_X509_CERT, NULL);
2401 			}
2402 		}
2403 
2404 		if (previous_schema < 10) {
2405 			if ((i = summary_field_array_index (summary_fields, E_CONTACT_NICKNAME)) >= 0) {
2406 				summary_field = &g_array_index (summary_fields, SummaryField, i);
2407 				summary_field->index |= INDEX_FLAG (PREFIX);
2408 			}
2409 
2410 			if ((i = summary_field_array_index (summary_fields, E_CONTACT_FILE_AS)) >= 0) {
2411 				summary_field = &g_array_index (summary_fields, SummaryField, i);
2412 				summary_field->index |= INDEX_FLAG (PREFIX);
2413 			}
2414 
2415 			if ((i = summary_field_array_index (summary_fields, E_CONTACT_GIVEN_NAME)) >= 0) {
2416 				summary_field = &g_array_index (summary_fields, SummaryField, i);
2417 				summary_field->index |= INDEX_FLAG (PREFIX);
2418 			}
2419 
2420 			if ((i = summary_field_array_index (summary_fields, E_CONTACT_FAMILY_NAME)) >= 0) {
2421 				summary_field = &g_array_index (summary_fields, SummaryField, i);
2422 				summary_field->index |= INDEX_FLAG (PREFIX);
2423 			}
2424 
2425 		}
2426 
2427 		if (previous_schema < 12) {
2428 			if (summary_field_array_index (summary_fields, E_CONTACT_PGP_CERT) < 0) {
2429 				summary_field_append (summary_fields, ebsql->priv->folderid,
2430 						      E_CONTACT_PGP_CERT, NULL);
2431 			}
2432 		}
2433 	}
2434 
2435  introspect_summary_finish:
2436 
2437 	/* Apply the introspected summary fields */
2438 	if (success) {
2439 		summary_fields_array_free (
2440 			ebsql->priv->summary_fields,
2441 			ebsql->priv->n_summary_fields);
2442 
2443 		ebsql->priv->n_summary_fields = summary_fields->len;
2444 		ebsql->priv->summary_fields = (SummaryField *) g_array_free (summary_fields, FALSE);
2445 
2446 		*introspected_columns = summary_columns;
2447 	} else if (summary_fields) {
2448 		gint n_fields;
2449 		SummaryField *fields;
2450 
2451 		/* Properly free the array */
2452 		n_fields = summary_fields->len;
2453 		fields = (SummaryField *) g_array_free (summary_fields, FALSE);
2454 		summary_fields_array_free (fields, n_fields);
2455 
2456 		g_slist_free_full (summary_columns, (GDestroyNotify) g_free);
2457 	}
2458 
2459 	g_free (multivalues);
2460 
2461 	EBSQL_NOTE (
2462 		SCHEMA,
2463 		g_printerr (
2464 			"SCHEMA: Introspected summary (%s)\n",
2465 			success ? "success" : "failed"));
2466 
2467 	return success;
2468 }
2469 
2470 /* Called with the lock held and inside a transaction */
2471 static gboolean
ebsql_init_contacts(EBookSqlite * ebsql,GSList * introspected_columns,GError ** error)2472 ebsql_init_contacts (EBookSqlite *ebsql,
2473                      GSList *introspected_columns,
2474                      GError **error)
2475 {
2476 	gint i;
2477 	gboolean success = TRUE;
2478 	GString *string;
2479 	GSList *summary_columns = NULL, *l;
2480 
2481 	/* Get a list of all columns and indexes which should be present
2482 	 * in the main summary table */
2483 	for (i = 0; i < ebsql->priv->n_summary_fields; i++) {
2484 		SummaryField *field = &(ebsql->priv->summary_fields[i]);
2485 
2486 		if (field->type != E_TYPE_CONTACT_ATTR_LIST) {
2487 			l = summary_field_list_columns (field, ebsql->priv->folderid);
2488 			summary_columns = g_slist_concat (summary_columns, l);
2489 		}
2490 	}
2491 
2492 	/* Create the main contacts table for this folder
2493 	 */
2494 	string = g_string_sized_new (32 * g_slist_length (summary_columns));
2495 	g_string_append (string, "CREATE TABLE IF NOT EXISTS %Q (");
2496 
2497 	for (l = summary_columns; l; l = l->next) {
2498 		ColumnInfo *info = l->data;
2499 
2500 		if (l != summary_columns)
2501 			g_string_append (string, ", ");
2502 
2503 		format_column_declaration (string, info);
2504 	}
2505 	g_string_append (string, ", vcard TEXT, bdata TEXT)");
2506 
2507 	success = ebsql_exec_printf (
2508 		ebsql, string->str,
2509 		NULL, NULL, NULL, error,
2510 		ebsql->priv->folderid);
2511 
2512 	g_string_free (string, TRUE);
2513 
2514 	/* If we introspected something, let's first adjust the contacts table
2515 	 * so that it includes the right columns */
2516 	if (introspected_columns) {
2517 
2518 		/* Add any missing columns which are in the summary fields but
2519 		 * not found in the contacts table
2520 		 */
2521 		for (l = summary_columns; success && l; l = l->next) {
2522 			ColumnInfo *info = l->data;
2523 
2524 			if (g_slist_find_custom (introspected_columns,
2525 						 info->name, (GCompareFunc) g_ascii_strcasecmp))
2526 				continue;
2527 
2528 			success = ebsql_exec_printf (
2529 				ebsql,
2530 				"ALTER TABLE %Q ADD COLUMN %s %s %s",
2531 				NULL, NULL, NULL, error,
2532 				ebsql->priv->folderid,
2533 				info->name, info->type,
2534 				info->extra ? info->extra : "");
2535 		}
2536 	}
2537 
2538 	/* Add indexes to columns in the main contacts table
2539 	 */
2540 	for (l = summary_columns; success && l; l = l->next) {
2541 		ColumnInfo *info = l->data;
2542 
2543 		success = ensure_column_index (ebsql, ebsql->priv->folderid, info, error);
2544 	}
2545 
2546 	g_slist_free_full (summary_columns, (GDestroyNotify) column_info_free);
2547 
2548 	EBSQL_NOTE (
2549 		SCHEMA,
2550 		g_printerr (
2551 			"SCHEMA: Initialized summary table '%s' (%s)\n",
2552 			ebsql->priv->folderid, success ? "success" : "failed"));
2553 
2554 	return success;
2555 }
2556 
2557 /* Called with the lock held and inside a transaction */
2558 static gboolean
ebsql_init_aux_tables(EBookSqlite * ebsql,gint previous_schema,GError ** error)2559 ebsql_init_aux_tables (EBookSqlite *ebsql,
2560                        gint previous_schema,
2561                        GError **error)
2562 {
2563 	GString *string;
2564 	gboolean success = TRUE;
2565 	GSList *aux_columns = NULL, *l;
2566 	gchar *tmp;
2567 	gint i;
2568 
2569 	/* Drop the general 'folder_id_lists' table which was used prior to
2570 	 * version 8 of the schema
2571 	 */
2572 	if (previous_schema >= 1 && previous_schema < 8) {
2573 		tmp = g_strconcat (ebsql->priv->folderid, "_lists", NULL);
2574 		success = ebsql_exec_printf (
2575 			ebsql, "DROP TABLE IF EXISTS %Q",
2576 			NULL, NULL, NULL, error, tmp);
2577 		g_free (tmp);
2578 	}
2579 
2580 	for (i = 0; success && i < ebsql->priv->n_summary_fields; i++) {
2581 		SummaryField *field = &(ebsql->priv->summary_fields[i]);
2582 
2583 		if (field->type != E_TYPE_CONTACT_ATTR_LIST)
2584 			continue;
2585 
2586 		aux_columns = summary_field_list_columns (field, ebsql->priv->folderid);
2587 
2588 		/* Create the auxiliary table for this multi valued field */
2589 		string = g_string_sized_new (
2590 			COLUMN_DEFINITION_BYTES * 3 +
2591 			COLUMN_DEFINITION_BYTES * g_slist_length (aux_columns));
2592 
2593 		g_string_append (string, "CREATE TABLE IF NOT EXISTS %Q (uid TEXT NOT NULL REFERENCES %Q (uid)");
2594 		for (l = aux_columns; l; l = l->next) {
2595 			ColumnInfo *info = l->data;
2596 
2597 			g_string_append (string, ", ");
2598 			format_column_declaration (string, info);
2599 		}
2600 		g_string_append_c (string, ')');
2601 
2602 		success = ebsql_exec_printf (
2603 			ebsql, string->str, NULL, NULL, NULL, error,
2604 			field->aux_table, ebsql->priv->folderid);
2605 		g_string_free (string, TRUE);
2606 
2607 		if (success) {
2608 
2609 			/* Create an index on the implied 'uid' column, this is important
2610 			 * when replacing (modifying) contacts, since we need to remove
2611 			 * all rows in an auxiliary table which matches a given UID.
2612 			 *
2613 			 * This index speeds up the constraint in a statement such as:
2614 			 *
2615 			 *   DELETE from email_list WHERE email_list.uid = 'contact uid'
2616 			 */
2617 			tmp = g_strconcat (
2618 				"UID_INDEX",
2619 				"_", field->dbname,
2620 				"_", ebsql->priv->folderid,
2621 				NULL);
2622 			ebsql_exec_printf (
2623 				ebsql,
2624 				"CREATE INDEX IF NOT EXISTS %Q ON %Q (%s)",
2625 				NULL, NULL, NULL, error,
2626 				tmp, field->aux_table, "uid");
2627 			g_free (tmp);
2628 		}
2629 
2630 		/* Add indexes to columns in this auxiliary table
2631 		 */
2632 		for (l = aux_columns; success && l; l = l->next) {
2633 			ColumnInfo *info = l->data;
2634 
2635 			success = ensure_column_index (ebsql, field->aux_table, info, error);
2636 		}
2637 
2638 		g_slist_free_full (aux_columns, (GDestroyNotify) column_info_free);
2639 
2640 		EBSQL_NOTE (
2641 			SCHEMA,
2642 			g_printerr (
2643 				"SCHEMA: Initialized auxiliary table '%s'\n",
2644 				field->aux_table));
2645 	}
2646 
2647 	if (success) {
2648 		gchar *multivalues;
2649 
2650 		multivalues = format_multivalues (ebsql);
2651 
2652 		success = ebsql_exec_printf (
2653 			ebsql,
2654 			"UPDATE folders SET multivalues=%Q WHERE folder_id=%Q",
2655 			NULL, NULL, NULL, error,
2656 			multivalues, ebsql->priv->folderid);
2657 
2658 		g_free (multivalues);
2659 	}
2660 
2661 	EBSQL_NOTE (
2662 		SCHEMA,
2663 		g_printerr (
2664 			"SCHEMA: Initialized auxiliary tables (%s)\n",
2665 			success ? "success" : "failed"));
2666 
2667 	return success;
2668 }
2669 
2670 static gboolean
ebsql_upgrade_one(EBookSqlite * ebsql,EbSqlChangeType change_type,EbSqlSearchData * result,GError ** error)2671 ebsql_upgrade_one (EBookSqlite *ebsql,
2672                    EbSqlChangeType change_type,
2673                    EbSqlSearchData *result,
2674                    GError **error)
2675 {
2676 	EContact *contact = NULL;
2677 	gboolean success;
2678 
2679 	/* It can be we're opening a light summary which was created without
2680 	 * storing the vcards, such as was used in EDS versions 3.2 to 3.6.
2681 	 *
2682 	 * In this case we just want to skip the contacts we can't load
2683 	 * and leave them as is in the SQLite, they will be added from
2684 	 * the old BDB in the case of a migration anyway.
2685 	 */
2686 	if (result->vcard)
2687 		contact = e_contact_new_from_vcard_with_uid (result->vcard, result->uid);
2688 
2689 	if (contact == NULL)
2690 		return TRUE;
2691 
2692 	success = ebsql_insert_contact (
2693 		ebsql, change_type, contact,
2694 		result->vcard, result->extra,
2695 		TRUE, error);
2696 
2697 	g_object_unref (contact);
2698 
2699 	return success;
2700 }
2701 
2702 /* Called with the lock held and inside a transaction */
2703 static gboolean
ebsql_upgrade(EBookSqlite * ebsql,EbSqlChangeType change_type,GError ** error)2704 ebsql_upgrade (EBookSqlite *ebsql,
2705                EbSqlChangeType change_type,
2706                GError **error)
2707 {
2708 	gchar *uid = NULL;
2709 	gint n_results;
2710 	gboolean success = TRUE;
2711 
2712 	do {
2713 		GSList *batch = NULL, *l;
2714 		EbSqlSearchData *result = NULL;
2715 
2716 		if (uid == NULL) {
2717 			success = ebsql_exec_printf (
2718 				ebsql,
2719 				"SELECT summary.uid, %s, summary.bdata FROM %Q AS summary "
2720 				"ORDER BY summary.uid ASC LIMIT %d",
2721 				collect_full_results_cb, &batch, NULL, error,
2722 				EBSQL_VCARD_FRAGMENT (ebsql),
2723 				ebsql->priv->folderid, EBSQL_UPGRADE_BATCH_SIZE);
2724 		} else {
2725 			success = ebsql_exec_printf (
2726 				ebsql,
2727 				"SELECT summary.uid, %s, summary.bdata FROM %Q AS summary "
2728 				"WHERE summary.uid > %Q "
2729 				"ORDER BY summary.uid ASC LIMIT %d",
2730 				collect_full_results_cb, &batch, NULL, error,
2731 				EBSQL_VCARD_FRAGMENT (ebsql),
2732 				ebsql->priv->folderid, uid, EBSQL_UPGRADE_BATCH_SIZE);
2733 		}
2734 
2735 		/* Reverse the list, we want to walk through it forwards */
2736 		batch = g_slist_reverse (batch);
2737 		for (l = batch; success && l; l = l->next) {
2738 			result = l->data;
2739 			success = ebsql_upgrade_one (
2740 				ebsql,
2741 				change_type,
2742 				result,
2743 				error);
2744 		}
2745 
2746 		/* result is now the last one in the list */
2747 		if (result) {
2748 			g_free (uid);
2749 			uid = result->uid;
2750 			result->uid = NULL;
2751 		}
2752 
2753 		n_results = g_slist_length (batch);
2754 		g_slist_free_full (batch, (GDestroyNotify) e_book_sqlite_search_data_free);
2755 
2756 	} while (success && n_results == EBSQL_UPGRADE_BATCH_SIZE);
2757 
2758 	g_free (uid);
2759 
2760 	/* Store the new locale & country code */
2761 	if (success)
2762 		success = ebsql_exec_printf (
2763 			ebsql, "UPDATE folders SET countrycode = %Q WHERE folder_id = %Q",
2764 			NULL, NULL, NULL, error,
2765 			ebsql->priv->region_code, ebsql->priv->folderid);
2766 
2767 	if (success)
2768 		success = ebsql_exec_printf (
2769 			ebsql, "UPDATE folders SET lc_collate = %Q WHERE folder_id = %Q",
2770 			NULL, NULL, NULL, error,
2771 			ebsql->priv->locale, ebsql->priv->folderid);
2772 
2773 	return success;
2774 }
2775 
2776 static gboolean
ebsql_set_locale_internal(EBookSqlite * ebsql,const gchar * locale,GError ** error)2777 ebsql_set_locale_internal (EBookSqlite *ebsql,
2778                            const gchar *locale,
2779                            GError **error)
2780 {
2781 	EBookSqlitePrivate *priv = ebsql->priv;
2782 	ECollator *collator;
2783 
2784 	g_return_val_if_fail (locale && locale[0], FALSE);
2785 
2786 	if (g_strcmp0 (priv->locale, locale) != 0) {
2787 		gchar *country_code = NULL;
2788 
2789 		collator = e_collator_new_interpret_country (
2790 			locale, &country_code, error);
2791 		if (collator == NULL)
2792 			return FALSE;
2793 
2794 		/* Assign region code parsed from the locale by ICU */
2795 		g_free (priv->region_code);
2796 		priv->region_code = country_code;
2797 
2798 		/* Assign locale */
2799 		g_free (priv->locale);
2800 		priv->locale = g_strdup (locale);
2801 
2802 		/* Assign collator */
2803 		if (ebsql->priv->collator)
2804 			e_collator_unref (ebsql->priv->collator);
2805 		ebsql->priv->collator = collator;
2806 	}
2807 
2808 	return TRUE;
2809 }
2810 
2811 /* Called with the lock held and inside a transaction */
2812 static gboolean
ebsql_init_legacy_keys(EBookSqlite * ebsql,gint previous_schema,GError ** error)2813 ebsql_init_legacy_keys (EBookSqlite *ebsql,
2814                         gint previous_schema,
2815                         GError **error)
2816 {
2817 	gboolean success = TRUE;
2818 
2819 	/* Schema 8 is when we moved from EBookSqlite */
2820 	if (previous_schema >= 1 && previous_schema < 8) {
2821 		gint is_populated = 0;
2822 		gchar *sync_data = NULL;
2823 
2824 		/* We need to hold on to the value of any previously set 'is_populated' flag */
2825 		success = ebsql_exec_printf (
2826 			ebsql, "SELECT is_populated FROM folders WHERE folder_id = %Q",
2827 			get_int_cb, &is_populated, NULL, error, ebsql->priv->folderid);
2828 
2829 		if (success) {
2830 			/* We can't use e_book_sqlite_set_key_value_int() at this
2831 			 * point as that would hold the access locks
2832 			 */
2833 			success = ebsql_exec_printf (
2834 				ebsql, "INSERT or REPLACE INTO keys (key, value, folder_id) values (%Q, %Q, %Q)",
2835 				NULL, NULL, NULL, error,
2836 				E_BOOK_SQL_IS_POPULATED_KEY,
2837 				is_populated ? "1" : "0",
2838 				ebsql->priv->folderid);
2839 		}
2840 
2841 		/* Repeat for 'sync_data' */
2842 		success = success && ebsql_exec_printf (
2843 			ebsql, "SELECT sync_data FROM folders WHERE folder_id = %Q",
2844 			get_string_cb, &sync_data, NULL, error, ebsql->priv->folderid);
2845 
2846 		if (success) {
2847 			success = ebsql_exec_printf (
2848 				ebsql, "INSERT or REPLACE INTO keys (key, value, folder_id) values (%Q, %Q, %Q)",
2849 				NULL, NULL, NULL, error,
2850 				E_BOOK_SQL_SYNC_DATA_KEY,
2851 				sync_data, ebsql->priv->folderid);
2852 
2853 			g_free (sync_data);
2854 		}
2855 	}
2856 
2857 	return success;
2858 }
2859 
2860 /* Called with the lock held and inside a transaction */
2861 static gboolean
ebsql_init_locale(EBookSqlite * ebsql,gint previous_schema,gboolean already_exists,GError ** error)2862 ebsql_init_locale (EBookSqlite *ebsql,
2863                    gint previous_schema,
2864                    gboolean already_exists,
2865                    GError **error)
2866 {
2867 	gchar *stored_lc_collate = NULL;
2868 	gchar *stored_region_code = NULL;
2869 	const gchar *lc_collate = NULL;
2870 	gboolean success = TRUE;
2871 	gboolean relocalize_needed = FALSE;
2872 
2873 	/* Get the locale setting for this addressbook */
2874 	if (already_exists) {
2875 		success = ebsql_exec_printf (
2876 			ebsql, "SELECT lc_collate FROM folders WHERE folder_id = %Q",
2877 			get_string_cb, &stored_lc_collate, NULL, error, ebsql->priv->folderid);
2878 
2879 		if (success)
2880 			success = ebsql_exec_printf (
2881 				ebsql, "SELECT countrycode FROM folders WHERE folder_id = %Q",
2882 				get_string_cb, &stored_region_code, NULL, error, ebsql->priv->folderid);
2883 
2884 		lc_collate = stored_lc_collate;
2885 	}
2886 
2887 	/* When creating a new addressbook, or upgrading from a version
2888 	 * where we did not have any locale setting; default to system locale,
2889 	 * we must absolutely always have a locale set.
2890 	 */
2891 	if (!lc_collate || !lc_collate[0])
2892 		lc_collate = setlocale (LC_COLLATE, NULL);
2893 	if (!lc_collate || !lc_collate[0])
2894 		lc_collate = setlocale (LC_ALL, NULL);
2895 	if (!lc_collate || !lc_collate[0])
2896 		lc_collate = "en_US.utf8";
2897 
2898 	/* Before touching any data, make sure we have a valid ECollator,
2899 	 * this will also resolve our region code
2900 	 */
2901 	if (success)
2902 		success = ebsql_set_locale_internal (ebsql, lc_collate, error);
2903 
2904 	/* Check if we need to relocalize */
2905 	if (success) {
2906 		/* Need to relocalize the whole thing if the schema has been upgraded to version 7 */
2907 		if (previous_schema >= 1 && previous_schema < 11)
2908 			relocalize_needed = TRUE;
2909 
2910 		/* We may need to relocalize for a country code change */
2911 		else if (g_strcmp0 (ebsql->priv->region_code, stored_region_code) != 0)
2912 			relocalize_needed = TRUE;
2913 	}
2914 
2915 	/* Reinsert all contacts with new locale & country code */
2916 	if (success && relocalize_needed)
2917 		success = ebsql_upgrade (ebsql, EBSQL_CHANGE_LAST, error);
2918 
2919 	EBSQL_NOTE (
2920 		SCHEMA,
2921 		g_printerr (
2922 			"SCHEMA: Initialized locale as '%s' (%s)\n",
2923 			ebsql->priv->locale, success ? "success" : "failed"));
2924 
2925 	g_free (stored_region_code);
2926 	g_free (stored_lc_collate);
2927 
2928 	return success;
2929 }
2930 
2931 static EBookSqlite *
ebsql_new_internal(const gchar * path,ESource * source,EbSqlVCardCallback vcard_callback,EbSqlChangeCallback change_callback,gpointer user_data,GDestroyNotify user_data_destroy,SummaryField * fields,gint n_fields,GCancellable * cancellable,GError ** error)2932 ebsql_new_internal (const gchar *path,
2933 		    ESource *source,
2934                     EbSqlVCardCallback vcard_callback,
2935                     EbSqlChangeCallback change_callback,
2936                     gpointer user_data,
2937                     GDestroyNotify user_data_destroy,
2938                     SummaryField *fields,
2939                     gint n_fields,
2940                     GCancellable *cancellable,
2941                     GError **error)
2942 {
2943 	EBookSqlite *ebsql;
2944 	gchar *dirname = NULL;
2945 	gint previous_schema = 0;
2946 	gboolean already_exists = FALSE;
2947 	gboolean success = TRUE;
2948 	GSList *introspected_columns = NULL;
2949 
2950 	g_return_val_if_fail (path != NULL, NULL);
2951 
2952 	EBSQL_LOCK_MUTEX (&dbcon_lock);
2953 
2954 	EBSQL_NOTE (
2955 		SCHEMA,
2956 		g_printerr ("SCHEMA: Creating new EBookSqlite at path '%s'\n", path));
2957 
2958 	ebsql = ebsql_ref_from_hash (path);
2959 	if (ebsql) {
2960 		EBSQL_NOTE (SCHEMA, g_printerr ("SCHEMA: An EBookSqlite already existed\n"));
2961 		goto exit;
2962 	}
2963 
2964 	ebsql = g_object_new (E_TYPE_BOOK_SQLITE, NULL);
2965 	ebsql->priv->path = g_strdup (path);
2966 	ebsql->priv->folderid = g_strdup (DEFAULT_FOLDER_ID);
2967 	ebsql->priv->summary_fields = fields;
2968 	ebsql->priv->n_summary_fields = n_fields;
2969 	ebsql->priv->vcard_callback = vcard_callback;
2970 	ebsql->priv->change_callback = change_callback;
2971 	ebsql->priv->user_data = user_data;
2972 	ebsql->priv->user_data_destroy = user_data_destroy;
2973 	if (source != NULL)
2974 		ebsql->priv->source = g_object_ref (source);
2975 	else
2976 		ebsql->priv->source = NULL;
2977 
2978 	EBSQL_NOTE (REF_COUNTS, g_printerr ("EBookSqlite initially created\n"));
2979 
2980 	/* Ensure existance of the directories leading up to 'path' */
2981 	dirname = g_path_get_dirname (path);
2982 	if (g_mkdir_with_parents (dirname, 0777) < 0) {
2983 		EBSQL_SET_ERROR (
2984 			error,
2985 			E_BOOK_SQLITE_ERROR_LOAD,
2986 			"Can not make parent directory: %s",
2987 			g_strerror (errno));
2988 		success = FALSE;
2989 		goto exit;
2990 	}
2991 
2992 	/* The additional instance lock is unneccesarry because of the global
2993 	 * lock held here, but let's keep it locked because we hold it while
2994 	 * executing any SQLite code throughout this code
2995 	 */
2996 	EBSQL_LOCK_MUTEX (&ebsql->priv->lock);
2997 
2998 	/* Initialize the SQLite (set some parameters and add some custom hooks) */
2999 	if (!ebsql_init_sqlite (ebsql, path, error)) {
3000 		EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
3001 		success = FALSE;
3002 		goto exit;
3003 	}
3004 
3005 	/* Lets do it all atomically inside a single transaction */
3006 	if (!ebsql_start_transaction (ebsql, EBSQL_LOCK_WRITE, cancellable, error)) {
3007 		EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
3008 		success = FALSE;
3009 		goto exit;
3010 	}
3011 
3012 	/* When loading addressbooks created by EBookBackendSqlite, we
3013 	 * need to fetch the 'folderid' which was in use for that existing
3014 	 * addressbook before introspecting its summary and upgrading
3015 	 * the schema.
3016 	 */
3017 	if (success)
3018 		success = ebsql_resolve_folderid (
3019 			ebsql,
3020 			&previous_schema,
3021 			&already_exists,
3022 			error);
3023 
3024 	/* Initialize main folders table, also retrieve the current
3025 	 * schema version if the table already exists
3026 	 */
3027 	if (success)
3028 		success = ebsql_init_folders (ebsql, previous_schema, error);
3029 
3030 	/* Initialize the key/value table */
3031 	if (success)
3032 		success = ebsql_init_keys (ebsql, error);
3033 
3034 	/* Determine if the addressbook already existed, and fill out
3035 	 * some information in the main folder table
3036 	 */
3037 	if (success && !already_exists)
3038 		success = ebsql_add_folder (ebsql, error);
3039 
3040 	/* If the addressbook did exist, then check how it's configured.
3041 	 *
3042 	 * Let the existing summary information override the current
3043 	 * one asked for by our callers.
3044 	 *
3045 	 * Some summary fields are also adjusted for schema upgrades
3046 	 */
3047 	if (success && already_exists)
3048 		success = ebsql_introspect_summary (
3049 			ebsql,
3050 			previous_schema,
3051 			&introspected_columns,
3052 			error);
3053 
3054 	/* Add the contacts table, ensure the right columns are defined
3055 	 * to handle our summary configuration
3056 	 */
3057 	if (success)
3058 		success = ebsql_init_contacts (
3059 			ebsql,
3060 			introspected_columns,
3061 			error);
3062 
3063 	/* Add any auxiliary tables which we might need to support our
3064 	 * summary configuration.
3065 	 *
3066 	 * Any fields which represent a 'list-of-strings' require an
3067 	 * auxiliary table to store them in.
3068 	 */
3069 	if (success)
3070 		success = ebsql_init_aux_tables (ebsql, previous_schema, error);
3071 
3072 	/* At this point we have resolved our schema, let's build our
3073 	 * precompiled statements, we might use them to re-insert contacts
3074 	 * in the next step
3075 	 */
3076 	if (success)
3077 		success = ebsql_init_statements (ebsql, error);
3078 
3079 	/* When porting from older schemas, we need to port the old 'is-populated' flag */
3080 	if (success)
3081 		success = ebsql_init_legacy_keys (ebsql, previous_schema, error);
3082 
3083 	/* Load / resolve the current locale setting
3084 	 *
3085 	 * Also perform the overall upgrade in this step
3086 	 * in the case that an upgrade happened, or a locale
3087 	 * change is detected... all rows need to be renormalized
3088 	 * for this.
3089 	 */
3090 	if (success)
3091 		success = ebsql_init_locale (
3092 			ebsql, previous_schema,
3093 			already_exists, error);
3094 
3095 
3096 	/* Schema 12 added E_CONTACT_PGP_CERT column into the summary;
3097 	   the ebsql_init_locale() also calls ebsql_upgrade() for schema 10-,
3098 	   thus call it here only for schema 11, to populate the PGP column */
3099 	if (success && previous_schema == 11)
3100 		success = ebsql_upgrade (ebsql, EBSQL_CHANGE_LAST, error);
3101 
3102 	if (success)
3103 		success = ebsql_commit_transaction (ebsql, error);
3104 	else
3105 		/* The GError is already set. */
3106 		ebsql_rollback_transaction (ebsql, NULL);
3107 
3108 	/* Release the instance lock and register to the global hash */
3109 	EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
3110 
3111 	if (success)
3112 		ebsql_register_to_hash (ebsql, path);
3113 
3114  exit:
3115 
3116 	/* Cleanup and exit */
3117 	EBSQL_UNLOCK_MUTEX (&dbcon_lock);
3118 
3119 	/* If we failed somewhere, give up on creating the 'ebsql',
3120 	 * otherwise add it to the hash table
3121 	 */
3122 	if (!success)
3123 		g_clear_object (&ebsql);
3124 
3125 	EBSQL_NOTE (
3126 		SCHEMA,
3127 		g_printerr (
3128 			"SCHEMA: %s the new EBookSqlite\n",
3129 			success ? "Successfully created" : "Failed to create"));
3130 
3131 	g_slist_free_full (introspected_columns, (GDestroyNotify) g_free);
3132 	g_free (dirname);
3133 
3134 	return ebsql;
3135 }
3136 
3137 /**********************************************************
3138  *                   Inserting Contacts                   *
3139  **********************************************************/
3140 static gchar *
convert_phone(const gchar * normal,const gchar * region_code,gint * out_country_code)3141 convert_phone (const gchar *normal,
3142                const gchar *region_code,
3143                gint *out_country_code)
3144 {
3145 	EPhoneNumber *number = NULL;
3146 	gchar *national_number = NULL;
3147 	gint country_code = 0;
3148 
3149 	/* Don't warn about erronous phone number strings, it's a perfectly normal
3150 	 * use case for users to enter notes instead of phone numbers in the phone
3151 	 * number contact fields, such as "Ask Jenny for Lisa's phone number"
3152 	 */
3153 	if (normal && e_phone_number_is_supported ())
3154 		number = e_phone_number_from_string (normal, region_code, NULL);
3155 
3156 	if (number) {
3157 		EPhoneNumberCountrySource source;
3158 
3159 		national_number = e_phone_number_get_national_number (number);
3160 		country_code = e_phone_number_get_country_code (number, &source);
3161 		e_phone_number_free (number);
3162 
3163 		if (source == E_PHONE_NUMBER_COUNTRY_FROM_DEFAULT)
3164 			country_code = 0;
3165 	}
3166 
3167 	if (out_country_code)
3168 		*out_country_code = country_code;
3169 
3170 	return national_number;
3171 }
3172 
3173 static gchar *
remove_leading_zeros(gchar * number)3174 remove_leading_zeros (gchar *number)
3175 {
3176 	gchar *trimmed = NULL;
3177 	gchar *tmp = number;
3178 
3179 	if (!number)
3180 		return NULL;
3181 
3182 	while ('0' == *tmp)
3183 		tmp++;
3184 
3185 	if (tmp == number)
3186 		return number;
3187 
3188 	trimmed = g_strdup (tmp);
3189 	g_free (number);
3190 
3191 	return trimmed;
3192 }
3193 
3194 typedef struct {
3195 	gint country_code;
3196 	gchar *national;
3197 } E164Number;
3198 
3199 static E164Number *
ebsql_e164_number_new(gint country_code,gchar * national)3200 ebsql_e164_number_new (gint country_code,
3201                        gchar *national)
3202 {
3203 	E164Number *number = g_slice_new (E164Number);
3204 
3205 	number->country_code = country_code;
3206 	number->national = g_strdup (national);
3207 
3208 	return number;
3209 }
3210 
3211 static void
ebsql_e164_number_free(E164Number * number)3212 ebsql_e164_number_free (E164Number *number)
3213 {
3214 	if (number) {
3215 		g_free (number->national);
3216 		g_slice_free (E164Number, number);
3217 	}
3218 }
3219 
3220 static gint
ebsql_e164_number_find(E164Number * number_a,E164Number * number_b)3221 ebsql_e164_number_find (E164Number *number_a,
3222                         E164Number *number_b)
3223 {
3224 	gint ret;
3225 
3226 	ret = number_a->country_code - number_b->country_code;
3227 
3228 	if (ret == 0)
3229 		ret = g_strcmp0 (
3230 			number_a->national,
3231 			number_b->national);
3232 
3233 	return ret;
3234 }
3235 
3236 static GList *
extract_e164_attribute_params(EContact * contact)3237 extract_e164_attribute_params (EContact *contact)
3238 {
3239 	EVCard *vcard = E_VCARD (contact);
3240 	GList *extracted = NULL;
3241 	GList *attr_list;
3242 
3243 	for (attr_list = e_vcard_get_attributes (vcard); attr_list; attr_list = attr_list->next) {
3244 		EVCardAttribute *const attr = attr_list->data;
3245 		EVCardAttributeParam *param = NULL;
3246 		GList *param_list, *values, *l;
3247 		gchar *this_national = NULL;
3248 		gint this_country = 0;
3249 
3250 		/* We only attach E164 parameters to TEL attributes. */
3251 		if (strcmp (e_vcard_attribute_get_name (attr), EVC_TEL) != 0)
3252 			continue;
3253 
3254 		/* Find already exisiting parameter, so that we can reuse it. */
3255 		for (param_list = e_vcard_attribute_get_params (attr); param_list; param_list = param_list->next) {
3256 			if (strcmp (e_vcard_attribute_param_get_name (param_list->data), EVC_X_E164) == 0) {
3257 				param = param_list->data;
3258 				break;
3259 			}
3260 		}
3261 
3262 		if (!param)
3263 			continue;
3264 
3265 		values = e_vcard_attribute_param_get_values (param);
3266 		for (l = values; l; l = l->next) {
3267 			const gchar *value = l->data;
3268 
3269 			if (value[0] == '+')
3270 				this_country = g_ascii_strtoll (&value[1], NULL, 10);
3271 			else if (this_national == NULL)
3272 				this_national = g_strdup (value);
3273 		}
3274 
3275 		if (this_national) {
3276 			E164Number *number;
3277 
3278 			EBSQL_NOTE (
3279 				CONVERT_E164,
3280 				g_printerr (
3281 					"Extracted e164 number from '%s' with "
3282 					"country = %d national = %s\n",
3283 					(gchar *) e_contact_get_const (contact, E_CONTACT_UID),
3284 					this_country, this_national));
3285 
3286 			number = ebsql_e164_number_new (
3287 				this_country, this_national);
3288 			extracted = g_list_prepend (extracted, number);
3289 		}
3290 
3291 		g_free (this_national);
3292 
3293 		/* Clear the values, we'll insert new ones */
3294 		e_vcard_attribute_param_remove_values (param);
3295 		e_vcard_attribute_remove_param (attr, EVC_X_E164);
3296 	}
3297 
3298 	EBSQL_NOTE (
3299 		CONVERT_E164,
3300 		g_printerr (
3301 			"Extracted %d numbers from '%s'\n",
3302 			g_list_length (extracted),
3303 			(gchar *) e_contact_get_const (contact, E_CONTACT_UID)));
3304 
3305 	return extracted;
3306 }
3307 
3308 static gboolean
update_e164_attribute_params(EBookSqlite * ebsql,EContact * contact,const gchar * default_region)3309 update_e164_attribute_params (EBookSqlite *ebsql,
3310                               EContact *contact,
3311                               const gchar *default_region)
3312 {
3313 	GList *original_numbers = NULL;
3314 	GList *attr_list;
3315 	gboolean changed = FALSE;
3316 	gint n_numbers = 0;
3317 	EVCard *vcard = E_VCARD (contact);
3318 
3319 	original_numbers = extract_e164_attribute_params (contact);
3320 
3321 	for (attr_list = e_vcard_get_attributes (vcard); attr_list; attr_list = attr_list->next) {
3322 		EVCardAttribute *const attr = attr_list->data;
3323 		EVCardAttributeParam *param = NULL;
3324 		const gchar *original_number = NULL;
3325 		gchar *country_string;
3326 		GList *values;
3327 		E164Number number = { 0, NULL };
3328 
3329 		/* We only attach E164 parameters to TEL attributes. */
3330 		if (strcmp (e_vcard_attribute_get_name (attr), EVC_TEL) != 0)
3331 			continue;
3332 
3333 		/* Fetch the TEL value */
3334 		values = e_vcard_attribute_get_values (attr);
3335 
3336 		/* Compute E164 number based on the TEL value */
3337 		if (values && values->data) {
3338 			original_number = (const gchar *) values->data;
3339 			number.national = convert_phone (
3340 				original_number,
3341 				ebsql->priv->region_code,
3342 				&(number.country_code));
3343 		}
3344 
3345 		if (number.national == NULL)
3346 			continue;
3347 
3348 		/* Count how many we successfully parsed in this region code */
3349 		n_numbers++;
3350 
3351 		/* Check if we have a differing e164 number, if there is no match
3352 		 * in the old existing values then the vcard changed
3353 		 */
3354 		if (!g_list_find_custom (original_numbers, &number,
3355 					 (GCompareFunc) ebsql_e164_number_find))
3356 			changed = TRUE;
3357 
3358 		if (number.country_code != 0)
3359 			country_string = g_strdup_printf ("+%d", number.country_code);
3360 		else
3361 			country_string = g_strdup ("");
3362 
3363 		param = e_vcard_attribute_param_new (EVC_X_E164);
3364 		e_vcard_attribute_add_param (attr, param);
3365 
3366 		/* Assign the parameter values. It seems odd that we revert
3367 		 * the order of NN and CC, but at least EVCard's parser doesn't
3368 		 * permit an empty first param value. Which of course could be
3369 		 * fixed - in order to create a nice potential IOP problem with
3370 		 ** other vCard parsers. */
3371 		e_vcard_attribute_param_add_values (param, number.national, country_string, NULL);
3372 
3373 		EBSQL_NOTE (
3374 			CONVERT_E164,
3375 			g_printerr (
3376 				"Converted '%s' to e164 number with country = %d "
3377 				"national = %s for '%s' (changed %s)\n",
3378 				original_number, number.country_code, number.national,
3379 				(gchar *) e_contact_get_const (contact, E_CONTACT_UID),
3380 				changed ? "yes" : "no"));
3381 
3382 		g_free (number.national);
3383 		g_free (country_string);
3384 	}
3385 
3386 	if (!changed &&
3387 	    n_numbers != g_list_length (original_numbers))
3388 		changed = TRUE;
3389 
3390 	EBSQL_NOTE (
3391 		CONVERT_E164,
3392 		g_printerr (
3393 			"Converted %d e164 numbers for '%s' which previously had %d e164 numbers\n",
3394 			n_numbers,
3395 			(gchar *) e_contact_get_const (contact, E_CONTACT_UID),
3396 			g_list_length (original_numbers)));
3397 
3398 	g_list_free_full (original_numbers, (GDestroyNotify) ebsql_e164_number_free);
3399 
3400 	return changed;
3401 }
3402 
3403 static sqlite3_stmt *
ebsql_prepare_multi_delete(EBookSqlite * ebsql,SummaryField * field,GError ** error)3404 ebsql_prepare_multi_delete (EBookSqlite *ebsql,
3405                             SummaryField *field,
3406                             GError **error)
3407 {
3408 	sqlite3_stmt *stmt = NULL;
3409 	gchar *stmt_str;
3410 
3411 	stmt_str = sqlite3_mprintf ("DELETE FROM %Q WHERE uid = :uid", field->aux_table);
3412 	stmt = ebsql_prepare_statement (ebsql, stmt_str, error);
3413 	sqlite3_free (stmt_str);
3414 
3415 	return stmt;
3416 }
3417 
3418 static gboolean
ebsql_run_multi_delete(EBookSqlite * ebsql,SummaryField * field,const gchar * uid,GError ** error)3419 ebsql_run_multi_delete (EBookSqlite *ebsql,
3420                         SummaryField *field,
3421                         const gchar *uid,
3422                         GError **error)
3423 {
3424 	sqlite3_stmt *stmt;
3425 	gint ret;
3426 
3427 	stmt = g_hash_table_lookup (ebsql->priv->multi_deletes, GUINT_TO_POINTER (field->field_id));
3428 
3429 	/* This can return an error if a previous call to sqlite3_step() had errors,
3430 	 * so let's just ignore any error in this case
3431 	 */
3432 	sqlite3_reset (stmt);
3433 
3434 	/* Clear all previously set values */
3435 	ret = sqlite3_clear_bindings (stmt);
3436 
3437 	/* Set the UID host parameter statically */
3438 	if (ret == SQLITE_OK)
3439 		ret = sqlite3_bind_text (stmt, 1, uid, -1, SQLITE_STATIC);
3440 
3441 	/* Run the statement */
3442 	return ebsql_complete_statement (ebsql, stmt, ret, error);
3443 }
3444 
3445 static sqlite3_stmt *
ebsql_prepare_multi_insert(EBookSqlite * ebsql,SummaryField * field,GError ** error)3446 ebsql_prepare_multi_insert (EBookSqlite *ebsql,
3447                             SummaryField *field,
3448                             GError **error)
3449 {
3450 	sqlite3_stmt *stmt = NULL;
3451 	GString *string;
3452 
3453 	string = g_string_sized_new (INSERT_MULTI_STMT_BYTES);
3454 	ebsql_string_append_printf (string, "INSERT INTO %Q (uid, value", field->aux_table);
3455 
3456 	if ((field->index & INDEX_FLAG (SUFFIX)) != 0)
3457 		g_string_append (string, ", value_" EBSQL_SUFFIX_REVERSE);
3458 
3459 	if ((field->index & INDEX_FLAG (PHONE)) != 0) {
3460 		g_string_append (string, ", value_" EBSQL_SUFFIX_PHONE);
3461 		g_string_append (string, ", value_" EBSQL_SUFFIX_COUNTRY);
3462 	}
3463 
3464 	g_string_append (string, ") VALUES (:uid, :value");
3465 
3466 	if ((field->index & INDEX_FLAG (SUFFIX)) != 0)
3467 		g_string_append (string, ", :value_" EBSQL_SUFFIX_REVERSE);
3468 
3469 	if ((field->index & INDEX_FLAG (PHONE)) != 0) {
3470 		g_string_append (string, ", :value_" EBSQL_SUFFIX_PHONE);
3471 		g_string_append (string, ", :value_" EBSQL_SUFFIX_COUNTRY);
3472 	}
3473 
3474 	g_string_append_c (string, ')');
3475 
3476 	stmt = ebsql_prepare_statement (ebsql, string->str, error);
3477 	g_string_free (string, TRUE);
3478 
3479 	return stmt;
3480 }
3481 
3482 static gboolean
ebsql_run_multi_insert_one(EBookSqlite * ebsql,sqlite3_stmt * stmt,SummaryField * field,const gchar * uid,const gchar * value,GError ** error)3483 ebsql_run_multi_insert_one (EBookSqlite *ebsql,
3484                             sqlite3_stmt *stmt,
3485                             SummaryField *field,
3486                             const gchar *uid,
3487                             const gchar *value,
3488                             GError **error)
3489 {
3490 	gchar *normal = e_util_utf8_normalize (value);
3491 	gchar *str;
3492 	gint ret, param_idx = 1;
3493 
3494 	/* :uid */
3495 	ret = sqlite3_bind_text (stmt, param_idx++, uid, -1, SQLITE_STATIC);
3496 
3497 	if (ret == SQLITE_OK)  /* :value */
3498 		ret = sqlite3_bind_text (stmt, param_idx++, normal, -1, g_free);
3499 
3500 	if (ret == SQLITE_OK && (field->index & INDEX_FLAG (SUFFIX)) != 0) {
3501 		if (normal)
3502 			str = g_utf8_strreverse (normal, -1);
3503 		else
3504 			str = NULL;
3505 
3506 		/* :value_reverse */
3507 		ret = sqlite3_bind_text (stmt, param_idx++, str, -1, g_free);
3508 	}
3509 
3510 	if (ret == SQLITE_OK && (field->index & INDEX_FLAG (PHONE)) != 0) {
3511 		gint country_code;
3512 
3513 		str = convert_phone (
3514 			normal, ebsql->priv->region_code,
3515 			&country_code);
3516 		str = remove_leading_zeros (str);
3517 
3518 		/* :value_phone */
3519 		ret = sqlite3_bind_text (stmt, param_idx++, str, -1, g_free);
3520 
3521 		/* :value_country */
3522 		if (ret == SQLITE_OK)
3523 			sqlite3_bind_int (stmt, param_idx++, country_code);
3524 
3525 	}
3526 
3527 	/* Run the statement */
3528 	return ebsql_complete_statement (ebsql, stmt, ret, error);
3529 }
3530 
3531 static gboolean
ebsql_run_multi_insert(EBookSqlite * ebsql,SummaryField * field,const gchar * uid,EContact * contact,GError ** error)3532 ebsql_run_multi_insert (EBookSqlite *ebsql,
3533                         SummaryField *field,
3534                         const gchar *uid,
3535                         EContact *contact,
3536                         GError **error)
3537 {
3538 	sqlite3_stmt *stmt;
3539 	GList *values, *l;
3540 	gboolean success = TRUE;
3541 
3542 	stmt = g_hash_table_lookup (ebsql->priv->multi_inserts, GUINT_TO_POINTER (field->field_id));
3543 	values = e_contact_get (contact, field->field_id);
3544 
3545 	for (l = values; success && l != NULL; l = l->next) {
3546 		gchar *value = (gchar *) l->data;
3547 
3548 		success = ebsql_run_multi_insert_one (
3549 			ebsql, stmt, field, uid, value, error);
3550 	}
3551 
3552 	/* Free the list of allocated strings */
3553 	e_contact_attr_list_free (values);
3554 
3555 	return success;
3556 }
3557 
3558 static sqlite3_stmt *
ebsql_prepare_insert(EBookSqlite * ebsql,gboolean replace_existing,GError ** error)3559 ebsql_prepare_insert (EBookSqlite *ebsql,
3560                       gboolean replace_existing,
3561                       GError **error)
3562 {
3563 	sqlite3_stmt *stmt;
3564 	GString *string;
3565 	gint i;
3566 
3567 	string = g_string_new ("");
3568 	if (replace_existing)
3569 		ebsql_string_append_printf (
3570 			string, "INSERT or REPLACE INTO %Q (",
3571 			ebsql->priv->folderid);
3572 	else
3573 		ebsql_string_append_printf (
3574 			string, "INSERT or FAIL INTO %Q (",
3575 			ebsql->priv->folderid);
3576 
3577 	/*
3578 	 * First specify the column names for the insert, since it's possible we
3579 	 * upgraded the DB and cannot be sure the order of the columns are ordered
3580 	 * just how we like them to be.
3581 	 */
3582 	for (i = 0; i < ebsql->priv->n_summary_fields; i++) {
3583 		SummaryField *field = &(ebsql->priv->summary_fields[i]);
3584 
3585 		/* Multi values go into a separate table/statement */
3586 		if (field->type != E_TYPE_CONTACT_ATTR_LIST) {
3587 
3588 			/* Only add a ", " before every field except the first,
3589 			 * this will not break because the first 2 fields (UID & REV)
3590 			 * are string fields.
3591 			 */
3592 			if (i > 0)
3593 				g_string_append (string, ", ");
3594 
3595 			g_string_append (string, field->dbname);
3596 		}
3597 
3598 		if (field->type == G_TYPE_STRING) {
3599 
3600 			if ((field->index & INDEX_FLAG (SORT_KEY)) != 0) {
3601 				g_string_append (string, ", ");
3602 				g_string_append (string, field->dbname);
3603 				g_string_append (string, "_" EBSQL_SUFFIX_SORT_KEY);
3604 			}
3605 
3606 			if ((field->index & INDEX_FLAG (SUFFIX)) != 0) {
3607 				g_string_append (string, ", ");
3608 				g_string_append (string, field->dbname);
3609 				g_string_append (string, "_" EBSQL_SUFFIX_REVERSE);
3610 			}
3611 
3612 			if ((field->index & INDEX_FLAG (PHONE)) != 0) {
3613 
3614 				g_string_append (string, ", ");
3615 				g_string_append (string, field->dbname);
3616 				g_string_append (string, "_" EBSQL_SUFFIX_PHONE);
3617 
3618 				g_string_append (string, ", ");
3619 				g_string_append (string, field->dbname);
3620 				g_string_append (string, "_" EBSQL_SUFFIX_COUNTRY);
3621 			}
3622 		}
3623 	}
3624 	g_string_append (string, ", vcard, bdata)");
3625 
3626 	/*
3627 	 * Now specify values for all of the column names we specified.
3628 	 */
3629 	g_string_append (string, " VALUES (");
3630 	for (i = 0; i < ebsql->priv->n_summary_fields; i++) {
3631 		SummaryField *field = &(ebsql->priv->summary_fields[i]);
3632 
3633 		if (field->type != E_TYPE_CONTACT_ATTR_LIST) {
3634 			/* Only add a ", " before every field except the first,
3635 			 * this will not break because the first 2 fields (UID & REV)
3636 			 * are string fields.
3637 			 */
3638 			if (i > 0)
3639 				g_string_append (string, ", ");
3640 		}
3641 
3642 		if (field->type == G_TYPE_STRING || field->type == G_TYPE_BOOLEAN ||
3643 		    field->type == E_TYPE_CONTACT_CERT) {
3644 
3645 			g_string_append_c (string, ':');
3646 			g_string_append (string, field->dbname);
3647 
3648 			if ((field->index & INDEX_FLAG (SORT_KEY)) != 0)
3649 				g_string_append_printf (string, ", :%s_" EBSQL_SUFFIX_SORT_KEY, field->dbname);
3650 
3651 			if ((field->index & INDEX_FLAG (SUFFIX)) != 0)
3652 				g_string_append_printf (string, ", :%s_" EBSQL_SUFFIX_REVERSE, field->dbname);
3653 
3654 			if ((field->index & INDEX_FLAG (PHONE)) != 0) {
3655 				g_string_append_printf (string, ", :%s_" EBSQL_SUFFIX_PHONE, field->dbname);
3656 				g_string_append_printf (string, ", :%s_" EBSQL_SUFFIX_COUNTRY, field->dbname);
3657 			}
3658 
3659 		} else if (field->type != E_TYPE_CONTACT_ATTR_LIST)
3660 			g_warn_if_reached ();
3661 	}
3662 
3663 	g_string_append (string, ", :vcard, :bdata)");
3664 
3665 	stmt = ebsql_prepare_statement (ebsql, string->str, error);
3666 	g_string_free (string, TRUE);
3667 
3668 	return stmt;
3669 }
3670 
3671 static gboolean
ebsql_init_statements(EBookSqlite * ebsql,GError ** error)3672 ebsql_init_statements (EBookSqlite *ebsql,
3673                        GError **error)
3674 {
3675 	sqlite3_stmt *stmt;
3676 	gint i;
3677 
3678 	ebsql->priv->insert_stmt = ebsql_prepare_insert (ebsql, FALSE, error);
3679 	if (!ebsql->priv->insert_stmt)
3680 		goto preparation_failed;
3681 
3682 	ebsql->priv->replace_stmt = ebsql_prepare_insert (ebsql, TRUE, error);
3683 	if (!ebsql->priv->replace_stmt)
3684 		goto preparation_failed;
3685 
3686 	ebsql->priv->multi_deletes =
3687 		g_hash_table_new_full (
3688 			g_direct_hash, g_direct_equal,
3689 			NULL,
3690 			(GDestroyNotify) sqlite3_finalize);
3691 	ebsql->priv->multi_inserts =
3692 		g_hash_table_new_full (
3693 			g_direct_hash, g_direct_equal,
3694 			NULL,
3695 			(GDestroyNotify) sqlite3_finalize);
3696 
3697 	for (i = 0; i < ebsql->priv->n_summary_fields; i++) {
3698 		SummaryField *field = &(ebsql->priv->summary_fields[i]);
3699 
3700 		if (field->type != E_TYPE_CONTACT_ATTR_LIST)
3701 			continue;
3702 
3703 		stmt = ebsql_prepare_multi_insert (ebsql, field, error);
3704 		if (!stmt)
3705 			goto preparation_failed;
3706 
3707 		g_hash_table_insert (
3708 			ebsql->priv->multi_inserts,
3709 			GUINT_TO_POINTER (field->field_id),
3710 			stmt);
3711 
3712 		stmt = ebsql_prepare_multi_delete (ebsql, field, error);
3713 		if (!stmt)
3714 			goto preparation_failed;
3715 
3716 		g_hash_table_insert (
3717 			ebsql->priv->multi_deletes,
3718 			GUINT_TO_POINTER (field->field_id),
3719 			stmt);
3720 	}
3721 
3722 	return TRUE;
3723 
3724  preparation_failed:
3725 
3726 	return FALSE;
3727 }
3728 
3729 static gboolean
ebsql_run_insert(EBookSqlite * ebsql,gboolean replace,EContact * contact,gchar * vcard,const gchar * extra,GError ** error)3730 ebsql_run_insert (EBookSqlite *ebsql,
3731                   gboolean replace,
3732                   EContact *contact,
3733                   gchar *vcard,
3734                   const gchar *extra,
3735                   GError **error)
3736 {
3737 	EBookSqlitePrivate *priv;
3738 	sqlite3_stmt *stmt;
3739 	gint i, param_idx;
3740 	gint ret;
3741 	gboolean success;
3742 	GError *local_error = NULL;
3743 
3744 	priv = ebsql->priv;
3745 
3746 	if (replace)
3747 		stmt = ebsql->priv->replace_stmt;
3748 	else
3749 		stmt = ebsql->priv->insert_stmt;
3750 
3751 	/* This can return an error if a previous call to sqlite3_step() had errors,
3752 	 * so let's just ignore any error in this case
3753 	 */
3754 	sqlite3_reset (stmt);
3755 
3756 	/* Clear all previously set values */
3757 	ret = sqlite3_clear_bindings (stmt);
3758 
3759 	for (i = 0, param_idx = 1; ret == SQLITE_OK && i < ebsql->priv->n_summary_fields; i++) {
3760 		SummaryField *field = &(ebsql->priv->summary_fields[i]);
3761 
3762 		if (field->type == G_TYPE_STRING) {
3763 			gchar *val;
3764 			gchar *normal;
3765 			gchar *str;
3766 
3767 			val = e_contact_get (contact, field->field_id);
3768 
3769 			/* Special exception, never normalize/localize the UID or REV string */
3770 			if (field->field_id != E_CONTACT_UID &&
3771 			    field->field_id != E_CONTACT_REV) {
3772 				normal = e_util_utf8_normalize (val);
3773 			} else
3774 				normal = g_strdup (val);
3775 
3776 			/* Takes ownership of 'normal' */
3777 			ret = sqlite3_bind_text (stmt, param_idx++, normal, -1, g_free);
3778 
3779 			if (ret == SQLITE_OK &&
3780 			    (field->index & INDEX_FLAG (SORT_KEY)) != 0) {
3781 				if (val)
3782 					str = e_collator_generate_key (ebsql->priv->collator, val, NULL);
3783 				else
3784 					str = g_strdup ("");
3785 
3786 				ret = sqlite3_bind_text (stmt, param_idx++, str, -1, g_free);
3787 			}
3788 
3789 			if (ret == SQLITE_OK &&
3790 			    (field->index & INDEX_FLAG (SUFFIX)) != 0) {
3791 				if (normal)
3792 					str = g_utf8_strreverse (normal, -1);
3793 				else
3794 					str = NULL;
3795 
3796 				ret = sqlite3_bind_text (stmt, param_idx++, str, -1, g_free);
3797 			}
3798 
3799 			if (ret == SQLITE_OK &&
3800 			    (field->index & INDEX_FLAG (PHONE)) != 0) {
3801 				gint country_code;
3802 
3803 				str = convert_phone (
3804 					normal, ebsql->priv->region_code,
3805 					&country_code);
3806 				str = remove_leading_zeros (str);
3807 
3808 				ret = sqlite3_bind_text (stmt, param_idx++, str, -1, g_free);
3809 				if (ret == SQLITE_OK)
3810 					sqlite3_bind_int (stmt, param_idx++, country_code);
3811 			}
3812 
3813 			g_free (val);
3814 		} else if (field->type == G_TYPE_BOOLEAN) {
3815 			gboolean val;
3816 
3817 			val = e_contact_get (contact, field->field_id) ? TRUE : FALSE;
3818 
3819 			ret = sqlite3_bind_int (stmt, param_idx++, val ? 1 : 0);
3820 		} else if (field->type == E_TYPE_CONTACT_CERT) {
3821 			EContactCert *cert = NULL;
3822 
3823 			cert = e_contact_get (contact, field->field_id);
3824 
3825 			/* We don't actually store the cert; only a boolean to indicate
3826 			 * that is *has* a cert. */
3827 			ret = sqlite3_bind_int (stmt, param_idx++, cert ? 1 : 0);
3828 			e_contact_cert_free (cert);
3829 		} else if (field->type != E_TYPE_CONTACT_ATTR_LIST)
3830 			g_warn_if_reached ();
3831 	}
3832 
3833 	if (ret == SQLITE_OK) {
3834 
3835 		EBSQL_NOTE (
3836 			INSERT,
3837 			g_printerr (
3838 				"Inserting vcard for contact with UID '%s'\n%s\n",
3839 				(gchar *) e_contact_get_const (contact, E_CONTACT_UID),
3840 				vcard ? vcard : "(no vcard)"));
3841 
3842 		/* If we have a priv->vcard_callback, then it's a shallow addressbook
3843 		 * and we don't populate the vcard column, need to free it anyway
3844 		 */
3845 		if (priv->vcard_callback != NULL) {
3846 			g_free (vcard);
3847 			vcard = NULL;
3848 		}
3849 
3850 		ret = sqlite3_bind_text (stmt, param_idx++, vcard, -1, g_free);
3851 	}
3852 
3853 	/* The extra data */
3854 	if (ret == SQLITE_OK)
3855 		ret = sqlite3_bind_text (stmt, param_idx++, g_strdup (extra), -1, g_free);
3856 
3857 	/* Run the statement */
3858 	success = ebsql_complete_statement (ebsql, stmt, ret, &local_error);
3859 
3860 	EBSQL_NOTE (
3861 		INSERT,
3862 		g_printerr (
3863 			"%s contact with UID '%s' and extra data '%s' vcard: %s (error: %s)\n",
3864 			success ? "Succesfully inserted" : "Failed to insert",
3865 			(gchar *) e_contact_get_const (contact, E_CONTACT_UID), extra,
3866 			vcard ? "yes" : "no",
3867 			local_error ? local_error->message : "(none)"));
3868 
3869 	if (!success)
3870 		g_propagate_error (error, local_error);
3871 
3872 	return success;
3873 }
3874 
3875 static gboolean
ebsql_insert_contact(EBookSqlite * ebsql,EbSqlChangeType change_type,EContact * contact,const gchar * original_vcard,const gchar * extra,gboolean replace,GError ** error)3876 ebsql_insert_contact (EBookSqlite *ebsql,
3877                       EbSqlChangeType change_type,
3878                       EContact *contact,
3879                       const gchar *original_vcard,
3880                       const gchar *extra,
3881                       gboolean replace,
3882                       GError **error)
3883 {
3884 	EBookSqlitePrivate *priv;
3885 	gboolean e164_changed = FALSE;
3886 	gboolean success;
3887 	gchar *uid, *vcard = NULL;
3888 
3889 	priv = ebsql->priv;
3890 	uid = e_contact_get (contact, E_CONTACT_UID);
3891 
3892 	/* Update E.164 parameters in vcard if needed */
3893 	e164_changed = update_e164_attribute_params (
3894 		ebsql, contact, priv->region_code);
3895 
3896 	if (e164_changed || original_vcard == NULL) {
3897 
3898 		/* Generate a new one if it changed (or if we don't have one) */
3899 		vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
3900 
3901 		if (e164_changed &&
3902 		    change_type != EBSQL_CHANGE_LAST &&
3903 		    ebsql->priv->change_callback)
3904 			ebsql->priv->change_callback (change_type,
3905 						      uid, extra, vcard,
3906 						      ebsql->priv->user_data);
3907 	} else {
3908 
3909 		vcard = g_strdup (original_vcard);
3910 	}
3911 
3912 	/* This actually consumes 'vcard' */
3913 	success = ebsql_run_insert (ebsql, replace, contact, vcard, extra, error);
3914 
3915 	/* Update attribute list table */
3916 	if (success) {
3917 		gint i;
3918 
3919 		for (i = 0; success && i < priv->n_summary_fields; i++) {
3920 			SummaryField *field = &(ebsql->priv->summary_fields[i]);
3921 
3922 			if (field->type != E_TYPE_CONTACT_ATTR_LIST)
3923 				continue;
3924 
3925 			success = ebsql_run_multi_delete (
3926 				ebsql, field, uid, error);
3927 
3928 			if (success)
3929 				success = ebsql_run_multi_insert (
3930 					ebsql, field, uid, contact, error);
3931 		}
3932 	}
3933 
3934 	g_free (uid);
3935 
3936 	return success;
3937 }
3938 
3939 /***************************************************************
3940  * Structures and utilities for preflight and query generation *
3941  ***************************************************************/
3942 
3943 /* This enumeration is ordered by severity, higher values
3944  * of PreflightStatus take precedence in error reporting.
3945  */
3946 typedef enum {
3947 	PREFLIGHT_OK = 0,
3948 	PREFLIGHT_LIST_ALL,
3949 	PREFLIGHT_NOT_SUMMARIZED,
3950 	PREFLIGHT_INVALID,
3951 	PREFLIGHT_UNSUPPORTED,
3952 } PreflightStatus;
3953 
3954 #define EBSQL_STATUS_STR(status) \
3955 	((status) == PREFLIGHT_OK ? "Ok" : \
3956 	 (status) == PREFLIGHT_LIST_ALL ? "List all" : \
3957 	 (status) == PREFLIGHT_NOT_SUMMARIZED ? "Not Summarized" : \
3958 	 (status) == PREFLIGHT_INVALID ? "Invalid" : \
3959 	 (status) == PREFLIGHT_UNSUPPORTED ? "Unsupported" : "(unknown status)")
3960 
3961 /* Whether we can satisfy the constraints or whether we
3962  * need to do a fallback, we still need to call
3963  * ebsql_generate_constraints()
3964  */
3965 #define EBSQL_STATUS_GEN_CONSTRAINTS(status) \
3966 	((status) == PREFLIGHT_OK || \
3967 	 (status) == PREFLIGHT_NOT_SUMMARIZED)
3968 
3969 /* Internal extension of the EBookQueryTest enumeration */
3970 enum {
3971 	/* 'exists' is a supported query on a field, but not part of EBookQueryTest */
3972 	BOOK_QUERY_EXISTS = E_BOOK_QUERY_LAST,
3973 	BOOK_QUERY_EXISTS_VCARD,
3974 
3975 	/* From here the compound types start */
3976 	BOOK_QUERY_SUB_AND,
3977 	BOOK_QUERY_SUB_OR,
3978 	BOOK_QUERY_SUB_NOT,
3979 	BOOK_QUERY_SUB_END,
3980 
3981 	BOOK_QUERY_SUB_FIRST = BOOK_QUERY_SUB_AND,
3982 };
3983 
3984 #define EBSQL_QUERY_TYPE_STR(query) \
3985 	((query) == BOOK_QUERY_EXISTS ? "exists" : \
3986 	 (query) == BOOK_QUERY_EXISTS_VCARD ? "exists_vcard" : \
3987 	 (query) == BOOK_QUERY_SUB_AND ? "AND" : \
3988 	 (query) == BOOK_QUERY_SUB_OR ? "OR" : \
3989 	 (query) == BOOK_QUERY_SUB_NOT ? "NOT" : \
3990 	 (query) == BOOK_QUERY_SUB_END ? "END" : \
3991 	 (query) == E_BOOK_QUERY_IS ? "is" : \
3992 	 (query) == E_BOOK_QUERY_CONTAINS ? "contains" : \
3993 	 (query) == E_BOOK_QUERY_BEGINS_WITH ? "begins-with" : \
3994 	 (query) == E_BOOK_QUERY_ENDS_WITH ? "ends-with" : \
3995 	 (query) == E_BOOK_QUERY_EQUALS_PHONE_NUMBER ? "eqphone" : \
3996 	 (query) == E_BOOK_QUERY_EQUALS_NATIONAL_PHONE_NUMBER ? "eqphone-national" : \
3997 	 (query) == E_BOOK_QUERY_EQUALS_SHORT_PHONE_NUMBER ? "eqphone-short" : \
3998 	 (query) == E_BOOK_QUERY_REGEX_NORMAL ? "regex-normal" : \
3999 	 (query) == E_BOOK_QUERY_REGEX_NORMAL ? "regex-raw" : "(unknown)")
4000 
4001 #define EBSQL_FIELD_ID_STR(field_id) \
4002 	((field_id) == E_CONTACT_FIELD_LAST ? "x-evolution-any-field" : \
4003 	 (field_id) == 0 ? "(not an EContactField)" : \
4004 	 e_contact_field_name (field_id))
4005 
4006 #define IS_QUERY_PHONE(query) \
4007 	((query) == E_BOOK_QUERY_EQUALS_PHONE_NUMBER || \
4008 	 (query) == E_BOOK_QUERY_EQUALS_NATIONAL_PHONE_NUMBER || \
4009 	 (query) == E_BOOK_QUERY_EQUALS_SHORT_PHONE_NUMBER)
4010 
4011 typedef struct {
4012 	guint          query; /* EBookQueryTest (extended) */
4013 } QueryElement;
4014 
4015 typedef struct {
4016 	guint          query; /* EBookQueryTest (extended) */
4017 } QueryDelimiter;
4018 
4019 typedef struct {
4020 	guint          query;          /* EBookQueryTest (extended) */
4021 
4022 	EContactField  field_id;       /* The EContactField to compare */
4023 	SummaryField  *field;          /* The summary field for 'field' */
4024 	gchar         *value;          /* The value to compare with */
4025 
4026 } QueryFieldTest;
4027 
4028 typedef struct {
4029 	guint          query;          /* EBookQueryTest (extended) */
4030 
4031 	/* Common fields from QueryFieldTest */
4032 	EContactField  field_id;       /* The EContactField to compare */
4033 	SummaryField  *field;          /* The summary field for 'field' */
4034 	gchar         *value;          /* The value to compare with */
4035 
4036 	/* Extension */
4037 	gchar         *region;   /* Region code from the query input */
4038 	gchar         *national; /* Parsed national number */
4039 	gint           country;  /* Parsed country code */
4040 } QueryPhoneTest;
4041 
4042 /* Stack initializer for the PreflightContext struct below */
4043 #define PREFLIGHT_CONTEXT_INIT { PREFLIGHT_OK, NULL, 0, FALSE }
4044 
4045 typedef struct {
4046 	PreflightStatus  status;         /* result status */
4047 	GPtrArray       *constraints;    /* main query; may be NULL */
4048 	guint64          aux_mask;       /* Bitmask of which auxiliary tables are needed in the query */
4049 	guint64          left_join_mask; /* Do we need to use a LEFT JOIN */
4050 } PreflightContext;
4051 
4052 static QueryElement *
query_delimiter_new(guint query)4053 query_delimiter_new (guint query)
4054 {
4055 	QueryDelimiter *delim;
4056 
4057 	g_return_val_if_fail (query >= BOOK_QUERY_SUB_FIRST, NULL);
4058 
4059 	delim = g_slice_new (QueryDelimiter);
4060 	delim->query = query;
4061 
4062 	return (QueryElement *) delim;
4063 }
4064 
4065 static QueryFieldTest *
query_field_test_new(guint query,EContactField field)4066 query_field_test_new (guint query,
4067                       EContactField field)
4068 {
4069 	QueryFieldTest *test;
4070 
4071 	g_return_val_if_fail (query < BOOK_QUERY_SUB_FIRST, NULL);
4072 	g_return_val_if_fail (IS_QUERY_PHONE (query) == FALSE, NULL);
4073 
4074 	test = g_slice_new (QueryFieldTest);
4075 	test->query = query;
4076 	test->field_id = field;
4077 
4078 	/* Instead of g_slice_new0, NULL them out manually */
4079 	test->field = NULL;
4080 	test->value = NULL;
4081 
4082 	return test;
4083 }
4084 
4085 static QueryPhoneTest *
query_phone_test_new(guint query,EContactField field)4086 query_phone_test_new (guint query,
4087                       EContactField field)
4088 {
4089 	QueryPhoneTest *test;
4090 
4091 	g_return_val_if_fail (IS_QUERY_PHONE (query), NULL);
4092 
4093 	test = g_slice_new (QueryPhoneTest);
4094 	test->query = query;
4095 	test->field_id = field;
4096 
4097 	/* Instead of g_slice_new0, NULL them out manually */
4098 	test->field = NULL;
4099 	test->value = NULL;
4100 
4101 	/* Extra QueryPhoneTest fields */
4102 	test->region = NULL;
4103 	test->national = NULL;
4104 	test->country = 0;
4105 
4106 	return test;
4107 }
4108 
4109 static void
query_element_free(QueryElement * element)4110 query_element_free (QueryElement *element)
4111 {
4112 	if (element) {
4113 
4114 		if (element->query >= BOOK_QUERY_SUB_FIRST) {
4115 			QueryDelimiter *delim = (QueryDelimiter *) element;
4116 
4117 			g_slice_free (QueryDelimiter, delim);
4118 		} else if (IS_QUERY_PHONE (element->query)) {
4119 			QueryPhoneTest *test = (QueryPhoneTest *) element;
4120 
4121 			g_free (test->value);
4122 			g_free (test->region);
4123 			g_free (test->national);
4124 			g_slice_free (QueryPhoneTest, test);
4125 		} else {
4126 			QueryFieldTest *test = (QueryFieldTest *) element;
4127 
4128 			g_free (test->value);
4129 			g_slice_free (QueryFieldTest, test);
4130 		}
4131 	}
4132 }
4133 
4134 /* We use ptr arrays for the QueryElement vectors */
4135 static inline void
constraints_insert(GPtrArray * array,gint idx,gpointer data)4136 constraints_insert (GPtrArray *array,
4137                     gint idx,
4138                     gpointer data)
4139 {
4140 #if 0
4141 	g_ptr_array_insert (array, idx, data);
4142 #else
4143 	g_return_if_fail ((idx >= -1) && (idx < (gint) array->len + 1));
4144 
4145 	if (idx < 0)
4146 		idx = array->len;
4147 
4148 	g_ptr_array_add (array, NULL);
4149 
4150 	if (idx != (array->len - 1))
4151 		memmove (
4152 			&(array->pdata[idx + 1]),
4153 			&(array->pdata[idx]),
4154 			((array->len - 1) - idx) * sizeof (gpointer));
4155 
4156 	array->pdata[idx] = data;
4157 #endif
4158 }
4159 
4160 static inline void
constraints_insert_delimiter(GPtrArray * array,gint idx,guint query)4161 constraints_insert_delimiter (GPtrArray *array,
4162                               gint idx,
4163                               guint query)
4164 {
4165 	QueryElement *delim;
4166 
4167 	delim = query_delimiter_new (query);
4168 	constraints_insert (array, idx, delim);
4169 }
4170 
4171 static inline void
constraints_insert_field_test(GPtrArray * array,gint idx,SummaryField * field,guint query,const gchar * value)4172 constraints_insert_field_test (GPtrArray *array,
4173                                gint idx,
4174                                SummaryField *field,
4175                                guint query,
4176                                const gchar *value)
4177 {
4178 	QueryFieldTest *test;
4179 
4180 	test = query_field_test_new (query, field->field_id);
4181 	test->field = field;
4182 	test->value = g_strdup (value);
4183 
4184 	constraints_insert (array, idx, test);
4185 }
4186 
4187 static void
preflight_context_clear(PreflightContext * context)4188 preflight_context_clear (PreflightContext *context)
4189 {
4190 	if (context) {
4191 		/* Free any allocated data, but leave the context values in place */
4192 		if (context->constraints)
4193 			g_ptr_array_free (context->constraints, TRUE);
4194 		context->constraints = NULL;
4195 	}
4196 }
4197 
4198 /* A small API to track the current sub-query context.
4199  *
4200  * I.e. sub contexts can be OR, AND, or NOT, in which
4201  * field tests or other sub contexts are nested.
4202  *
4203  * The 'count' field is a simple counter of how deep the contexts are nested.
4204  *
4205  * The 'cond_count' field is to be used by the caller for its own purposes;
4206  * it is incremented in sub_query_context_push() only if the inc_cond_count
4207  * parameter is TRUE. This is used by query_preflight_check() in a complex
4208  * fashion which is described there.
4209  */
4210 typedef GQueue SubQueryContext;
4211 
4212 typedef struct {
4213 	guint sub_type; /* The type of this sub context */
4214 	guint count;    /* The number of field tests so far in this context */
4215 	guint cond_count; /* User-specific conditional counter */
4216 } SubQueryData;
4217 
4218 #define sub_query_context_new g_queue_new
4219 #define sub_query_context_free(ctx) g_queue_free (ctx)
4220 
4221 static inline void
sub_query_context_push(SubQueryContext * ctx,guint sub_type,gboolean inc_cond_count)4222 sub_query_context_push (SubQueryContext *ctx,
4223                         guint sub_type, gboolean inc_cond_count)
4224 {
4225 	SubQueryData *data, *prev;
4226 
4227 	prev = g_queue_peek_tail (ctx);
4228 
4229 	data = g_slice_new (SubQueryData);
4230 	data->sub_type = sub_type;
4231 	data->count = 0;
4232 	data->cond_count = prev ? prev->cond_count : 0;
4233 	if (inc_cond_count)
4234 		data->cond_count++;
4235 
4236 	g_queue_push_tail (ctx, data);
4237 }
4238 
4239 static inline void
sub_query_context_pop(SubQueryContext * ctx)4240 sub_query_context_pop (SubQueryContext *ctx)
4241 {
4242 	SubQueryData *data;
4243 
4244 	data = g_queue_pop_tail (ctx);
4245 	g_slice_free (SubQueryData, data);
4246 }
4247 
4248 static inline guint
sub_query_context_peek_type(SubQueryContext * ctx)4249 sub_query_context_peek_type (SubQueryContext *ctx)
4250 {
4251 	SubQueryData *data;
4252 
4253 	data = g_queue_peek_tail (ctx);
4254 
4255 	return data->sub_type;
4256 }
4257 
4258 static inline guint
sub_query_context_peek_cond_counter(SubQueryContext * ctx)4259 sub_query_context_peek_cond_counter (SubQueryContext *ctx)
4260 {
4261 	SubQueryData *data;
4262 
4263 	data = g_queue_peek_tail (ctx);
4264 
4265 	if (data)
4266 		return data->cond_count;
4267 	else
4268 		return 0;
4269 }
4270 
4271 /* Returns the context field test count before incrementing */
4272 static inline guint
sub_query_context_increment(SubQueryContext * ctx)4273 sub_query_context_increment (SubQueryContext *ctx)
4274 {
4275 	SubQueryData *data;
4276 
4277 	data = g_queue_peek_tail (ctx);
4278 
4279 	if (data) {
4280 		data->count++;
4281 
4282 		return (data->count - 1);
4283 	}
4284 
4285 	/* If we're not in a sub context, just return 0 */
4286 	return 0;
4287 }
4288 
4289 /**********************************************************
4290  *                  Querying preflighting                 *
4291  **********************************************************
4292  *
4293  * The preflight checks are performed before a query might
4294  * take place in order to evaluate whether the given query
4295  * can be performed with the current summary configuration.
4296  *
4297  * After preflighting, all relevant data has been extracted
4298  * from the search expression and the search expression need
4299  * not be parsed again.
4300  */
4301 
4302 /* The PreflightSubCallback is expected to return TRUE
4303  * to keep iterating and FALSE to abort iteration.
4304  *
4305  * The sub_level is the counter of how deep the 'element'
4306  * is nested in sub elements, the offset is the real offset
4307  * of 'element' in the array passed to query_preflight_foreach_sub().
4308  */
4309 typedef gboolean (* PreflightSubCallback) (QueryElement *element,
4310 					   gint          sub_level,
4311 					   gint          offset,
4312 					   gpointer      user_data);
4313 
4314 static void
query_preflight_foreach_sub(QueryElement ** elements,gint n_elements,gint offset,gboolean include_delim,PreflightSubCallback callback,gpointer user_data)4315 query_preflight_foreach_sub (QueryElement **elements,
4316                              gint n_elements,
4317                              gint offset,
4318                              gboolean include_delim,
4319                              PreflightSubCallback callback,
4320                              gpointer user_data)
4321 {
4322 	gint sub_counter = 1, i;
4323 
4324 	g_return_if_fail (offset >= 0 && offset < n_elements);
4325 	g_return_if_fail (elements[offset]->query >= BOOK_QUERY_SUB_FIRST);
4326 	g_return_if_fail (callback != NULL);
4327 
4328 	if (include_delim && !callback (elements[offset], 0, offset, user_data))
4329 		return;
4330 
4331 	for (i = (offset + 1); sub_counter > 0 && i < n_elements; i++) {
4332 
4333 		if (elements[i]->query >= BOOK_QUERY_SUB_FIRST) {
4334 
4335 			if (elements[i]->query == BOOK_QUERY_SUB_END)
4336 				sub_counter--;
4337 			else
4338 				sub_counter++;
4339 
4340 			if (include_delim &&
4341 			    !callback (elements[i], sub_counter, i, user_data))
4342 				break;
4343 		} else {
4344 
4345 			if (!callback (elements[i], sub_counter, i, user_data))
4346 				break;
4347 		}
4348 	}
4349 }
4350 
4351 /* Table used in ESExp parsing below */
4352 static const struct {
4353 	const gchar *name;    /* Name of the symbol to match for this parse phase */
4354 	gboolean     subset;  /* TRUE for the subset ESExpIFunc, otherwise the field check ESExpFunc */
4355 	guint        test;    /* Extended EBookQueryTest value */
4356 } check_symbols[] = {
4357 	{ "and",              TRUE, BOOK_QUERY_SUB_AND },
4358 	{ "or",               TRUE, BOOK_QUERY_SUB_OR },
4359 	{ "not",              TRUE, BOOK_QUERY_SUB_NOT },
4360 
4361 	{ "contains",         FALSE, E_BOOK_QUERY_CONTAINS },
4362 	{ "is",               FALSE, E_BOOK_QUERY_IS },
4363 	{ "beginswith",       FALSE, E_BOOK_QUERY_BEGINS_WITH },
4364 	{ "endswith",         FALSE, E_BOOK_QUERY_ENDS_WITH },
4365 	{ "eqphone",          FALSE, E_BOOK_QUERY_EQUALS_PHONE_NUMBER },
4366 	{ "eqphone_national", FALSE, E_BOOK_QUERY_EQUALS_NATIONAL_PHONE_NUMBER },
4367 	{ "eqphone_short",    FALSE, E_BOOK_QUERY_EQUALS_SHORT_PHONE_NUMBER },
4368 	{ "regex_normal",     FALSE, E_BOOK_QUERY_REGEX_NORMAL },
4369 	{ "regex_raw",        FALSE, E_BOOK_QUERY_REGEX_RAW },
4370 	{ "exists",           FALSE, BOOK_QUERY_EXISTS },
4371 	{ "exists_vcard",     FALSE, BOOK_QUERY_EXISTS_VCARD }
4372 };
4373 
4374 /* Cheat our way into passing mode data to these funcs */
4375 static ESExpResult *
func_check_subset(ESExp * f,gint argc,struct _ESExpTerm ** argv,gpointer data)4376 func_check_subset (ESExp *f,
4377                    gint argc,
4378                    struct _ESExpTerm **argv,
4379                    gpointer data)
4380 {
4381 	ESExpResult *result, *sub_result;
4382 	GPtrArray *result_array;
4383 	QueryElement *element, **sub_elements;
4384 	gint i, j, len;
4385 	guint query_type;
4386 
4387 	query_type = GPOINTER_TO_UINT (data);
4388 
4389 	/* The compound query delimiter is the first element in this return array */
4390 	result_array = g_ptr_array_new_with_free_func ((GDestroyNotify) query_element_free);
4391 	element = query_delimiter_new (query_type);
4392 	g_ptr_array_add (result_array, element);
4393 
4394 	EBSQL_NOTE (
4395 		PREFLIGHT,
4396 		g_printerr (
4397 			"PREFLIGHT INIT: Open sub: %s\n",
4398 			EBSQL_QUERY_TYPE_STR (query_type)));
4399 
4400 	for (i = 0; i < argc; i++) {
4401 		sub_result = e_sexp_term_eval (f, argv[i]);
4402 
4403 		if (sub_result->type == ESEXP_RES_ARRAY_PTR) {
4404 			/* Steal the elements directly from the sub result */
4405 			sub_elements = (QueryElement **) sub_result->value.ptrarray->pdata;
4406 			len = sub_result->value.ptrarray->len;
4407 
4408 			for (j = 0; j < len; j++) {
4409 				element = sub_elements[j];
4410 				sub_elements[j] = NULL;
4411 
4412 				g_ptr_array_add (result_array, element);
4413 			}
4414 		}
4415 		e_sexp_result_free (f, sub_result);
4416 	}
4417 
4418 	EBSQL_NOTE (
4419 		PREFLIGHT,
4420 		g_printerr (
4421 			"PREFLIGHT INIT: Close sub: %s\n",
4422 			EBSQL_QUERY_TYPE_STR (query_type)));
4423 
4424 	/* The last element in this return array is the sub end delimiter */
4425 	element = query_delimiter_new (BOOK_QUERY_SUB_END);
4426 	g_ptr_array_add (result_array, element);
4427 
4428 	result = e_sexp_result_new (f, ESEXP_RES_ARRAY_PTR);
4429 	result->value.ptrarray = result_array;
4430 
4431 	return result;
4432 }
4433 
4434 static ESExpResult *
func_check(struct _ESExp * f,gint argc,struct _ESExpResult ** argv,gpointer data)4435 func_check (struct _ESExp *f,
4436             gint argc,
4437             struct _ESExpResult **argv,
4438             gpointer data)
4439 {
4440 	ESExpResult *result;
4441 	GPtrArray *result_array;
4442 	QueryElement *element = NULL;
4443 	EContactField field_id = 0;
4444 	const gchar *query_name = NULL;
4445 	const gchar *query_value = NULL;
4446 	const gchar *query_extra = NULL;
4447 	guint query_type;
4448 
4449 	query_type = GPOINTER_TO_UINT (data);
4450 
4451 	if (argc == 1 && query_type == BOOK_QUERY_EXISTS &&
4452 	    argv[0]->type == ESEXP_RES_STRING) {
4453 		query_name = argv[0]->value.string;
4454 
4455 		field_id = e_contact_field_id (query_name);
4456 	} else if (argc == 2 &&
4457 	    argv[0]->type == ESEXP_RES_STRING &&
4458 	    argv[1]->type == ESEXP_RES_STRING) {
4459 		query_name = argv[0]->value.string;
4460 		query_value = argv[1]->value.string;
4461 
4462 		/* We use E_CONTACT_FIELD_LAST to hold the special case of "x-evolution-any-field" */
4463 		if (g_strcmp0 (query_name, "x-evolution-any-field") == 0)
4464 			field_id = E_CONTACT_FIELD_LAST;
4465 		else
4466 			field_id = e_contact_field_id (query_name);
4467 
4468 	} else if (argc == 3 &&
4469 		   argv[0]->type == ESEXP_RES_STRING &&
4470 		   argv[1]->type == ESEXP_RES_STRING &&
4471 		   argv[2]->type == ESEXP_RES_STRING) {
4472 		query_name = argv[0]->value.string;
4473 		query_value = argv[1]->value.string;
4474 		query_extra = argv[2]->value.string;
4475 
4476 		field_id = e_contact_field_id (query_name);
4477 	}
4478 
4479 	if (IS_QUERY_PHONE (query_type)) {
4480 		QueryPhoneTest *test;
4481 
4482 		/* Collect data from this field test */
4483 		test = query_phone_test_new (query_type, field_id);
4484 		test->value = g_strdup (query_value);
4485 		test->region = g_strdup (query_extra);
4486 
4487 		element = (QueryElement *) test;
4488 	} else {
4489 		QueryFieldTest *test;
4490 
4491 		/* Collect data from this field test */
4492 		test = query_field_test_new (query_type, field_id);
4493 		test->value = g_strdup (query_value);
4494 
4495 		element = (QueryElement *) test;
4496 	}
4497 
4498 	EBSQL_NOTE (
4499 		PREFLIGHT,
4500 		g_printerr (
4501 			"PREFLIGHT INIT: Adding field test: `%s' on field `%s' "
4502 			"(field name: %s query value: %s query extra: %s)\n",
4503 			EBSQL_QUERY_TYPE_STR (query_type),
4504 			EBSQL_FIELD_ID_STR (field_id),
4505 			query_name, query_value, query_extra));
4506 
4507 	/* Return an array with only one element, for lack of a pointer type ESExpResult */
4508 	result_array = g_ptr_array_new_with_free_func ((GDestroyNotify) query_element_free);
4509 	g_ptr_array_add (result_array, element);
4510 
4511 	result = e_sexp_result_new (f, ESEXP_RES_ARRAY_PTR);
4512 	result->value.ptrarray = result_array;
4513 
4514 	return result;
4515 }
4516 
4517 /* Initial stage of preflighting:
4518  *
4519  *  o Parse the search expression and generate our array of QueryElements
4520  *  o Collect lengths of query terms
4521  */
4522 static void
query_preflight_initialize(PreflightContext * context,const gchar * sexp)4523 query_preflight_initialize (PreflightContext *context,
4524                             const gchar *sexp)
4525 {
4526 	ESExp *sexp_parser;
4527 	ESExpResult *result;
4528 	gint esexp_error, i;
4529 
4530 	if (sexp == NULL || *sexp == '\0') {
4531 		context->status = PREFLIGHT_LIST_ALL;
4532 		return;
4533 	}
4534 
4535 	sexp_parser = e_sexp_new ();
4536 
4537 	for (i = 0; i < G_N_ELEMENTS (check_symbols); i++) {
4538 		if (check_symbols[i].subset) {
4539 			e_sexp_add_ifunction (
4540 				sexp_parser, 0, check_symbols[i].name,
4541 				func_check_subset,
4542 				GUINT_TO_POINTER (check_symbols[i].test));
4543 		} else {
4544 			e_sexp_add_function (
4545 				sexp_parser, 0, check_symbols[i].name,
4546 				func_check,
4547 				GUINT_TO_POINTER (check_symbols[i].test));
4548 		}
4549 	}
4550 
4551 	e_sexp_input_text (sexp_parser, sexp, strlen (sexp));
4552 	esexp_error = e_sexp_parse (sexp_parser);
4553 
4554 	if (esexp_error == -1) {
4555 		context->status = PREFLIGHT_INVALID;
4556 
4557 		EBSQL_NOTE (
4558 			PREFLIGHT,
4559 			g_printerr ("PREFLIGHT INIT: Sexp parse error\n"));
4560 	} else {
4561 
4562 		result = e_sexp_eval (sexp_parser);
4563 		if (result) {
4564 
4565 			if (result->type == ESEXP_RES_ARRAY_PTR) {
4566 
4567 				/* Just steal the array away from the ESexpResult */
4568 				context->constraints = result->value.ptrarray;
4569 				result->value.ptrarray = NULL;
4570 
4571 			} else {
4572 				context->status = PREFLIGHT_INVALID;
4573 
4574 				EBSQL_NOTE (
4575 					PREFLIGHT,
4576 					g_printerr ("PREFLIGHT INIT: ERROR, Did not get GPtrArray\n"));
4577 			}
4578 		}
4579 
4580 		e_sexp_result_free (sexp_parser, result);
4581 	}
4582 
4583 	g_object_unref (sexp_parser);
4584 
4585 	EBSQL_NOTE (
4586 		PREFLIGHT,
4587 		g_printerr (
4588 			"PREFLIGHT INIT: Completed with status %s\n",
4589 			EBSQL_STATUS_STR (context->status)));
4590 }
4591 
4592 typedef struct {
4593 	EBookSqlite   *ebsql;
4594 	SummaryField  *field;
4595 	gboolean       condition;
4596 } AttrListCheckData;
4597 
4598 static gboolean
check_has_attr_list_cb(QueryElement * element,gint sub_level,gint offset,gpointer user_data)4599 check_has_attr_list_cb (QueryElement *element,
4600                         gint sub_level,
4601                         gint offset,
4602                         gpointer user_data)
4603 {
4604 	QueryFieldTest *test = (QueryFieldTest *) element;
4605 	AttrListCheckData *data = (AttrListCheckData *) user_data;
4606 
4607 	/* We havent resolved all the fields at this stage yet */
4608 	if (!test->field)
4609 		test->field = summary_field_get (data->ebsql, test->field_id);
4610 
4611 	if (test->field && test->field->type == E_TYPE_CONTACT_ATTR_LIST)
4612 		data->condition = TRUE;
4613 
4614 	/* Keep looping until we find one */
4615 	return (data->condition == FALSE);
4616 }
4617 
4618 static gboolean
check_different_fields_cb(QueryElement * element,gint sub_level,gint offset,gpointer user_data)4619 check_different_fields_cb (QueryElement *element,
4620 			   gint sub_level,
4621 			   gint offset,
4622 			   gpointer user_data)
4623 {
4624 	QueryFieldTest *test = (QueryFieldTest *) element;
4625 	AttrListCheckData *data = (AttrListCheckData *) user_data;
4626 
4627 	/* We havent resolved all the fields at this stage yet */
4628 	if (!test->field)
4629 		test->field = summary_field_get (data->ebsql, test->field_id);
4630 
4631 	if (test->field && data->field && test->field != data->field)
4632 		data->condition = TRUE;
4633 	else
4634 		data->field = test->field;
4635 
4636 	/* Keep looping until we find one */
4637 	return (data->condition == FALSE);
4638 }
4639 
4640 /* What is done in this pass:
4641  *  o Viability of the query is analyzed, i.e. can it be done with the summary columns.
4642  *  o Phone numbers are parsed and loaded onto QueryPhoneTests
4643  *  o Bitmask of auxiliary tables is collected
4644  */
4645 static void
query_preflight_check(PreflightContext * context,EBookSqlite * ebsql)4646 query_preflight_check (PreflightContext *context,
4647                        EBookSqlite *ebsql)
4648 {
4649 	gint i, n_elements;
4650 	QueryElement **elements;
4651 	SubQueryContext *ctx;
4652 
4653 	context->status = PREFLIGHT_OK;
4654 
4655 	if (context->constraints != NULL) {
4656 		elements = (QueryElement **) context->constraints->pdata;
4657 		n_elements = context->constraints->len;
4658 	} else {
4659 		elements = NULL;
4660 		n_elements = 0;
4661 	}
4662 
4663 	ctx = sub_query_context_new ();
4664 
4665 	for (i = 0; i < n_elements; i++) {
4666 		QueryFieldTest *test;
4667 		guint           field_test;
4668 
4669 		EBSQL_NOTE (
4670 			PREFLIGHT,
4671 			g_printerr (
4672 				"PREFLIGHT CHECK: Encountered: %s\n",
4673 				EBSQL_QUERY_TYPE_STR (elements[i]->query)));
4674 
4675 		if (elements[i]->query >= BOOK_QUERY_SUB_FIRST) {
4676 			AttrListCheckData data = { ebsql, NULL, FALSE };
4677 
4678 			switch (elements[i]->query) {
4679 			case BOOK_QUERY_SUB_OR:
4680 				/* An OR doesn't have to force us to use a LEFT JOIN, as long
4681 				   as all its sub-conditions are on the same field. */
4682 				query_preflight_foreach_sub (elements,
4683 							     n_elements,
4684 							     i, FALSE,
4685 							     check_different_fields_cb,
4686 							     &data);
4687 				/* falls through */
4688 			case BOOK_QUERY_SUB_AND:
4689 				sub_query_context_push (ctx, elements[i]->query, data.condition);
4690 				break;
4691 			case BOOK_QUERY_SUB_END:
4692 				sub_query_context_pop (ctx);
4693 				break;
4694 
4695 			/* It's too complicated to properly perform
4696 			 * the unary NOT operator on a constraint which
4697 			 * accesses attribute lists.
4698 			 *
4699 			 * Hint, if the contact has a "%.com" email address
4700 			 * and a "%.org" email address, what do we return
4701 			 * for (not (endswith "email" ".com") ?
4702 			 *
4703 			 * Currently we rely on DISTINCT to sort out
4704 			 * muliple results from the attribute list tables,
4705 			 * this breaks down with NOT.
4706 			 */
4707 			case BOOK_QUERY_SUB_NOT:
4708 				query_preflight_foreach_sub (elements,
4709 							     n_elements,
4710 							     i, FALSE,
4711 							     check_has_attr_list_cb,
4712 							     &data);
4713 
4714 				if (data.condition) {
4715 					context->status = MAX (
4716 						context->status,
4717 						PREFLIGHT_NOT_SUMMARIZED);
4718 					EBSQL_NOTE (
4719 						PREFLIGHT,
4720 						g_printerr (
4721 							"PREFLIGHT CHECK: "
4722 							"Setting invalid for NOT (mutli-attribute), "
4723 							"new status: %s\n",
4724 							EBSQL_STATUS_STR (context->status)));
4725 				}
4726 				break;
4727 
4728 			default:
4729 				g_warn_if_reached ();
4730 			}
4731 
4732 			continue;
4733 		}
4734 
4735 		test = (QueryFieldTest *) elements[i];
4736 		field_test = (EBookQueryTest) test->query;
4737 
4738 		if (!test->field)
4739 			test->field = summary_field_get (ebsql, test->field_id);
4740 
4741 		/* Even if the field is not in the summary, we need to
4742 		 * retport unsupported errors if phone number queries are
4743 		 * issued while libphonenumber is unavailable
4744 		 */
4745 		if (!test->field) {
4746 
4747 			/* Special case for e_book_query_any_field_contains().
4748 			 *
4749 			 * We interpret 'x-evolution-any-field' as E_CONTACT_FIELD_LAST
4750 			 */
4751 			if (test->field_id == E_CONTACT_FIELD_LAST) {
4752 
4753 				/* If we search for a NULL or zero length string, it
4754 				 * means 'get all contacts', that is considered a summary
4755 				 * query but is handled differently (i.e. we just drop the
4756 				 * field tests and run a regular query).
4757 				 *
4758 				 * This is only true if the 'any field contains' query is
4759 				 * the only test in the constraints, however.
4760 				 */
4761 				if (n_elements == 1 && (!test->value || !test->value[0])) {
4762 
4763 					context->status = MAX (context->status, PREFLIGHT_LIST_ALL);
4764 					EBSQL_NOTE (
4765 						PREFLIGHT,
4766 						g_printerr (
4767 							"PREFLIGHT CHECK: "
4768 							"Encountered lonesome 'x-evolution-any-field' with empty value, "
4769 							"new status: %s\n",
4770 							EBSQL_STATUS_STR (context->status)));
4771 				} else {
4772 
4773 					/* Searching for a value with 'x-evolution-any-field' is
4774 					 * not a summary query.
4775 					 */
4776 					context->status = MAX (context->status, PREFLIGHT_NOT_SUMMARIZED);
4777 					EBSQL_NOTE (
4778 						PREFLIGHT,
4779 						g_printerr (
4780 							"PREFLIGHT CHECK: "
4781 							"Encountered 'x-evolution-any-field', "
4782 							"new status: %s\n",
4783 							EBSQL_STATUS_STR (context->status)));
4784 				}
4785 
4786 			} else {
4787 
4788 				/* Couldnt resolve the field, it's not a summary query */
4789 				context->status = MAX (context->status, PREFLIGHT_NOT_SUMMARIZED);
4790 				EBSQL_NOTE (
4791 					PREFLIGHT,
4792 					g_printerr (
4793 						"PREFLIGHT CHECK: "
4794 						"Field `%s' not in the summary, new status: %s\n",
4795 						EBSQL_FIELD_ID_STR (test->field_id),
4796 						EBSQL_STATUS_STR (context->status)));
4797 			}
4798 		}
4799 
4800 		if (test->field && test->field->type == E_TYPE_CONTACT_CERT) {
4801 			/* For certificates, and later potentially other fields,
4802 			 * the only information in the summary is the fact that
4803 			 * they exist, or not. So the only check we can do from
4804 			 * the summary is BOOK_QUERY_EXISTS. */
4805 			if (field_test != BOOK_QUERY_EXISTS) {
4806 				context->status = MAX (context->status, PREFLIGHT_NOT_SUMMARIZED);
4807 				EBSQL_NOTE (
4808 					PREFLIGHT,
4809 					g_printerr (
4810 						"PREFLIGHT CHECK: "
4811 						"Cannot perform '%s' check on existence summary field '%s', new status: %s\n",
4812 						EBSQL_QUERY_TYPE_STR (field_test),
4813 						EBSQL_FIELD_ID_STR (test->field_id),
4814 						EBSQL_STATUS_STR (context->status)));
4815 			}
4816 			/* Bypass the other checks below which are not appropriate. */
4817 			continue;
4818 		}
4819 
4820 		switch (field_test) {
4821 		case E_BOOK_QUERY_IS:
4822 			break;
4823 
4824 		case BOOK_QUERY_EXISTS:
4825 		case E_BOOK_QUERY_CONTAINS:
4826 		case E_BOOK_QUERY_BEGINS_WITH:
4827 		case E_BOOK_QUERY_ENDS_WITH:
4828 		case E_BOOK_QUERY_REGEX_NORMAL:
4829 
4830 			/* All of these queries can only apply to string fields,
4831 			 * or fields which hold multiple strings
4832 			 */
4833 			if (test->field) {
4834 				if (test->field->type == G_TYPE_BOOLEAN &&
4835 				    field_test == BOOK_QUERY_EXISTS) {
4836 					context->status = MAX (context->status, PREFLIGHT_NOT_SUMMARIZED);
4837 				} else if (test->field->type != G_TYPE_STRING &&
4838 					   test->field->type != E_TYPE_CONTACT_ATTR_LIST) {
4839 					context->status = MAX (context->status, PREFLIGHT_INVALID);
4840 					EBSQL_NOTE (
4841 						PREFLIGHT,
4842 						g_printerr (
4843 							"PREFLIGHT CHECK: "
4844 							"Refusing pattern match on boolean field `%s', new status: %s\n",
4845 							EBSQL_FIELD_ID_STR (test->field_id),
4846 							EBSQL_STATUS_STR (context->status)));
4847 				}
4848 			}
4849 
4850 			break;
4851 
4852 		case BOOK_QUERY_EXISTS_VCARD:
4853 			/* Exists vCard queries only supported in the fallback */
4854 			context->status = MAX (context->status, PREFLIGHT_NOT_SUMMARIZED);
4855 			EBSQL_NOTE (
4856 				PREFLIGHT,
4857 				g_printerr (
4858 					"PREFLIGHT CHECK: "
4859 					"Exists vCard requires full data, new status: %s\n",
4860 					EBSQL_STATUS_STR (context->status)));
4861 			break;
4862 
4863 		case E_BOOK_QUERY_REGEX_RAW:
4864 			/* Raw regex queries only supported in the fallback */
4865 			context->status = MAX (context->status, PREFLIGHT_NOT_SUMMARIZED);
4866 			EBSQL_NOTE (
4867 				PREFLIGHT,
4868 				g_printerr (
4869 					"PREFLIGHT CHECK: "
4870 					"Raw regexp requires full data, new status: %s\n",
4871 					EBSQL_STATUS_STR (context->status)));
4872 			break;
4873 
4874 		case E_BOOK_QUERY_EQUALS_PHONE_NUMBER:
4875 		case E_BOOK_QUERY_EQUALS_NATIONAL_PHONE_NUMBER:
4876 		case E_BOOK_QUERY_EQUALS_SHORT_PHONE_NUMBER:
4877 
4878 			/* Phone number queries are supported so long as they are in the summary,
4879 			 * libphonenumber is available, and the phone number string is a valid one
4880 			 */
4881 			if (!e_phone_number_is_supported ()) {
4882 
4883 				context->status = MAX (context->status, PREFLIGHT_UNSUPPORTED);
4884 				EBSQL_NOTE (
4885 					PREFLIGHT,
4886 					g_printerr (
4887 						"PREFLIGHT CHECK: "
4888 						"Usupported phone number query, new status: %s\n",
4889 						EBSQL_STATUS_STR (context->status)));
4890 			} else {
4891 				QueryPhoneTest *phone_test = (QueryPhoneTest *) test;
4892 				EPhoneNumberCountrySource source;
4893 				EPhoneNumber *number;
4894 				const gchar *region_code;
4895 
4896 				if (phone_test->region)
4897 					region_code = phone_test->region;
4898 				else
4899 					region_code = ebsql->priv->region_code;
4900 
4901 				number = e_phone_number_from_string (
4902 					phone_test->value,
4903 					region_code, NULL);
4904 
4905 				if (number == NULL) {
4906 
4907 					context->status = MAX (context->status, PREFLIGHT_INVALID);
4908 					EBSQL_NOTE (
4909 						PREFLIGHT,
4910 						g_printerr (
4911 							"PREFLIGHT CHECK: "
4912 							"Invalid phone number `%s', new status: %s\n",
4913 							phone_test->value,
4914 							EBSQL_STATUS_STR (context->status)));
4915 				} else {
4916 					/* Collect values we'll need later while generating field
4917 					 * tests, no need to parse the phone number more than once
4918 					 */
4919 					phone_test->national = e_phone_number_get_national_number (number);
4920 					phone_test->country = e_phone_number_get_country_code (number, &source);
4921 					phone_test->national = remove_leading_zeros (phone_test->national);
4922 
4923 					if (source == E_PHONE_NUMBER_COUNTRY_FROM_DEFAULT)
4924 						phone_test->country = 0;
4925 
4926 					e_phone_number_free (number);
4927 				}
4928 			}
4929 			break;
4930 		}
4931 
4932 		if (test->field &&
4933 		    test->field->type == E_TYPE_CONTACT_ATTR_LIST) {
4934 			gint aux_index = summary_field_get_index (ebsql, test->field_id);
4935 
4936 			/* It's really improbable that we ever get 64 fields in the summary
4937 			 * In any case we warn about this in e_book_sqlite_new_full().
4938 			 */
4939 			g_warn_if_fail (aux_index >= 0 && aux_index < EBSQL_MAX_SUMMARY_FIELDS);
4940 
4941 			/* Just to mute a compiler warning when aux_index == -1 */
4942 			aux_index = ABS (aux_index);
4943 
4944 			context->aux_mask |= (1 << aux_index);
4945 			EBSQL_NOTE (
4946 				PREFLIGHT,
4947 				g_printerr (
4948 					"PREFLIGHT CHECK: "
4949 					"Adding auxiliary field `%s' to the mask\n",
4950 					EBSQL_FIELD_ID_STR (test->field_id)));
4951 
4952 			/* If this condition is a *requirement* for the overall query to
4953 			   match a given record (i.e. there's no surrounding 'OR' but
4954 			   only 'AND'), then we can use an inner join for the query and
4955 			   it will be a lot more efficient. If records without this
4956 			   condition can also match the overall condition, then we must
4957 			   use LEFT JOIN. */
4958 			if (sub_query_context_peek_cond_counter (ctx)) {
4959 				context->left_join_mask |= (1 << aux_index);
4960 				EBSQL_NOTE (
4961 					PREFLIGHT,
4962 					g_printerr (
4963 						"PREFLIGHT CHECK: "
4964 						"Using LEFT JOIN because auxiliary field is not absolute requirement\n"));
4965 			}
4966 		}
4967 	}
4968 
4969 	sub_query_context_free (ctx);
4970 }
4971 
4972 /* Handle special case of E_CONTACT_FULL_NAME
4973  *
4974  * For any query which accesses the full name field,
4975  * we need to also OR it with any of the related name
4976  * fields, IF those are found in the summary as well.
4977  */
4978 static void
query_preflight_substitute_full_name(PreflightContext * context,EBookSqlite * ebsql)4979 query_preflight_substitute_full_name (PreflightContext *context,
4980                                       EBookSqlite *ebsql)
4981 {
4982 	gint i, j;
4983 
4984 	for (i = 0; context->constraints != NULL && i < context->constraints->len; i++) {
4985 		SummaryField *family_name, *given_name, *nickname;
4986 		QueryElement *element;
4987 		QueryFieldTest *test;
4988 
4989 		element = g_ptr_array_index (context->constraints, i);
4990 
4991 		if (element->query >= BOOK_QUERY_SUB_FIRST)
4992 			continue;
4993 
4994 		test = (QueryFieldTest *) element;
4995 		if (test->field_id != E_CONTACT_FULL_NAME)
4996 			continue;
4997 
4998 		family_name = summary_field_get (ebsql, E_CONTACT_FAMILY_NAME);
4999 		given_name = summary_field_get (ebsql, E_CONTACT_GIVEN_NAME);
5000 		nickname = summary_field_get (ebsql, E_CONTACT_NICKNAME);
5001 
5002 		/* If any of these are in the summary, then we'll construct
5003 		 * a grouped OR statment for this E_CONTACT_FULL_NAME test */
5004 		if (family_name || given_name || nickname) {
5005 			/* Add the OR directly before the E_CONTACT_FULL_NAME test */
5006 			constraints_insert_delimiter (context->constraints, i, BOOK_QUERY_SUB_OR);
5007 
5008 			j = i + 2;
5009 
5010 			if (family_name)
5011 				constraints_insert_field_test (
5012 					context->constraints, j++,
5013 					family_name, test->query,
5014 					test->value);
5015 
5016 			if (given_name)
5017 				constraints_insert_field_test (
5018 					context->constraints, j++,
5019 					given_name, test->query,
5020 					test->value);
5021 
5022 			if (nickname)
5023 				constraints_insert_field_test (
5024 					context->constraints, j++,
5025 					nickname, test->query,
5026 					test->value);
5027 
5028 			constraints_insert_delimiter (context->constraints, j, BOOK_QUERY_SUB_END);
5029 
5030 			i = j;
5031 		}
5032 	}
5033 }
5034 
5035 static void
query_preflight(PreflightContext * context,EBookSqlite * ebsql,const gchar * sexp)5036 query_preflight (PreflightContext *context,
5037                  EBookSqlite *ebsql,
5038                  const gchar *sexp)
5039 {
5040 	EBSQL_NOTE (PREFLIGHT, g_printerr ("PREFLIGHT BEGIN\n"));
5041 	query_preflight_initialize (context, sexp);
5042 
5043 	if (context->status == PREFLIGHT_OK) {
5044 
5045 		query_preflight_check (context, ebsql);
5046 
5047 		/* No need to change the constraints if we're not
5048 		 * going to generate statements with it
5049 		 */
5050 		if (context->status == PREFLIGHT_OK) {
5051 			EBSQL_NOTE (
5052 				PREFLIGHT,
5053 				g_printerr ("PREFLIGHT: Substituting full name\n"));
5054 
5055 			/* Handle E_CONTACT_FULL_NAME substitutions */
5056 			query_preflight_substitute_full_name (context, ebsql);
5057 
5058 		} else {
5059 			EBSQL_NOTE (PREFLIGHT, g_printerr ("PREFLIGHT: Clearing context\n"));
5060 
5061 			/* We might use this context to perform a fallback query,
5062 			 * so let's clear out all the constraints now
5063 			 */
5064 			preflight_context_clear (context);
5065 		}
5066 	}
5067 
5068 	EBSQL_NOTE (
5069 		PREFLIGHT,
5070 		g_printerr (
5071 			"PREFLIGHT END (status: %s)\n",
5072 			EBSQL_STATUS_STR (context->status)));
5073 }
5074 
5075 /**********************************************************
5076  *                 Field Test Generators                  *
5077  **********************************************************
5078  *
5079  * This section contains the field test generators for
5080  * various EBookQueryTest types. When implementing new
5081  * query types, a new GenerateFieldTest needs to be created
5082  * and added to the table below.
5083  */
5084 
5085 typedef void (* GenerateFieldTest) (EBookSqlite      *ebsql,
5086 				    GString          *string,
5087 				    QueryFieldTest   *test);
5088 
5089 /* This function escapes characters which need escaping
5090  * for LIKE statements as well as the single quotes.
5091  *
5092  * The return value is not suitable to be formatted
5093  * with %Q or %q
5094  */
5095 static gchar *
ebsql_normalize_for_like(QueryFieldTest * test,gboolean reverse_string,gboolean * escape_needed)5096 ebsql_normalize_for_like (QueryFieldTest *test,
5097                           gboolean reverse_string,
5098                           gboolean *escape_needed)
5099 {
5100 	GString *str;
5101 	size_t len;
5102 	gchar c;
5103 	gboolean escape_modifier_needed = FALSE;
5104 	const gchar *normal = NULL;
5105 	const gchar *ptr;
5106 	const gchar *str_to_escape;
5107 	gchar *reverse = NULL;
5108 	gchar *freeme = NULL;
5109 
5110 	if (test->field_id == E_CONTACT_UID ||
5111 	    test->field_id == E_CONTACT_REV) {
5112 		normal = test->value;
5113 	} else {
5114 		freeme = e_util_utf8_normalize (test->value);
5115 		normal = freeme;
5116 	}
5117 
5118 	if (reverse_string) {
5119 		reverse = g_utf8_strreverse (normal, -1);
5120 		str_to_escape = reverse;
5121 	} else
5122 		str_to_escape = normal;
5123 
5124 	/* Just assume each character must be escaped. The result of this function
5125 	 * is discarded shortly after calling this function. Therefore it's
5126 	 * acceptable to possibly allocate twice the memory needed.
5127 	 */
5128 	len = strlen (str_to_escape);
5129 	str = g_string_sized_new (2 * len + 4 + strlen (EBSQL_ESCAPE_SEQUENCE) - 1);
5130 
5131 	ptr = str_to_escape;
5132 	while ((c = *ptr++)) {
5133 		if (c == '\'') {
5134 			g_string_append_c (str, '\'');
5135 		} else if (c == '%' || c == '_' || c == '^') {
5136 			g_string_append_c (str, '^');
5137 			escape_modifier_needed = TRUE;
5138 		}
5139 
5140 		g_string_append_c (str, c);
5141 	}
5142 
5143 	if (escape_needed)
5144 		*escape_needed = escape_modifier_needed;
5145 
5146 	g_free (freeme);
5147 	g_free (reverse);
5148 
5149 	return g_string_free (str, FALSE);
5150 }
5151 
5152 static void
field_test_query_is(EBookSqlite * ebsql,GString * string,QueryFieldTest * test)5153 field_test_query_is (EBookSqlite *ebsql,
5154                      GString *string,
5155                      QueryFieldTest *test)
5156 {
5157 	SummaryField *field = test->field;
5158 	gchar *normal;
5159 
5160 	ebsql_string_append_column (string, field, NULL);
5161 
5162 	if (test->field_id == E_CONTACT_UID ||
5163 	    test->field_id == E_CONTACT_REV) {
5164 		/* UID & REV fields are not normalized in the summary */
5165 		ebsql_string_append_printf (string, " = %Q", test->value);
5166 	} else {
5167 		normal = e_util_utf8_normalize (test->value);
5168 		ebsql_string_append_printf (string, " = %Q", normal);
5169 		g_free (normal);
5170 	}
5171 }
5172 
5173 static void
field_test_query_contains(EBookSqlite * ebsql,GString * string,QueryFieldTest * test)5174 field_test_query_contains (EBookSqlite *ebsql,
5175                            GString *string,
5176                            QueryFieldTest *test)
5177 {
5178 	SummaryField *field = test->field;
5179 	gboolean need_escape;
5180 	gchar *escaped;
5181 
5182 	escaped = ebsql_normalize_for_like (test, FALSE, &need_escape);
5183 
5184 	g_string_append_c (string, '(');
5185 
5186 	ebsql_string_append_column (string, field, NULL);
5187 	g_string_append (string, " IS NOT NULL AND ");
5188 	ebsql_string_append_column (string, field, NULL);
5189 	g_string_append (string, " LIKE '%");
5190 	g_string_append (string, escaped);
5191 	g_string_append (string, "%'");
5192 
5193 	if (need_escape)
5194 		g_string_append (string, EBSQL_ESCAPE_SEQUENCE);
5195 
5196 	g_string_append_c (string, ')');
5197 
5198 	g_free (escaped);
5199 }
5200 
5201 static void
field_test_query_begins_with(EBookSqlite * ebsql,GString * string,QueryFieldTest * test)5202 field_test_query_begins_with (EBookSqlite *ebsql,
5203                               GString *string,
5204                               QueryFieldTest *test)
5205 {
5206 	SummaryField *field = test->field;
5207 	gboolean need_escape;
5208 	gchar *escaped;
5209 
5210 	escaped = ebsql_normalize_for_like (test, FALSE, &need_escape);
5211 
5212 	g_string_append_c (string, '(');
5213 	ebsql_string_append_column (string, field, NULL);
5214 	g_string_append (string, " IS NOT NULL AND ");
5215 
5216 	ebsql_string_append_column (string, field, NULL);
5217 	g_string_append (string, " LIKE \'");
5218 	g_string_append (string, escaped);
5219 	g_string_append (string, "%\'");
5220 
5221 	if (need_escape)
5222 		g_string_append (string, EBSQL_ESCAPE_SEQUENCE);
5223 	g_string_append_c (string, ')');
5224 
5225 	g_free (escaped);
5226 }
5227 
5228 static void
field_test_query_ends_with(EBookSqlite * ebsql,GString * string,QueryFieldTest * test)5229 field_test_query_ends_with (EBookSqlite *ebsql,
5230                             GString *string,
5231                             QueryFieldTest *test)
5232 {
5233 	SummaryField *field = test->field;
5234 	gboolean need_escape;
5235 	gchar *escaped;
5236 
5237 	if ((field->index & INDEX_FLAG (SUFFIX)) != 0) {
5238 
5239 		escaped = ebsql_normalize_for_like (test, TRUE, &need_escape);
5240 
5241 		g_string_append_c (string, '(');
5242 		ebsql_string_append_column (string, field, EBSQL_SUFFIX_REVERSE);
5243 		g_string_append (string, " IS NOT NULL AND ");
5244 
5245 		ebsql_string_append_column (string, field, EBSQL_SUFFIX_REVERSE);
5246 		g_string_append (string, " LIKE \'");
5247 		g_string_append (string, escaped);
5248 		g_string_append (string, "%\'");
5249 
5250 	} else {
5251 
5252 		escaped = ebsql_normalize_for_like (test, FALSE, &need_escape);
5253 		g_string_append_c (string, '(');
5254 
5255 		ebsql_string_append_column (string, field, NULL);
5256 		g_string_append (string, " IS NOT NULL AND ");
5257 
5258 		ebsql_string_append_column (string, field, NULL);
5259 		g_string_append (string, " LIKE \'%");
5260 		g_string_append (string, escaped);
5261 		g_string_append_c (string, '\'');
5262 	}
5263 
5264 	if (need_escape)
5265 		g_string_append (string, EBSQL_ESCAPE_SEQUENCE);
5266 
5267 	g_string_append_c (string, ')');
5268 	g_free (escaped);
5269 }
5270 
5271 static void
field_test_query_eqphone(EBookSqlite * ebsql,GString * string,QueryFieldTest * test)5272 field_test_query_eqphone (EBookSqlite *ebsql,
5273                           GString *string,
5274                           QueryFieldTest *test)
5275 {
5276 	SummaryField *field = test->field;
5277 	QueryPhoneTest *phone_test = (QueryPhoneTest *) test;
5278 
5279 	if ((field->index & INDEX_FLAG (PHONE)) != 0) {
5280 
5281 		g_string_append_c (string, '(');
5282 		ebsql_string_append_column (string, field, EBSQL_SUFFIX_PHONE);
5283 		ebsql_string_append_printf (string, " = %Q AND ", phone_test->national);
5284 
5285 		/* For exact matches, a country code qualifier is required by both
5286 		 * query input and row input
5287 		 */
5288 		ebsql_string_append_column (string, field, EBSQL_SUFFIX_COUNTRY);
5289 		g_string_append (string, " != 0 AND ");
5290 
5291 		ebsql_string_append_column (string, field, EBSQL_SUFFIX_COUNTRY);
5292 		ebsql_string_append_printf (string, " = %d", phone_test->country);
5293 		g_string_append_c (string, ')');
5294 
5295 	} else {
5296 
5297 		/* No indexed columns available, perform the fallback */
5298 		g_string_append (string, EBSQL_FUNC_EQPHONE_EXACT " (");
5299 		ebsql_string_append_column (string, field, NULL);
5300 		ebsql_string_append_printf (string, ", %Q)", test->value);
5301 	}
5302 }
5303 
5304 static void
field_test_query_eqphone_national(EBookSqlite * ebsql,GString * string,QueryFieldTest * test)5305 field_test_query_eqphone_national (EBookSqlite *ebsql,
5306                                    GString *string,
5307                                    QueryFieldTest *test)
5308 {
5309 
5310 	SummaryField *field = test->field;
5311 	QueryPhoneTest *phone_test = (QueryPhoneTest *) test;
5312 
5313 	if ((field->index & INDEX_FLAG (PHONE)) != 0) {
5314 
5315 		/* Only a compound expression if there is a country code */
5316 		if (phone_test->country)
5317 			g_string_append_c (string, '(');
5318 
5319 		/* Generate: phone = %Q */
5320 		ebsql_string_append_column (string, field, EBSQL_SUFFIX_PHONE);
5321 		ebsql_string_append_printf (string, " = %Q", phone_test->national);
5322 
5323 		/* When doing a national search, no need to check country
5324 		 * code unless the query number also has a country code
5325 		 */
5326 		if (phone_test->country) {
5327 			/* Generate: (phone = %Q AND (country = 0 OR country = %d)) */
5328 			g_string_append (string, " AND (");
5329 			ebsql_string_append_column (string, field, EBSQL_SUFFIX_COUNTRY);
5330 			g_string_append (string, " = 0 OR ");
5331 			ebsql_string_append_column (string, field, EBSQL_SUFFIX_COUNTRY);
5332 			ebsql_string_append_printf (string, " = %d))", phone_test->country);
5333 
5334 		}
5335 
5336 	} else {
5337 
5338 		/* No indexed columns available, perform the fallback */
5339 		g_string_append (string, EBSQL_FUNC_EQPHONE_NATIONAL " (");
5340 		ebsql_string_append_column (string, field, NULL);
5341 		ebsql_string_append_printf (string, ", %Q)", test->value);
5342 	}
5343 }
5344 
5345 static void
field_test_query_eqphone_short(EBookSqlite * ebsql,GString * string,QueryFieldTest * test)5346 field_test_query_eqphone_short (EBookSqlite *ebsql,
5347                                 GString *string,
5348                                 QueryFieldTest *test)
5349 {
5350 	SummaryField *field = test->field;
5351 
5352 	/* No quick way to do the short match */
5353 	g_string_append (string, EBSQL_FUNC_EQPHONE_SHORT " (");
5354 	ebsql_string_append_column (string, field, NULL);
5355 	ebsql_string_append_printf (string, ", %Q)", test->value);
5356 }
5357 
5358 static void
field_test_query_regex_normal(EBookSqlite * ebsql,GString * string,QueryFieldTest * test)5359 field_test_query_regex_normal (EBookSqlite *ebsql,
5360                                GString *string,
5361                                QueryFieldTest *test)
5362 {
5363 	SummaryField *field = test->field;
5364 	gchar *normal;
5365 
5366 	normal = e_util_utf8_normalize (test->value);
5367 
5368 	if (field->aux_table)
5369 		ebsql_string_append_printf (
5370 			string, "%s.value REGEXP %Q",
5371 			field->aux_table_symbolic,
5372 			normal);
5373 	else
5374 		ebsql_string_append_printf (
5375 			string, "summary.%s REGEXP %Q",
5376 			field->dbname,
5377 			normal);
5378 
5379 	g_free (normal);
5380 }
5381 
5382 static void
field_test_query_exists(EBookSqlite * ebsql,GString * string,QueryFieldTest * test)5383 field_test_query_exists (EBookSqlite *ebsql,
5384                          GString *string,
5385                          QueryFieldTest *test)
5386 {
5387 	SummaryField *field = test->field;
5388 
5389 	ebsql_string_append_column (string, field, NULL);
5390 
5391 	if (test->field->type == E_TYPE_CONTACT_CERT)
5392 		ebsql_string_append_printf (string, " IS NOT '0'");
5393 	else
5394 		ebsql_string_append_printf (string, " IS NOT NULL");
5395 }
5396 
5397 /* Lookup table for field test generators per EBookQueryTest,
5398  *
5399  * WARNING: This must stay in line with the EBookQueryTest definition.
5400  */
5401 static const GenerateFieldTest field_test_func_table[] = {
5402 	field_test_query_is,               /* E_BOOK_QUERY_IS */
5403 	field_test_query_contains,         /* E_BOOK_QUERY_CONTAINS */
5404 	field_test_query_begins_with,      /* E_BOOK_QUERY_BEGINS_WITH */
5405 	field_test_query_ends_with,        /* E_BOOK_QUERY_ENDS_WITH */
5406 	field_test_query_eqphone,          /* E_BOOK_QUERY_EQUALS_PHONE_NUMBER */
5407 	field_test_query_eqphone_national, /* E_BOOK_QUERY_EQUALS_NATIONAL_PHONE_NUMBER */
5408 	field_test_query_eqphone_short,    /* E_BOOK_QUERY_EQUALS_SHORT_PHONE_NUMBER */
5409 	field_test_query_regex_normal,     /* E_BOOK_QUERY_REGEX_NORMAL */
5410 	NULL /* Requires fallback */,      /* E_BOOK_QUERY_REGEX_RAW  */
5411 	field_test_query_exists,           /* BOOK_QUERY_EXISTS */
5412 	NULL /* Requires fallback */       /* BOOK_QUERY_EXISTS_VCARD */
5413 };
5414 
5415 /**********************************************************
5416  *                   Querying Contacts                    *
5417  **********************************************************/
5418 
5419 /* The various search types indicate what should be fetched
5420  */
5421 typedef enum {
5422 	SEARCH_FULL,          /* Get a list of EbSqlSearchData */
5423 	SEARCH_UID_AND_REV,   /* Get a list of EbSqlSearchData, with shallow vcards only containing UID & REV */
5424 	SEARCH_UID,           /* Get a list of UID strings */
5425 	SEARCH_COUNT,         /* Get the number of matching rows */
5426 } SearchType;
5427 
5428 static void
ebsql_generate_constraints(EBookSqlite * ebsql,GString * string,GPtrArray * constraints,const gchar * sexp)5429 ebsql_generate_constraints (EBookSqlite *ebsql,
5430                             GString *string,
5431                             GPtrArray *constraints,
5432                             const gchar *sexp)
5433 {
5434 	SubQueryContext *ctx;
5435 	QueryDelimiter *delim;
5436 	QueryFieldTest *test;
5437 	QueryElement **elements;
5438 	gint n_elements, i;
5439 
5440 	/* If there are no constraints, we generate the fallback constraint for 'sexp' */
5441 	if (constraints == NULL) {
5442 		ebsql_string_append_printf (
5443 			string,
5444 			EBSQL_FUNC_COMPARE_VCARD " (%Q, %s)",
5445 			sexp, EBSQL_VCARD_FRAGMENT (ebsql));
5446 		return;
5447 	}
5448 
5449 	elements = (QueryElement **) constraints->pdata;
5450 	n_elements = constraints->len;
5451 
5452 	ctx = sub_query_context_new ();
5453 
5454 	for (i = 0; i < n_elements; i++) {
5455 		GenerateFieldTest generate_test_func = NULL;
5456 
5457 		/* Seperate field tests with the appropriate grouping */
5458 		if (elements[i]->query != BOOK_QUERY_SUB_END &&
5459 		    sub_query_context_increment (ctx) > 0) {
5460 			guint delim_type = sub_query_context_peek_type (ctx);
5461 
5462 			switch (delim_type) {
5463 			case BOOK_QUERY_SUB_AND:
5464 
5465 				g_string_append (string, " AND ");
5466 				break;
5467 
5468 			case BOOK_QUERY_SUB_OR:
5469 
5470 				g_string_append (string, " OR ");
5471 				break;
5472 
5473 			case BOOK_QUERY_SUB_NOT:
5474 
5475 				/* Nothing to do between children of NOT,
5476 				 * there should only ever be one child of NOT anyway
5477 				 */
5478 				break;
5479 
5480 			case BOOK_QUERY_SUB_END:
5481 			default:
5482 				g_warn_if_reached ();
5483 			}
5484 		}
5485 
5486 		if (elements[i]->query >= BOOK_QUERY_SUB_FIRST) {
5487 			delim = (QueryDelimiter *) elements[i];
5488 
5489 			switch (delim->query) {
5490 
5491 			case BOOK_QUERY_SUB_NOT:
5492 
5493 				/* NOT is a unary operator and as such
5494 				 * comes before the opening parenthesis
5495 				 */
5496 				g_string_append (string, "NOT ");
5497 
5498 				/* Fall through */
5499 
5500 			case BOOK_QUERY_SUB_AND:
5501 			case BOOK_QUERY_SUB_OR:
5502 
5503 				/* Open a grouped statement and push the context */
5504 				sub_query_context_push (ctx, delim->query, FALSE);
5505 				g_string_append_c (string, '(');
5506 				break;
5507 
5508 			case BOOK_QUERY_SUB_END:
5509 				/* Close a grouped statement and pop the context */
5510 				g_string_append_c (string, ')');
5511 				sub_query_context_pop (ctx);
5512 				break;
5513 			default:
5514 				g_warn_if_reached ();
5515 			}
5516 
5517 			continue;
5518 		}
5519 
5520 		/* Find the appropriate field test generator */
5521 		test = (QueryFieldTest *) elements[i];
5522 		if (test->query < G_N_ELEMENTS (field_test_func_table))
5523 			generate_test_func = field_test_func_table[test->query];
5524 
5525 		/* These should never happen, if it does it should be
5526 		 * fixed in the preflight checks
5527 		 */
5528 		g_warn_if_fail (generate_test_func != NULL);
5529 		g_warn_if_fail (test->field != NULL);
5530 
5531 		/* Generate the field test */
5532 		/* coverity[var_deref_op] */
5533 		generate_test_func (ebsql, string, test);
5534 	}
5535 
5536 	sub_query_context_free (ctx);
5537 }
5538 
5539 /* Generates the SELECT portion of the query, this will take care of
5540  * preparing the context of the query, and add the needed JOIN statements
5541  * based on which fields are referenced in the query expression.
5542  *
5543  * This also handles getting the correct callback and asking for the
5544  * right data depending on the 'search_type'
5545  */
5546 static EbSqlRowFunc
ebsql_generate_select(EBookSqlite * ebsql,GString * string,SearchType search_type,PreflightContext * context,GError ** error)5547 ebsql_generate_select (EBookSqlite *ebsql,
5548                        GString *string,
5549                        SearchType search_type,
5550                        PreflightContext *context,
5551                        GError **error)
5552 {
5553 	EbSqlRowFunc callback = NULL;
5554 	gboolean add_auxiliary_tables = FALSE;
5555 	gint i;
5556 
5557 	if (context->status == PREFLIGHT_OK &&
5558 	    context->aux_mask != 0)
5559 		add_auxiliary_tables = TRUE;
5560 
5561 	g_string_append (string, "SELECT ");
5562 	if (add_auxiliary_tables)
5563 		g_string_append (string, "DISTINCT ");
5564 
5565 	switch (search_type) {
5566 	case SEARCH_FULL:
5567 		callback = collect_full_results_cb;
5568 		g_string_append (string, "summary.uid, ");
5569 		g_string_append (string, EBSQL_VCARD_FRAGMENT (ebsql));
5570 		g_string_append (string, ", summary.bdata ");
5571 		break;
5572 	case SEARCH_UID_AND_REV:
5573 		callback = collect_lean_results_cb;
5574 		g_string_append (string, "summary.uid, summary.Rev, summary.bdata ");
5575 		break;
5576 	case SEARCH_UID:
5577 		callback = collect_uid_results_cb;
5578 		g_string_append (string, "summary.uid ");
5579 		break;
5580 	case SEARCH_COUNT:
5581 		callback = get_count_cb;
5582 		if (context->aux_mask != 0)
5583 			g_string_append (string, "count (DISTINCT summary.uid) ");
5584 		else
5585 			g_string_append (string, "count (*) ");
5586 		break;
5587 	}
5588 
5589 	ebsql_string_append_printf (string, "FROM %Q AS summary", ebsql->priv->folderid);
5590 
5591 	/* Add any required auxiliary tables into the query context */
5592 	if (add_auxiliary_tables) {
5593 		for (i = 0; i < ebsql->priv->n_summary_fields; i++) {
5594 
5595 			/* We cap this at EBSQL_MAX_SUMMARY_FIELDS (64 bits) at creation time */
5596 			if ((context->aux_mask & (1 << i)) != 0) {
5597 				SummaryField *field = &(ebsql->priv->summary_fields[i]);
5598 				gboolean left_join = (context->left_join_mask >> i) & 1;
5599 
5600 				/* Note the '+' in the JOIN statement.
5601 				 *
5602 				 * This plus makes the uid's index ineligable to participate
5603 				 * in any indexing.
5604 				 *
5605 				 * Without this, the indexes which we prefer for prefix or
5606 				 * suffix matching in the auxiliary tables are ignored and
5607 				 * only considered on exact matches.
5608 				 *
5609 				 * This is crucial to ensure that the uid index does not
5610 				 * compete with the value index in constraints such as:
5611 				 *
5612 				 *     WHERE email_list.value LIKE "boogieman%"
5613 				 */
5614 				ebsql_string_append_printf (
5615 					string, " %sJOIN %Q AS %s ON %s%s.uid = summary.uid",
5616 					left_join ? "LEFT " : "",
5617 					field->aux_table,
5618 					field->aux_table_symbolic,
5619 					left_join ? "" : "+",
5620 					field->aux_table_symbolic);
5621 			}
5622 		}
5623 	}
5624 
5625 	return callback;
5626 }
5627 
5628 static gboolean
ebsql_is_autocomplete_query(PreflightContext * context)5629 ebsql_is_autocomplete_query (PreflightContext *context)
5630 {
5631 	QueryFieldTest *test;
5632 	QueryElement **elements;
5633 	gint n_elements, i;
5634 	int non_aux_fields = 0;
5635 
5636 	if (context->status != PREFLIGHT_OK || context->aux_mask == 0)
5637 		return FALSE;
5638 
5639 	elements = (QueryElement **) context->constraints->pdata;
5640 	n_elements = context->constraints->len;
5641 
5642 	for (i = 0; i < n_elements; i++) {
5643 		test = (QueryFieldTest *) elements[i];
5644 
5645 		/* For these, check if the field being operated on is
5646 		   an auxiliary field or not. */
5647 		if (elements[i]->query == E_BOOK_QUERY_BEGINS_WITH ||
5648 		    elements[i]->query == E_BOOK_QUERY_ENDS_WITH ||
5649 		    elements[i]->query == E_BOOK_QUERY_IS ||
5650 		    elements[i]->query == BOOK_QUERY_EXISTS ||
5651 		    elements[i]->query == E_BOOK_QUERY_CONTAINS) {
5652 			if (test->field->type != E_TYPE_CONTACT_ATTR_LIST)
5653 				non_aux_fields++;
5654 			continue;
5655 		}
5656 
5657 		/* Nothing else is allowed other than "(or" ... ")" */
5658 		if (elements[i]->query != BOOK_QUERY_SUB_OR &&
5659 		    elements[i]->query != BOOK_QUERY_SUB_END)
5660 			return FALSE;
5661 	}
5662 
5663 	/* If there were no non-aux fields being queried, don't bother */
5664 	return non_aux_fields != 0;
5665 }
5666 
5667 static EbSqlRowFunc
ebsql_generate_autocomplete_query(EBookSqlite * ebsql,GString * string,SearchType search_type,PreflightContext * context,GError ** error)5668 ebsql_generate_autocomplete_query (EBookSqlite *ebsql,
5669 				   GString *string,
5670 				   SearchType search_type,
5671 				   PreflightContext *context,
5672 				   GError **error)
5673 {
5674 	QueryElement **elements;
5675 	gint n_elements, i;
5676 	guint64 aux_mask = context->aux_mask;
5677 	guint64 left_join_mask = context->left_join_mask;
5678 	EbSqlRowFunc callback;
5679 	gboolean first = TRUE;
5680 
5681 	elements = (QueryElement **) context->constraints->pdata;
5682 	n_elements = context->constraints->len;
5683 
5684 	/* First the queries which use aux tables. */
5685 	for (i = 0; i < n_elements; i++) {
5686 		GenerateFieldTest generate_test_func = NULL;
5687 		QueryFieldTest *test;
5688 		gint aux_index;
5689 
5690 		if (elements[i]->query == BOOK_QUERY_SUB_OR ||
5691 		    elements[i]->query == BOOK_QUERY_SUB_END)
5692 			continue;
5693 
5694 		test = (QueryFieldTest *) elements[i];
5695 		if (test->field->type != E_TYPE_CONTACT_ATTR_LIST)
5696 			continue;
5697 
5698 		aux_index = summary_field_get_index (ebsql, test->field_id);
5699 		g_warn_if_fail (aux_index >= 0 && aux_index < EBSQL_MAX_SUMMARY_FIELDS);
5700 
5701 		/* Just to mute a compiler warning when aux_index == -1 */
5702 		aux_index = ABS (aux_index);
5703 
5704 		context->aux_mask = (1 << aux_index);
5705 		context->left_join_mask = 0;
5706 
5707 		callback = ebsql_generate_select (ebsql, string, search_type, context, error);
5708 		g_string_append (string, " WHERE ");
5709 		context->aux_mask = aux_mask;
5710 		context->left_join_mask = left_join_mask;
5711 		if (!callback)
5712 			return NULL;
5713 
5714 		generate_test_func = field_test_func_table[test->query];
5715 		generate_test_func (ebsql, string, test);
5716 
5717 		g_string_append (string, " UNION ");
5718 	}
5719 	/* Finally, generate the SELECT for the primary fields. */
5720 	context->aux_mask = 0;
5721 	callback = ebsql_generate_select (ebsql, string, search_type, context, error);
5722 	context->aux_mask = aux_mask;
5723 	if (!callback)
5724 		return NULL;
5725 
5726 	g_string_append (string, " WHERE ");
5727 
5728 	for (i = 0; i < n_elements; i++) {
5729 		GenerateFieldTest generate_test_func = NULL;
5730 		QueryFieldTest *test;
5731 
5732 		if (elements[i]->query == BOOK_QUERY_SUB_OR ||
5733 		    elements[i]->query == BOOK_QUERY_SUB_END)
5734 			continue;
5735 
5736 		test = (QueryFieldTest *) elements[i];
5737 		if (test->field->type == E_TYPE_CONTACT_ATTR_LIST)
5738 			continue;
5739 
5740 		if (!first)
5741 			g_string_append (string, " OR ");
5742 		else
5743 			first = FALSE;
5744 
5745 		generate_test_func = field_test_func_table[test->query];
5746 		generate_test_func (ebsql, string, test);
5747 	}
5748 
5749 	return callback;
5750 }
5751 static gboolean
ebsql_do_search_query(EBookSqlite * ebsql,PreflightContext * context,const gchar * sexp,SearchType search_type,GSList ** return_data,GCancellable * cancellable,GError ** error)5752 ebsql_do_search_query (EBookSqlite *ebsql,
5753                        PreflightContext *context,
5754                        const gchar *sexp,
5755                        SearchType search_type,
5756                        GSList **return_data,
5757                        GCancellable *cancellable,
5758                        GError **error)
5759 {
5760 	GString *string;
5761 	EbSqlRowFunc callback = NULL;
5762 	gboolean success = FALSE;
5763 
5764 	/* We might calculate a reasonable estimation of bytes
5765 	 * during the preflight checks */
5766 	string = g_string_sized_new (GENERATED_QUERY_BYTES);
5767 
5768 	/* Extra special case. For the common case of the email composer's
5769 	   addressbook autocompletion, we really want the most optimal query.
5770 	   So check for it and use a basically hand-crafted one. */
5771         if (ebsql_is_autocomplete_query(context)) {
5772 		callback = ebsql_generate_autocomplete_query (ebsql, string, search_type, context, error);
5773 	} else {
5774 		/* Generate the leading SELECT statement */
5775 		callback = ebsql_generate_select (
5776 						  ebsql, string, search_type, context, error);
5777 
5778 		if (callback &&
5779 		    EBSQL_STATUS_GEN_CONSTRAINTS (context->status)) {
5780 			/*
5781 			 * Now generate the search expression on the main contacts table
5782 			 */
5783 			g_string_append (string, " WHERE ");
5784 			ebsql_generate_constraints (
5785 				ebsql, string, context->constraints, sexp);
5786 		}
5787 	}
5788 
5789 	if (callback)
5790 		success = ebsql_exec (
5791 			ebsql, string->str,
5792 			callback, return_data,
5793 			cancellable, error);
5794 
5795 	g_string_free (string, TRUE);
5796 
5797 	return success;
5798 }
5799 
5800 /* ebsql_search_query:
5801  * @ebsql: An EBookSqlite
5802  * @sexp: The search expression, or NULL for all contacts
5803  * @search_type: Indicates what kind of data should be returned
5804  * @return_data: A list of data fetched from the DB, as specified by 'search_type'
5805  * @error: Location to store any error which may have occurred
5806  *
5807  * This is the main common entry point for querying contacts.
5808  *
5809  * If the query cannot be satisfied with the summary, then
5810  * a fallback will automatically be used.
5811  */
5812 static gboolean
ebsql_search_query(EBookSqlite * ebsql,const gchar * sexp,SearchType search_type,GSList ** return_data,GCancellable * cancellable,GError ** error)5813 ebsql_search_query (EBookSqlite *ebsql,
5814                     const gchar *sexp,
5815                     SearchType search_type,
5816                     GSList **return_data,
5817                     GCancellable *cancellable,
5818                     GError **error)
5819 {
5820 	PreflightContext context = PREFLIGHT_CONTEXT_INIT;
5821 	gboolean success = FALSE;
5822 
5823 	/* Now start with the query preflighting */
5824 	query_preflight (&context, ebsql, sexp);
5825 
5826 	switch (context.status) {
5827 	case PREFLIGHT_OK:
5828 	case PREFLIGHT_LIST_ALL:
5829 	case PREFLIGHT_NOT_SUMMARIZED:
5830 		/* No errors, let's really search */
5831 		success = ebsql_do_search_query (
5832 			ebsql, &context, sexp,
5833 			search_type, return_data,
5834 			cancellable, error);
5835 		break;
5836 
5837 	case PREFLIGHT_INVALID:
5838 		EBSQL_SET_ERROR (
5839 			error,
5840 			E_BOOK_SQLITE_ERROR_INVALID_QUERY,
5841 			_("Invalid query: %s"), sexp);
5842 		break;
5843 
5844 	case PREFLIGHT_UNSUPPORTED:
5845 		EBSQL_SET_ERROR_LITERAL (
5846 			error,
5847 			E_BOOK_SQLITE_ERROR_UNSUPPORTED_QUERY,
5848 			_("Query contained unsupported elements"));
5849 		break;
5850 	}
5851 
5852 	preflight_context_clear (&context);
5853 
5854 	return success;
5855 }
5856 
5857 /******************************************************************
5858  *                    EbSqlCursor Implementation                  *
5859  ******************************************************************/
5860 typedef struct _CursorState CursorState;
5861 
5862 struct _CursorState {
5863 	gchar            **values;    /* The current cursor position, results will be returned after this position */
5864 	gchar             *last_uid;  /* The current cursor contact UID position, used as a tie breaker */
5865 	EbSqlCursorOrigin  position;  /* The position is updated with the cursor state and is used to distinguish
5866 				       * between the beginning and the ending of the cursor's contact list.
5867 				       * While the cursor is in a non-null state, the position will be
5868 				       * EBSQL_CURSOR_ORIGIN_CURRENT.
5869 				       */
5870 };
5871 
5872 struct _EbSqlCursor {
5873 	EBookBackendSExp *sexp;       /* An EBookBackendSExp based on the query, used by e_book_sqlite_cursor_compare () */
5874 	gchar         *select_vcards; /* The first fragment when querying results */
5875 	gchar         *select_count;  /* The first fragment when querying contact counts */
5876 	gchar         *query;         /* The SQL query expression derived from the passed search expression */
5877 	gchar         *order;         /* The normal order SQL query fragment to append at the end, containing ORDER BY etc */
5878 	gchar         *reverse_order; /* The reverse order SQL query fragment to append at the end, containing ORDER BY etc */
5879 
5880 	EContactField       *sort_fields;   /* The fields to sort in a query in the order or sort priority */
5881 	EBookCursorSortType *sort_types;    /* The sort method to use for each field */
5882 	gint                 n_sort_fields; /* The amound of sort fields */
5883 
5884 	CursorState          state;
5885 };
5886 
5887 static CursorState *cursor_state_copy             (EbSqlCursor          *cursor,
5888 						   CursorState          *state);
5889 static void         cursor_state_free             (EbSqlCursor          *cursor,
5890 						   CursorState          *state);
5891 static void         cursor_state_clear            (EbSqlCursor          *cursor,
5892 						   CursorState          *state,
5893 						   EbSqlCursorOrigin     position);
5894 static void         cursor_state_set_from_contact (EBookSqlite          *ebsql,
5895 						   EbSqlCursor          *cursor,
5896 						   CursorState          *state,
5897 						   EContact             *contact);
5898 static void         cursor_state_set_from_vcard   (EBookSqlite          *ebsql,
5899 						   EbSqlCursor          *cursor,
5900 						   CursorState          *state,
5901 						   const gchar          *vcard);
5902 
5903 static CursorState *
cursor_state_copy(EbSqlCursor * cursor,CursorState * state)5904 cursor_state_copy (EbSqlCursor *cursor,
5905                    CursorState *state)
5906 {
5907 	CursorState *copy;
5908 	gint i;
5909 
5910 	copy = g_slice_new0 (CursorState);
5911 	copy->values = g_new0 (gchar *, cursor->n_sort_fields);
5912 
5913 	for (i = 0; i < cursor->n_sort_fields; i++)
5914 		copy->values[i] = g_strdup (state->values[i]);
5915 
5916 	copy->last_uid = g_strdup (state->last_uid);
5917 	copy->position = state->position;
5918 
5919 	return copy;
5920 }
5921 
5922 static void
cursor_state_free(EbSqlCursor * cursor,CursorState * state)5923 cursor_state_free (EbSqlCursor *cursor,
5924                    CursorState *state)
5925 {
5926 	if (state) {
5927 		cursor_state_clear (cursor, state, EBSQL_CURSOR_ORIGIN_BEGIN);
5928 		g_free (state->values);
5929 		g_slice_free (CursorState, state);
5930 	}
5931 }
5932 
5933 static void
cursor_state_clear(EbSqlCursor * cursor,CursorState * state,EbSqlCursorOrigin position)5934 cursor_state_clear (EbSqlCursor *cursor,
5935                     CursorState *state,
5936                     EbSqlCursorOrigin position)
5937 {
5938 	gint i;
5939 
5940 	for (i = 0; i < cursor->n_sort_fields; i++) {
5941 		g_free (state->values[i]);
5942 		state->values[i] = NULL;
5943 	}
5944 
5945 	g_free (state->last_uid);
5946 	state->last_uid = NULL;
5947 	state->position = position;
5948 }
5949 
5950 static void
cursor_state_set_from_contact(EBookSqlite * ebsql,EbSqlCursor * cursor,CursorState * state,EContact * contact)5951 cursor_state_set_from_contact (EBookSqlite *ebsql,
5952                                EbSqlCursor *cursor,
5953                                CursorState *state,
5954                                EContact *contact)
5955 {
5956 	gint i;
5957 
5958 	cursor_state_clear (cursor, state, EBSQL_CURSOR_ORIGIN_BEGIN);
5959 
5960 	for (i = 0; i < cursor->n_sort_fields; i++) {
5961 		const gchar *string = e_contact_get_const (contact, cursor->sort_fields[i]);
5962 		SummaryField *field;
5963 		gchar *sort_key;
5964 
5965 		if (string)
5966 			sort_key = e_collator_generate_key (
5967 				ebsql->priv->collator,
5968 				string, NULL);
5969 		else
5970 			sort_key = g_strdup ("");
5971 
5972 		field = summary_field_get (ebsql, cursor->sort_fields[i]);
5973 
5974 		if (field && (field->index & INDEX_FLAG (SORT_KEY)) != 0) {
5975 			state->values[i] = sort_key;
5976 		} else {
5977 			state->values[i] = ebsql_encode_vcard_sort_key (sort_key);
5978 			g_free (sort_key);
5979 		}
5980 	}
5981 
5982 	state->last_uid = e_contact_get (contact, E_CONTACT_UID);
5983 	state->position = EBSQL_CURSOR_ORIGIN_CURRENT;
5984 }
5985 
5986 static void
cursor_state_set_from_vcard(EBookSqlite * ebsql,EbSqlCursor * cursor,CursorState * state,const gchar * vcard)5987 cursor_state_set_from_vcard (EBookSqlite *ebsql,
5988                              EbSqlCursor *cursor,
5989                              CursorState *state,
5990                              const gchar *vcard)
5991 {
5992 	EContact *contact;
5993 
5994 	contact = e_contact_new_from_vcard (vcard);
5995 	cursor_state_set_from_contact (ebsql, cursor, state, contact);
5996 	g_object_unref (contact);
5997 }
5998 
5999 static gboolean
ebsql_cursor_setup_query(EBookSqlite * ebsql,EbSqlCursor * cursor,const gchar * sexp,GError ** error)6000 ebsql_cursor_setup_query (EBookSqlite *ebsql,
6001                           EbSqlCursor *cursor,
6002                           const gchar *sexp,
6003                           GError **error)
6004 {
6005 	PreflightContext context = PREFLIGHT_CONTEXT_INIT;
6006 	GString *string;
6007 
6008 	/* Preflighting and error checking */
6009 	if (sexp) {
6010 		query_preflight (&context, ebsql, sexp);
6011 
6012 		if (context.status > PREFLIGHT_NOT_SUMMARIZED) {
6013 			EBSQL_SET_ERROR_LITERAL (
6014 				error,
6015 				E_BOOK_SQLITE_ERROR_INVALID_QUERY,
6016 				_("Invalid query for EbSqlCursor"));
6017 
6018 			preflight_context_clear (&context);
6019 			return FALSE;
6020 
6021 		}
6022 	}
6023 
6024 	/* Now we caught the errors, let's generate our queries and get out of here ... */
6025 	g_free (cursor->select_vcards);
6026 	g_free (cursor->select_count);
6027 	g_free (cursor->query);
6028 	g_clear_object (&(cursor->sexp));
6029 
6030 	/* Generate the leading SELECT portions that we need */
6031 	string = g_string_new ("");
6032 	ebsql_generate_select (ebsql, string, SEARCH_FULL, &context, NULL);
6033 	cursor->select_vcards = g_string_free (string, FALSE);
6034 
6035 	string = g_string_new ("");
6036 	ebsql_generate_select (ebsql, string, SEARCH_COUNT, &context, NULL);
6037 	cursor->select_count = g_string_free (string, FALSE);
6038 
6039 	if (sexp == NULL || context.status == PREFLIGHT_LIST_ALL) {
6040 		cursor->query = NULL;
6041 		cursor->sexp = NULL;
6042 	} else {
6043 		/* Generate the constraints for our queries
6044 		 */
6045 		string = g_string_new (NULL);
6046 		ebsql_generate_constraints (
6047 			ebsql, string, context.constraints, sexp);
6048 		cursor->query = g_string_free (string, FALSE);
6049 		cursor->sexp = e_book_backend_sexp_new (sexp);
6050 	}
6051 
6052 	preflight_context_clear (&context);
6053 
6054 	return TRUE;
6055 }
6056 
6057 static gchar *
ebsql_cursor_order_by_fragment(EBookSqlite * ebsql,const EContactField * sort_fields,const EBookCursorSortType * sort_types,guint n_sort_fields,gboolean reverse)6058 ebsql_cursor_order_by_fragment (EBookSqlite *ebsql,
6059                                 const EContactField *sort_fields,
6060                                 const EBookCursorSortType *sort_types,
6061                                 guint n_sort_fields,
6062                                 gboolean reverse)
6063 {
6064 	GString *string;
6065 	gint i;
6066 
6067 	string = g_string_new ("ORDER BY ");
6068 
6069 	for (i = 0; i < n_sort_fields; i++) {
6070 		SummaryField *field = summary_field_get (ebsql, sort_fields[i]);
6071 
6072 		if (i > 0)
6073 			g_string_append (string, ", ");
6074 
6075 		if (field &&
6076 		    (field->index & INDEX_FLAG (SORT_KEY)) != 0) {
6077 			g_string_append (string, "summary.");
6078 			g_string_append (string, field->dbname);
6079 			g_string_append (string, "_" EBSQL_SUFFIX_SORT_KEY " ");
6080 		} else {
6081 			g_string_append (string, EBSQL_VCARD_FRAGMENT (ebsql));
6082 			g_string_append (string, " COLLATE ");
6083 			g_string_append (string, EBSQL_COLLATE_PREFIX);
6084 			g_string_append (string, e_contact_field_name (sort_fields[i]));
6085 			g_string_append_c (string, ' ');
6086 		}
6087 
6088 		if (reverse)
6089 			g_string_append (string, (sort_types[i] == E_BOOK_CURSOR_SORT_ASCENDING ? "DESC" : "ASC"));
6090 		else
6091 			g_string_append (string, (sort_types[i] == E_BOOK_CURSOR_SORT_ASCENDING ? "ASC" : "DESC"));
6092 	}
6093 
6094 	/* Also order the UID, since it's our tie breaker */
6095 	if (n_sort_fields > 0)
6096 		g_string_append (string, ", ");
6097 
6098 	g_string_append (string, "summary.uid ");
6099 	g_string_append (string, reverse ? "DESC" : "ASC");
6100 
6101 	return g_string_free (string, FALSE);
6102 }
6103 
6104 static EbSqlCursor *
ebsql_cursor_new(EBookSqlite * ebsql,const gchar * sexp,const EContactField * sort_fields,const EBookCursorSortType * sort_types,guint n_sort_fields)6105 ebsql_cursor_new (EBookSqlite *ebsql,
6106                   const gchar *sexp,
6107                   const EContactField *sort_fields,
6108                   const EBookCursorSortType *sort_types,
6109                   guint n_sort_fields)
6110 {
6111 	EbSqlCursor *cursor = g_slice_new0 (EbSqlCursor);
6112 
6113 	cursor->order = ebsql_cursor_order_by_fragment (
6114 		ebsql, sort_fields, sort_types, n_sort_fields, FALSE);
6115 	cursor->reverse_order = ebsql_cursor_order_by_fragment (
6116 		ebsql, sort_fields, sort_types, n_sort_fields, TRUE);
6117 
6118 	/* Sort parameters */
6119 	cursor->n_sort_fields = n_sort_fields;
6120 	cursor->sort_fields = g_memdup (sort_fields, sizeof (EContactField) * n_sort_fields);
6121 	cursor->sort_types = g_memdup (sort_types,  sizeof (EBookCursorSortType) * n_sort_fields);
6122 
6123 	/* Cursor state */
6124 	cursor->state.values = g_new0 (gchar *, n_sort_fields);
6125 	cursor->state.last_uid = NULL;
6126 	cursor->state.position = EBSQL_CURSOR_ORIGIN_BEGIN;
6127 
6128 	return cursor;
6129 }
6130 
6131 static void
ebsql_cursor_free(EbSqlCursor * cursor)6132 ebsql_cursor_free (EbSqlCursor *cursor)
6133 {
6134 	if (cursor) {
6135 		cursor_state_clear (cursor, &(cursor->state), EBSQL_CURSOR_ORIGIN_BEGIN);
6136 		g_free (cursor->state.values);
6137 
6138 		g_clear_object (&(cursor->sexp));
6139 		g_free (cursor->select_vcards);
6140 		g_free (cursor->select_count);
6141 		g_free (cursor->query);
6142 		g_free (cursor->order);
6143 		g_free (cursor->reverse_order);
6144 		g_free (cursor->sort_fields);
6145 		g_free (cursor->sort_types);
6146 
6147 		g_slice_free (EbSqlCursor, cursor);
6148 	}
6149 }
6150 
6151 #define GREATER_OR_LESS(cursor, idx, reverse) \
6152 	(reverse ? \
6153 	 (((EbSqlCursor *) cursor)->sort_types[idx] == E_BOOK_CURSOR_SORT_ASCENDING ? '<' : '>') : \
6154 	 (((EbSqlCursor *) cursor)->sort_types[idx] == E_BOOK_CURSOR_SORT_ASCENDING ? '>' : '<'))
6155 
6156 static inline void
ebsql_cursor_format_equality(EBookSqlite * ebsql,GString * string,EContactField field_id,const gchar * value,gchar equality)6157 ebsql_cursor_format_equality (EBookSqlite *ebsql,
6158                               GString *string,
6159                               EContactField field_id,
6160                               const gchar *value,
6161                               gchar equality)
6162 {
6163 	SummaryField *field = summary_field_get (ebsql, field_id);
6164 
6165 	if (field &&
6166 	    (field->index & INDEX_FLAG (SORT_KEY)) != 0) {
6167 
6168 		g_string_append (string, "summary.");
6169 		g_string_append (string, field->dbname);
6170 		g_string_append (string, "_" EBSQL_SUFFIX_SORT_KEY " ");
6171 
6172 		ebsql_string_append_printf (string, "%c %Q", equality, value);
6173 
6174 	} else {
6175 		ebsql_string_append_printf (
6176 			string, "(%s %c %Q ",
6177 			EBSQL_VCARD_FRAGMENT (ebsql),
6178 			equality, value);
6179 
6180 		g_string_append (string, "COLLATE " EBSQL_COLLATE_PREFIX);
6181 		g_string_append (string, e_contact_field_name (field_id));
6182 		g_string_append_c (string, ')');
6183 	}
6184 }
6185 
6186 static gchar *
ebsql_cursor_constraints(EBookSqlite * ebsql,EbSqlCursor * cursor,CursorState * state,gboolean reverse,gboolean include_current_uid)6187 ebsql_cursor_constraints (EBookSqlite *ebsql,
6188                           EbSqlCursor *cursor,
6189                           CursorState *state,
6190                           gboolean reverse,
6191                           gboolean include_current_uid)
6192 {
6193 	GString *string;
6194 	gint i, j;
6195 
6196 	/* Example for:
6197 	 *    ORDER BY family_name ASC, given_name DESC
6198 	 *
6199 	 * Where current cursor values are:
6200 	 *    family_name = Jackson
6201 	 *    given_name  = Micheal
6202 	 *
6203 	 * With reverse = FALSE
6204 	 *
6205 	 *    (summary.family_name > 'Jackson') OR
6206 	 *    (summary.family_name = 'Jackson' AND summary.given_name < 'Micheal') OR
6207 	 *    (summary.family_name = 'Jackson' AND summary.given_name = 'Micheal' AND summary.uid > 'last-uid')
6208 	 *
6209 	 * With reverse = TRUE (needed for moving the cursor backwards through results)
6210 	 *
6211 	 *    (summary.family_name < 'Jackson') OR
6212 	 *    (summary.family_name = 'Jackson' AND summary.given_name > 'Micheal') OR
6213 	 *    (summary.family_name = 'Jackson' AND summary.given_name = 'Micheal' AND summary.uid < 'last-uid')
6214 	 *
6215 	 */
6216 	string = g_string_new (NULL);
6217 
6218 	for (i = 0; i <= cursor->n_sort_fields; i++) {
6219 
6220 		/* Break once we hit a NULL value */
6221 		if ((i < cursor->n_sort_fields && state->values[i] == NULL) ||
6222 		    (i == cursor->n_sort_fields && state->last_uid == NULL))
6223 			break;
6224 
6225 		/* Between each qualifier, add an 'OR' */
6226 		if (i > 0)
6227 			g_string_append (string, " OR ");
6228 
6229 		/* Begin qualifier */
6230 		g_string_append_c (string, '(');
6231 
6232 		/* Create the '=' statements leading up to the current tie breaker */
6233 		for (j = 0; j < i; j++) {
6234 			ebsql_cursor_format_equality (ebsql, string,
6235 						      cursor->sort_fields[j],
6236 						      state->values[j], '=');
6237 			g_string_append (string, " AND ");
6238 		}
6239 
6240 		if (i == cursor->n_sort_fields) {
6241 
6242 			/* The 'include_current_uid' clause is used for calculating
6243 			 * the current position of the cursor, inclusive of the
6244 			 * current position.
6245 			 */
6246 			if (include_current_uid)
6247 				g_string_append_c (string, '(');
6248 
6249 			/* Append the UID tie breaker */
6250 			ebsql_string_append_printf (
6251 				string,
6252 				"summary.uid %c %Q",
6253 				reverse ? '<' : '>',
6254 				state->last_uid);
6255 
6256 			if (include_current_uid)
6257 				ebsql_string_append_printf (
6258 					string,
6259 					" OR summary.uid = %Q)",
6260 					state->last_uid);
6261 
6262 		} else {
6263 
6264 			/* SPECIAL CASE: If we have a parially set cursor state, then we must
6265 			 * report next results that are inclusive of the final qualifier.
6266 			 *
6267 			 * This allows one to set the cursor with the family name set to 'J'
6268 			 * and include the results for contact's Mr & Miss 'J'.
6269 			 */
6270 			gboolean include_exact_match =
6271 				(reverse == FALSE &&
6272 				 ((i + 1 < cursor->n_sort_fields && state->values[i + 1] == NULL) ||
6273 				  (i + 1 == cursor->n_sort_fields && state->last_uid == NULL)));
6274 
6275 			if (include_exact_match)
6276 				g_string_append_c (string, '(');
6277 
6278 			/* Append the final qualifier for this field */
6279 			ebsql_cursor_format_equality (ebsql, string,
6280 						      cursor->sort_fields[i],
6281 						      state->values[i],
6282 						      GREATER_OR_LESS (cursor, i, reverse));
6283 
6284 			if (include_exact_match) {
6285 				g_string_append (string, " OR ");
6286 				ebsql_cursor_format_equality (ebsql, string,
6287 							      cursor->sort_fields[i],
6288 							      state->values[i], '=');
6289 				g_string_append_c (string, ')');
6290 			}
6291 		}
6292 
6293 		/* End qualifier */
6294 		g_string_append_c (string, ')');
6295 	}
6296 
6297 	return g_string_free (string, FALSE);
6298 }
6299 
6300 static gboolean
cursor_count_total_locked(EBookSqlite * ebsql,EbSqlCursor * cursor,gint * total,GError ** error)6301 cursor_count_total_locked (EBookSqlite *ebsql,
6302                            EbSqlCursor *cursor,
6303                            gint *total,
6304                            GError **error)
6305 {
6306 	GString *query;
6307 	gboolean success;
6308 
6309 	query = g_string_new (cursor->select_count);
6310 
6311 	/* Add the filter constraints (if any) */
6312 	if (cursor->query) {
6313 		g_string_append (query, " WHERE ");
6314 
6315 		g_string_append_c (query, '(');
6316 		g_string_append (query, cursor->query);
6317 		g_string_append_c (query, ')');
6318 	}
6319 
6320 	/* Execute the query */
6321 	success = ebsql_exec (ebsql, query->str, get_count_cb, total, NULL, error);
6322 
6323 	g_string_free (query, TRUE);
6324 
6325 	return success;
6326 }
6327 
6328 static gboolean
cursor_count_position_locked(EBookSqlite * ebsql,EbSqlCursor * cursor,gint * position,GError ** error)6329 cursor_count_position_locked (EBookSqlite *ebsql,
6330                               EbSqlCursor *cursor,
6331                               gint *position,
6332                               GError **error)
6333 {
6334 	GString *query;
6335 	gboolean success;
6336 
6337 	query = g_string_new (cursor->select_count);
6338 
6339 	/* Add the filter constraints (if any) */
6340 	if (cursor->query) {
6341 		g_string_append (query, " WHERE ");
6342 
6343 		g_string_append_c (query, '(');
6344 		g_string_append (query, cursor->query);
6345 		g_string_append_c (query, ')');
6346 	}
6347 
6348 	/* Add the cursor constraints (if any) */
6349 	if (cursor->state.values[0] != NULL) {
6350 		gchar *constraints = NULL;
6351 
6352 		if (!cursor->query)
6353 			g_string_append (query, " WHERE ");
6354 		else
6355 			g_string_append (query, " AND ");
6356 
6357 		/* Here we do a reverse query, we're looking for all the
6358 		 * results leading up to the current cursor value, including
6359 		 * the cursor value
6360 		 */
6361 		constraints = ebsql_cursor_constraints (
6362 			ebsql, cursor, &(cursor->state), TRUE, TRUE);
6363 
6364 		g_string_append_c (query, '(');
6365 		g_string_append (query, constraints);
6366 		g_string_append_c (query, ')');
6367 
6368 		g_free (constraints);
6369 	}
6370 
6371 	/* Execute the query */
6372 	success = ebsql_exec (ebsql, query->str, get_count_cb, position, NULL, error);
6373 
6374 	g_string_free (query, TRUE);
6375 
6376 	return success;
6377 }
6378 
6379 /**********************************************************
6380  *                     GObjectClass                       *
6381  **********************************************************/
6382 static void
e_book_sqlite_dispose(GObject * object)6383 e_book_sqlite_dispose (GObject *object)
6384 {
6385 	EBookSqlite *ebsql = E_BOOK_SQLITE (object);
6386 
6387 	ebsql_unregister_from_hash (ebsql);
6388 
6389 	/* Chain up to parent's dispose() method. */
6390 	G_OBJECT_CLASS (e_book_sqlite_parent_class)->dispose (object);
6391 }
6392 
6393 static void
e_book_sqlite_finalize(GObject * object)6394 e_book_sqlite_finalize (GObject *object)
6395 {
6396 	EBookSqlite *ebsql = E_BOOK_SQLITE (object);
6397 	EBookSqlitePrivate *priv = ebsql->priv;
6398 
6399 	summary_fields_array_free (
6400 		priv->summary_fields,
6401 		priv->n_summary_fields);
6402 
6403 	g_free (priv->folderid);
6404 	g_free (priv->path);
6405 	g_free (priv->locale);
6406 	g_free (priv->region_code);
6407 
6408 	if (priv->collator)
6409 		e_collator_unref (priv->collator);
6410 
6411 	g_clear_object (&priv->source);
6412 
6413 	g_mutex_clear (&priv->lock);
6414 	g_mutex_clear (&priv->updates_lock);
6415 
6416 	if (priv->multi_deletes)
6417 		g_hash_table_destroy (priv->multi_deletes);
6418 
6419 	if (priv->multi_inserts)
6420 		g_hash_table_destroy (priv->multi_inserts);
6421 
6422 	if (priv->user_data && priv->user_data_destroy)
6423 		priv->user_data_destroy (priv->user_data);
6424 
6425 	sqlite3_finalize (priv->insert_stmt);
6426 	sqlite3_finalize (priv->replace_stmt);
6427 	sqlite3_close (priv->db);
6428 
6429 	EBSQL_NOTE (REF_COUNTS, g_printerr ("EBookSqlite finalized\n"));
6430 
6431 	/* Chain up to parent's finalize() method. */
6432 	G_OBJECT_CLASS (e_book_sqlite_parent_class)->finalize (object);
6433 }
6434 
6435 static void
e_book_sqlite_constructed(GObject * object)6436 e_book_sqlite_constructed (GObject *object)
6437 {
6438 	/* Chain up to parent's constructed() method. */
6439 	G_OBJECT_CLASS (e_book_sqlite_parent_class)->constructed (object);
6440 
6441 	e_extensible_load_extensions (E_EXTENSIBLE (object));
6442 }
6443 
6444 static gboolean
ebsql_signals_accumulator(GSignalInvocationHint * ihint,GValue * return_accu,const GValue * handler_return,gpointer data)6445 ebsql_signals_accumulator (GSignalInvocationHint *ihint,
6446 			   GValue *return_accu,
6447 			   const GValue *handler_return,
6448 			   gpointer data)
6449 {
6450 	gboolean handler_result;
6451 
6452 	handler_result = g_value_get_boolean (handler_return);
6453 	g_value_set_boolean (return_accu, handler_result);
6454 
6455 	return handler_result;
6456 }
6457 
6458 static gboolean
ebsql_before_insert_contact_default(EBookSqlite * ebsql,gpointer db,EContact * contact,const gchar * extra,gboolean replace,GCancellable * cancellable,GError ** error)6459 ebsql_before_insert_contact_default (EBookSqlite *ebsql,
6460 				     gpointer db,
6461 				     EContact *contact,
6462 				     const gchar *extra,
6463 				     gboolean replace,
6464 				     GCancellable *cancellable,
6465 				     GError **error)
6466 {
6467 	return TRUE;
6468 }
6469 
6470 static gboolean
ebsql_before_remove_contact_default(EBookSqlite * ebsql,gpointer db,const gchar * contact_uid,GCancellable * cancellable,GError ** error)6471 ebsql_before_remove_contact_default (EBookSqlite *ebsql,
6472 				     gpointer db,
6473 				     const gchar *contact_uid,
6474 				     GCancellable *cancellable,
6475 				     GError **error)
6476 {
6477 	return TRUE;
6478 }
6479 
6480 static void
e_book_sqlite_class_init(EBookSqliteClass * class)6481 e_book_sqlite_class_init (EBookSqliteClass *class)
6482 {
6483 	GObjectClass *object_class;
6484 
6485 	object_class = G_OBJECT_CLASS (class);
6486 	object_class->dispose = e_book_sqlite_dispose;
6487 	object_class->finalize = e_book_sqlite_finalize;
6488 	object_class->constructed = e_book_sqlite_constructed;
6489 
6490 	class->before_insert_contact = ebsql_before_insert_contact_default;
6491 	class->before_remove_contact = ebsql_before_remove_contact_default;
6492 
6493 	/* Parse the EBSQL_DEBUG environment variable */
6494 	ebsql_init_debug ();
6495 
6496 	signals[BEFORE_INSERT_CONTACT] = g_signal_new (
6497 		"before-insert-contact",
6498 		G_OBJECT_CLASS_TYPE (class),
6499 		G_SIGNAL_RUN_LAST,
6500 		G_STRUCT_OFFSET (EBookSqliteClass, before_insert_contact),
6501 		ebsql_signals_accumulator,
6502 		NULL,
6503 		g_cclosure_marshal_generic,
6504 		G_TYPE_BOOLEAN, 6,
6505 		G_TYPE_POINTER,
6506 		E_TYPE_CONTACT,
6507 		G_TYPE_STRING,
6508 		G_TYPE_BOOLEAN,
6509 		G_TYPE_OBJECT,
6510 		G_TYPE_POINTER);
6511 
6512 	signals[BEFORE_REMOVE_CONTACT] = g_signal_new (
6513 		"before-remove-contact",
6514 		G_OBJECT_CLASS_TYPE (class),
6515 		G_SIGNAL_RUN_LAST,
6516 		G_STRUCT_OFFSET (EBookSqliteClass, before_remove_contact),
6517 		ebsql_signals_accumulator,
6518 		NULL,
6519 		g_cclosure_marshal_generic,
6520 		G_TYPE_BOOLEAN, 4,
6521 		G_TYPE_POINTER,
6522 		G_TYPE_STRING,
6523 		G_TYPE_CANCELLABLE,
6524 		G_TYPE_POINTER);
6525 }
6526 
6527 static void
e_book_sqlite_init(EBookSqlite * ebsql)6528 e_book_sqlite_init (EBookSqlite *ebsql)
6529 {
6530 	ebsql->priv = e_book_sqlite_get_instance_private (ebsql);
6531 
6532 	g_mutex_init (&ebsql->priv->lock);
6533 	g_mutex_init (&ebsql->priv->updates_lock);
6534 }
6535 
6536 /**********************************************************
6537  *                          API                           *
6538  **********************************************************/
6539 static EBookSqlite *
ebsql_new_default(const gchar * path,ESource * source,EbSqlVCardCallback vcard_callback,EbSqlChangeCallback change_callback,gpointer user_data,GDestroyNotify user_data_destroy,GCancellable * cancellable,GError ** error)6540 ebsql_new_default (const gchar *path,
6541 		   ESource *source,
6542                    EbSqlVCardCallback vcard_callback,
6543                    EbSqlChangeCallback change_callback,
6544                    gpointer user_data,
6545                    GDestroyNotify user_data_destroy,
6546                    GCancellable *cancellable,
6547                    GError **error)
6548 {
6549 	EBookSqlite *ebsql;
6550 	GArray *summary_fields;
6551 	gint i;
6552 
6553 	/* Create the default summary structs */
6554 	summary_fields = g_array_new (FALSE, FALSE, sizeof (SummaryField));
6555 	for (i = 0; i < G_N_ELEMENTS (default_summary_fields); i++)
6556 		summary_field_append (summary_fields, DEFAULT_FOLDER_ID, default_summary_fields[i], NULL);
6557 
6558 	/* Add the default index flags */
6559 	summary_fields_add_indexes (
6560 		summary_fields,
6561 		default_indexed_fields,
6562 		default_index_types,
6563 		G_N_ELEMENTS (default_indexed_fields));
6564 
6565 	ebsql = ebsql_new_internal (
6566 		path, source,
6567 		vcard_callback, change_callback,
6568 		user_data, user_data_destroy,
6569 		(SummaryField *) summary_fields->data,
6570 		summary_fields->len,
6571 		cancellable, error);
6572 
6573 	g_array_free (summary_fields, FALSE);
6574 
6575 	return ebsql;
6576 }
6577 
6578 /**
6579  * e_book_sqlite_new:
6580  * @path: location to load or create the new database
6581  * @source: (nullable): an optional #ESource, associated with the #EBookSqlite, or %NULL
6582  * @cancellable: A #GCancellable
6583  * @error: A location to store any error that may have occurred.
6584  *
6585  * Creates a new #EBookSqlite with the default summary configuration.
6586  *
6587  * Aside from the manditory fields %E_CONTACT_UID, %E_CONTACT_REV,
6588  * the default configuration stores the following fields for quick
6589  * performance of searches: %E_CONTACT_FILE_AS, %E_CONTACT_NICKNAME,
6590  * %E_CONTACT_FULL_NAME, %E_CONTACT_GIVEN_NAME, %E_CONTACT_FAMILY_NAME,
6591  * %E_CONTACT_EMAIL, %E_CONTACT_TEL, %E_CONTACT_IS_LIST, %E_CONTACT_LIST_SHOW_ADDRESSES,
6592  * and %E_CONTACT_WANTS_HTML.
6593  *
6594  * The fields %E_CONTACT_FULL_NAME and %E_CONTACT_EMAIL are configured
6595  * to respond extra quickly with the %E_BOOK_INDEX_PREFIX index flag.
6596  *
6597  * The fields %E_CONTACT_FILE_AS, %E_CONTACT_FAMILY_NAME and
6598  * %E_CONTACT_GIVEN_NAME are configured to perform well with
6599  * the #EbSqlCursor interface, using the %E_BOOK_INDEX_SORT_KEY
6600  * index flag.
6601  *
6602  * Returns: (transfer full): A reference to an #EBookSqlite
6603  *
6604  * Since: 3.12
6605  **/
6606 EBookSqlite *
e_book_sqlite_new(const gchar * path,ESource * source,GCancellable * cancellable,GError ** error)6607 e_book_sqlite_new (const gchar *path,
6608 		   ESource *source,
6609                    GCancellable *cancellable,
6610                    GError **error)
6611 {
6612 	g_return_val_if_fail (path && path[0], NULL);
6613 
6614 	return ebsql_new_default (path, source, NULL, NULL, NULL, NULL, cancellable, error);
6615 }
6616 
6617 /**
6618  * e_book_sqlite_new_full:
6619  * @path: location to load or create the new database
6620  * @source: an optional #ESource, associated with the #EBookSqlite, or %NULL
6621  * @setup: (nullable): an #ESourceBackendSummarySetup describing how the summary should be setup, or %NULL to use the default
6622  * @vcard_callback: (nullable) (scope async) (closure user_data): A function to resolve vcards
6623  * @change_callback: (nullable) (scope async) (closure user_data): A function to catch notifications of vcard changes
6624  * @user_data: (nullable): callback user data
6625  * @user_data_destroy: (nullable): A function to free @user_data automatically when the created #EBookSqlite is destroyed.
6626  * @cancellable: A #GCancellable
6627  * @error: A location to store any error that may have occurred.
6628  *
6629  * Opens or creates a new addressbook at @path.
6630  *
6631  * Like e_book_sqlite_new(), but allows configuration of which contact fields
6632  * will be stored for quick reference in the summary. The configuration indicated by
6633  * @setup will only be taken into account when initially creating the underlying table,
6634  * further configurations will be ignored.
6635  *
6636  * The fields %E_CONTACT_UID and %E_CONTACT_REV are not optional,
6637  * they will be stored in the summary regardless of this function's parameters.
6638  * Only #EContactFields with the type #G_TYPE_STRING, #G_TYPE_BOOLEAN or
6639  * #E_TYPE_CONTACT_ATTR_LIST are currently supported.
6640  *
6641  * If @vcard_callback is specified, then vcards will not be stored by functions
6642  * such as e_book_sqlitedb_add_contact(). Instead @vcard_callback will be invoked
6643  * at any time the created #EBookSqlite requires a vcard, either as a fallback
6644  * for querying search expressions which cannot be satisfied with the summary
6645  * fields, or when reporting results from searches.
6646  *
6647  * If any error occurs and %NULL is returned, then the passed @user_data will
6648  * be automatically freed using the @user_data_destroy function, if specified.
6649  *
6650  * It is recommended to store all contact vcards in the #EBookSqlite addressbook
6651  * if at all possible, however in some cases the vcards must be stored in some
6652  * other storage.
6653  *
6654  * Returns: (transfer full): The newly created #EBookSqlite, or %NULL if opening or creating the addressbook failed.
6655  *
6656  * Since: 3.12
6657  **/
6658 EBookSqlite *
e_book_sqlite_new_full(const gchar * path,ESource * source,ESourceBackendSummarySetup * setup,EbSqlVCardCallback vcard_callback,EbSqlChangeCallback change_callback,gpointer user_data,GDestroyNotify user_data_destroy,GCancellable * cancellable,GError ** error)6659 e_book_sqlite_new_full (const gchar *path,
6660 			ESource *source,
6661                         ESourceBackendSummarySetup *setup,
6662                         EbSqlVCardCallback vcard_callback,
6663                         EbSqlChangeCallback change_callback,
6664                         gpointer user_data,
6665                         GDestroyNotify user_data_destroy,
6666                         GCancellable *cancellable,
6667                         GError **error)
6668 {
6669 	EBookSqlite *ebsql = NULL;
6670 	EContactField *fields;
6671 	EContactField *indexed_fields;
6672 	EBookIndexType *index_types = NULL;
6673 	gboolean had_error = FALSE;
6674 	GArray *summary_fields;
6675 	gint n_fields = 0, n_indexed_fields = 0, i;
6676 
6677 	g_return_val_if_fail (path && path[0], NULL);
6678 	g_return_val_if_fail (setup == NULL || E_IS_SOURCE_BACKEND_SUMMARY_SETUP (setup), NULL);
6679 
6680 	if (!setup)
6681 		return ebsql_new_default (
6682 			path,
6683 			source,
6684 			vcard_callback,
6685 			change_callback,
6686 			user_data,
6687 			user_data_destroy,
6688 			cancellable, error);
6689 
6690 	fields = e_source_backend_summary_setup_get_summary_fields (setup, &n_fields);
6691 	indexed_fields = e_source_backend_summary_setup_get_indexed_fields (setup, &index_types, &n_indexed_fields);
6692 
6693 	/* No specified summary fields indicates the default summary configuration should be used */
6694 	if (n_fields <= 0 || n_fields >= EBSQL_MAX_SUMMARY_FIELDS) {
6695 
6696 		if (n_fields)
6697 			g_warning (
6698 				"EBookSqlite refused to create addressbook with over %d summary fields",
6699 				EBSQL_MAX_SUMMARY_FIELDS);
6700 
6701 		ebsql = ebsql_new_default (
6702 			path,
6703 			source,
6704 			vcard_callback,
6705 			change_callback,
6706 			user_data,
6707 			user_data_destroy,
6708 			cancellable, error);
6709 		g_free (fields);
6710 		g_free (index_types);
6711 		g_free (indexed_fields);
6712 
6713 		return ebsql;
6714 	}
6715 
6716 	summary_fields = g_array_new (FALSE, FALSE, sizeof (SummaryField));
6717 
6718 	/* Ensure the non-optional fields first */
6719 	summary_field_append (summary_fields, DEFAULT_FOLDER_ID, E_CONTACT_UID, error);
6720 	summary_field_append (summary_fields, DEFAULT_FOLDER_ID, E_CONTACT_REV, error);
6721 
6722 	for (i = 0; i < n_fields; i++) {
6723 		if (!summary_field_append (summary_fields, DEFAULT_FOLDER_ID, fields[i], error)) {
6724 			had_error = TRUE;
6725 			break;
6726 		}
6727 	}
6728 
6729 	if (had_error) {
6730 		gint n_sfields;
6731 		SummaryField *sfields;
6732 
6733 		/* Properly free the array */
6734 		n_sfields = summary_fields->len;
6735 		sfields = (SummaryField *) g_array_free (summary_fields, FALSE);
6736 		summary_fields_array_free (sfields, n_sfields);
6737 
6738 		g_free (fields);
6739 		g_free (index_types);
6740 		g_free (indexed_fields);
6741 
6742 		if (user_data && user_data_destroy)
6743 			user_data_destroy (user_data);
6744 
6745 		return NULL;
6746 	}
6747 
6748 	/* Add the 'indexed' flag to the SummaryField structs */
6749 	summary_fields_add_indexes (
6750 		summary_fields, indexed_fields, index_types, n_indexed_fields);
6751 
6752 	ebsql = ebsql_new_internal (
6753 		path, source,
6754 		vcard_callback, change_callback,
6755 		user_data, user_data_destroy,
6756 		(SummaryField *) summary_fields->data,
6757 		summary_fields->len,
6758 		cancellable, error);
6759 
6760 	g_free (fields);
6761 	g_free (index_types);
6762 	g_free (indexed_fields);
6763 	g_array_free (summary_fields, FALSE);
6764 
6765 	return ebsql;
6766 }
6767 
6768 /**
6769  * e_book_sqlite_lock:
6770  * @ebsql: An #EBookSqlite
6771  * @lock_type: The #EbSqlLockType to acquire
6772  * @cancellable: A #GCancellable
6773  * @error: A location to store any error that may have occurred.
6774  *
6775  * Obtains an exclusive lock on @ebsql and starts a transaction.
6776  *
6777  * This should be called if you need to access @ebsql multiple times while
6778  * ensuring an atomic transaction. End this transaction with e_book_sqlite_unlock().
6779  *
6780  * If @cancellable is specified, then @ebsql will retain a reference to it until
6781  * e_book_sqlite_unlock() is called. Any accesses to @ebsql with the lock held
6782  * are expected to have the same @cancellable specified, or %NULL.
6783  *
6784  * <note><para>Aside from ensuring atomicity of transactions, this function will hold a mutex
6785  * which will cause further calls to e_book_sqlite_lock() to block. If you are accessing
6786  * @ebsql from multiple threads, then any interactions with @ebsql should be nested in calls
6787  * to e_book_sqlite_lock() and e_book_sqlite_unlock().</para></note>
6788  *
6789  * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
6790  *
6791  * Since: 3.12
6792  **/
6793 gboolean
e_book_sqlite_lock(EBookSqlite * ebsql,EbSqlLockType lock_type,GCancellable * cancellable,GError ** error)6794 e_book_sqlite_lock (EBookSqlite *ebsql,
6795                     EbSqlLockType lock_type,
6796                     GCancellable *cancellable,
6797                     GError **error)
6798 {
6799 	gboolean success;
6800 
6801 	g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
6802 
6803 	EBSQL_LOCK_MUTEX (&ebsql->priv->updates_lock);
6804 
6805 	/* Here, after obtaining the outer facing transaction lock, we need
6806 	 * to assert that there is no cancellable already set */
6807 	if (ebsql->priv->cancel != NULL) {
6808 		/* This should never happen, if it does it's a bug
6809 		 * in this code, not the calling code
6810 		 */
6811 		g_warn_if_reached ();
6812 		EBSQL_UNLOCK_MUTEX (&ebsql->priv->updates_lock);
6813 		return FALSE;
6814 	}
6815 
6816 	EBSQL_LOCK_MUTEX (&ebsql->priv->lock);
6817 
6818 	/* Here, after obtaining the regular lock, we need to assert that we are
6819 	 * the toplevel transaction */
6820 	if (ebsql->priv->in_transaction != 0) {
6821 		g_warn_if_reached ();
6822 		EBSQL_LOCK_MUTEX (&ebsql->priv->lock);
6823 		EBSQL_UNLOCK_MUTEX (&ebsql->priv->updates_lock);
6824 		return FALSE;
6825 	}
6826 
6827 	success = ebsql_start_transaction (ebsql, lock_type, cancellable, error);
6828 	EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
6829 
6830 	/* If we failed to start the transaction, we don't hold the lock */
6831 	if (!success)
6832 		EBSQL_UNLOCK_MUTEX (&ebsql->priv->updates_lock);
6833 
6834 	return success;
6835 }
6836 
6837 /**
6838  * e_book_sqlite_unlock:
6839  * @ebsql: An #EBookSqlite
6840  * @action: Which #EbSqlUnlockAction to take while unlocking
6841  * @error: A location to store any error that may have occurred.
6842  *
6843  * Releases an exclusive on @ebsql and finishes a transaction previously
6844  * started with e_book_sqlite_lock_updates().
6845  *
6846  * <note><para>If this fails, the lock on @ebsql is still released and @error will
6847  * be set to indicate why the transaction or rollback failed.</para></note>
6848  *
6849  * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
6850  *
6851  * Since: 3.12
6852  **/
6853 gboolean
e_book_sqlite_unlock(EBookSqlite * ebsql,EbSqlUnlockAction action,GError ** error)6854 e_book_sqlite_unlock (EBookSqlite *ebsql,
6855                       EbSqlUnlockAction action,
6856                       GError **error)
6857 {
6858 	gboolean success = FALSE;
6859 
6860 	g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
6861 
6862 	EBSQL_LOCK_MUTEX (&ebsql->priv->lock);
6863 
6864 	switch (action) {
6865 	case EBSQL_UNLOCK_NONE:
6866 	case EBSQL_UNLOCK_COMMIT:
6867 		success = ebsql_commit_transaction (ebsql, error);
6868 		break;
6869 	case EBSQL_UNLOCK_ROLLBACK:
6870 		success = ebsql_rollback_transaction (ebsql, error);
6871 		break;
6872 	}
6873 
6874 	EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
6875 
6876 	EBSQL_UNLOCK_MUTEX (&ebsql->priv->updates_lock);
6877 
6878 	return success;
6879 }
6880 
6881 /**
6882  * e_book_sqlite_ref_collator:
6883  * @ebsql: An #EBookSqlite
6884  *
6885  * References the currently active #ECollator for @ebsql,
6886  * use e_collator_unref() when finished using the returned collator.
6887  *
6888  * Note that the active collator will change with the active locale setting.
6889  *
6890  * Returns: (transfer full): A reference to the active collator.
6891  *
6892  * Since: 3.12
6893  */
6894 ECollator *
e_book_sqlite_ref_collator(EBookSqlite * ebsql)6895 e_book_sqlite_ref_collator (EBookSqlite *ebsql)
6896 {
6897 	g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), NULL);
6898 
6899 	return e_collator_ref (ebsql->priv->collator);
6900 }
6901 
6902 /**
6903  * e_book_sqlite_ref_source:
6904  * @ebsql: An #EBookSqlite
6905  *
6906  * References the #ESource to which @ebsql is paired,
6907  * use g_object_unref() when finished using the source.
6908  * It can be %NULL in some cases, like when running tests.
6909  *
6910  * Returns: (transfer full): A reference to the #ESource to which @ebsql
6911  * is paired, or %NULL.
6912  *
6913  * Since: 3.16
6914 */
6915 ESource *
e_book_sqlite_ref_source(EBookSqlite * ebsql)6916 e_book_sqlite_ref_source (EBookSqlite *ebsql)
6917 {
6918 	g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), NULL);
6919 
6920 	if (!ebsql->priv->source)
6921 		return NULL;
6922 
6923 	return g_object_ref (ebsql->priv->source);
6924 }
6925 
6926 /**
6927  * e_book_sqlitedb_add_contact:
6928  * @ebsql: An #EBookSqlite
6929  * @contact: EContact to be added
6930  * @extra: Extra data to store in association with this contact
6931  * @replace: Whether this contact should replace another contact with the same UID.
6932  * @cancellable: A #GCancellable
6933  * @error: A location to store any error that may have occurred.
6934  *
6935  * This is a convenience wrapper for e_book_sqlite_add_contacts(),
6936  * which is the preferred means to add or modify multiple contacts when possible.
6937  *
6938  * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
6939  *
6940  * Since: 3.12
6941  **/
6942 gboolean
e_book_sqlite_add_contact(EBookSqlite * ebsql,EContact * contact,const gchar * extra,gboolean replace,GCancellable * cancellable,GError ** error)6943 e_book_sqlite_add_contact (EBookSqlite *ebsql,
6944                            EContact *contact,
6945                            const gchar *extra,
6946                            gboolean replace,
6947                            GCancellable *cancellable,
6948                            GError **error)
6949 {
6950 	GSList l;
6951 	GSList el;
6952 
6953 	g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
6954 	g_return_val_if_fail (E_IS_CONTACT (contact), FALSE);
6955 
6956 	l.data = contact;
6957 	l.next = NULL;
6958 
6959 	el.data = (gpointer) extra;
6960 	el.next = NULL;
6961 
6962 	return e_book_sqlite_add_contacts (ebsql, &l, &el, replace, cancellable, error);
6963 }
6964 
6965 /**
6966  * e_book_sqlite_add_contacts:
6967  * @ebsql: An #EBookSqlite
6968  * @contacts: (element-type EContact): A list of contacts to add to @ebsql
6969  * @extra: (nullable) (element-type utf8): A list of extra data to store in association with this contact
6970  * @replace: Whether this contact should replace another contact with the same UID.
6971  * @cancellable: A #GCancellable
6972  * @error: A location to store any error that may have occurred.
6973  *
6974  * Adds or replaces contacts in @ebsql. If @replace_existing is specified then existing
6975  * contacts with the same UID will be replaced, otherwise adding an existing contact
6976  * will return an error.
6977  *
6978  * If @extra is specified, it must have an equal length as the @contacts list. Each element
6979  * from the @extra list will be stored in association with it's corresponding contact
6980  * in the @contacts list.
6981  *
6982  * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
6983  *
6984  * Since: 3.12
6985  **/
6986 gboolean
e_book_sqlite_add_contacts(EBookSqlite * ebsql,GSList * contacts,GSList * extra,gboolean replace,GCancellable * cancellable,GError ** error)6987 e_book_sqlite_add_contacts (EBookSqlite *ebsql,
6988                             GSList *contacts,
6989                             GSList *extra,
6990                             gboolean replace,
6991                             GCancellable *cancellable,
6992                             GError **error)
6993 {
6994 	GSList *l, *ll;
6995 	gboolean success = TRUE;
6996 
6997 	g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
6998 	g_return_val_if_fail (contacts != NULL, FALSE);
6999 	g_return_val_if_fail (extra == NULL ||
7000 			      g_slist_length (extra) == g_slist_length (contacts), FALSE);
7001 
7002 	EBSQL_LOCK_OR_RETURN (ebsql, cancellable, FALSE);
7003 
7004 	if (!ebsql_start_transaction (ebsql, EBSQL_LOCK_WRITE, cancellable, error)) {
7005 		EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
7006 		return FALSE;
7007 	}
7008 
7009 	for (l = contacts, ll = extra;
7010 	     success && l != NULL;
7011 	     l = l->next, ll = ll ? ll->next : NULL) {
7012 		EContact *contact = (EContact *) l->data;
7013 		const gchar *extra_data = NULL;
7014 
7015 		if (ll)
7016 			extra_data = (const gchar *) ll->data;
7017 
7018 		g_signal_emit (ebsql,
7019 			       signals[BEFORE_INSERT_CONTACT],
7020 			       0,
7021 			       ebsql->priv->db,
7022 			       contact, extra_data,
7023 			       replace,
7024 			       cancellable, error,
7025 			       &success);
7026 		if (!success)
7027 			break;
7028 
7029 		success = ebsql_insert_contact (
7030 			ebsql,
7031 			EBSQL_CHANGE_CONTACT_ADDED,
7032 			contact, NULL, extra_data,
7033 			replace, error);
7034 	}
7035 
7036 	if (success)
7037 		success = ebsql_commit_transaction (ebsql, error);
7038 	else
7039 		/* The GError is already set. */
7040 		ebsql_rollback_transaction (ebsql, NULL);
7041 
7042 	EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
7043 
7044 	return success;
7045 }
7046 
7047 /**
7048  * e_book_sqlite_remove_contact:
7049  * @ebsql: An #EBookSqlite
7050  * @uid: the uid of the contact to remove
7051  * @cancellable: A #GCancellable
7052  * @error: A location to store any error that may have occurred.
7053  *
7054  * Removes the contact indicated by @uid from @ebsql.
7055  *
7056  * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
7057  *
7058  * Since: 3.12
7059  **/
7060 gboolean
e_book_sqlite_remove_contact(EBookSqlite * ebsql,const gchar * uid,GCancellable * cancellable,GError ** error)7061 e_book_sqlite_remove_contact (EBookSqlite *ebsql,
7062                               const gchar *uid,
7063                               GCancellable *cancellable,
7064                               GError **error)
7065 {
7066 	GSList l;
7067 
7068 	g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
7069 	g_return_val_if_fail (uid != NULL, FALSE);
7070 
7071 	l.data = (gchar *) uid; /* Won't modify it, I promise :) */
7072 	l.next = NULL;
7073 
7074 	return e_book_sqlite_remove_contacts (
7075 		ebsql, &l, cancellable, error);
7076 }
7077 
7078 static gchar *
generate_delete_stmt(const gchar * table,GSList * uids)7079 generate_delete_stmt (const gchar *table,
7080                       GSList *uids)
7081 {
7082 	GString *str = g_string_new (NULL);
7083 	GSList  *l;
7084 
7085 	ebsql_string_append_printf (str, "DELETE FROM %Q WHERE uid IN (", table);
7086 
7087 	for (l = uids; l; l = l->next) {
7088 		const gchar *uid = (const gchar *) l->data;
7089 
7090 		/* First uid with no comma */
7091 		if (l != uids)
7092 			g_string_append_printf (str, ", ");
7093 
7094 		ebsql_string_append_printf (str, "%Q", uid);
7095 	}
7096 
7097 	g_string_append_c (str, ')');
7098 
7099 	return g_string_free (str, FALSE);
7100 }
7101 
7102 /**
7103  * e_book_sqlite_remove_contacts:
7104  * @ebsql: An #EBookSqlite
7105  * @uids: (element-type utf8): a #GSList of uids indicating which contacts to remove
7106  * @cancellable: A #GCancellable
7107  * @error: A location to store any error that may have occurred.
7108  *
7109  * Removes the contacts indicated by @uids from @ebsql.
7110  *
7111  * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
7112  *
7113  * Since: 3.12
7114  **/
7115 gboolean
e_book_sqlite_remove_contacts(EBookSqlite * ebsql,GSList * uids,GCancellable * cancellable,GError ** error)7116 e_book_sqlite_remove_contacts (EBookSqlite *ebsql,
7117                                GSList *uids,
7118                                GCancellable *cancellable,
7119                                GError **error)
7120 {
7121 	gboolean success = TRUE;
7122 	gint i;
7123 	gchar *stmt;
7124 	const gchar *contact_uid;
7125 	GSList *l = NULL;
7126 
7127 	g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
7128 	g_return_val_if_fail (uids != NULL, FALSE);
7129 
7130 	EBSQL_LOCK_OR_RETURN (ebsql, cancellable, FALSE);
7131 
7132 	if (!ebsql_start_transaction (ebsql, EBSQL_LOCK_WRITE, cancellable, error)) {
7133 		EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
7134 		return FALSE;
7135 	}
7136 
7137 	for (l = uids; success && l; l = l->next) {
7138 		contact_uid = (const gchar *) l->data;
7139 		g_signal_emit (ebsql,
7140 			       signals[BEFORE_REMOVE_CONTACT],
7141 			       0,
7142 			       ebsql->priv->db,
7143 			       contact_uid,
7144 			       cancellable, error,
7145 			       &success);
7146 	}
7147 
7148 	/* Delete data from the auxiliary tables first */
7149 	for (i = 0; success && i < ebsql->priv->n_summary_fields; i++) {
7150 		SummaryField *field = &(ebsql->priv->summary_fields[i]);
7151 
7152 		if (field->type != E_TYPE_CONTACT_ATTR_LIST)
7153 			continue;
7154 
7155 		stmt = generate_delete_stmt (field->aux_table, uids);
7156 		success = ebsql_exec (ebsql, stmt, NULL, NULL, NULL, error);
7157 		g_free (stmt);
7158 	}
7159 
7160 	/* Now delete the entry from the main contacts */
7161 	if (success) {
7162 		stmt = generate_delete_stmt (ebsql->priv->folderid, uids);
7163 		success = ebsql_exec (ebsql, stmt, NULL, NULL, NULL, error);
7164 		g_free (stmt);
7165 	}
7166 
7167 	if (success)
7168 		success = ebsql_commit_transaction (ebsql, error);
7169 	else
7170 		/* The GError is already set. */
7171 		ebsql_rollback_transaction (ebsql, NULL);
7172 
7173 	EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
7174 
7175 	return success;
7176 }
7177 
7178 /**
7179  * e_book_sqlite_has_contact:
7180  * @ebsql: An #EBookSqlite
7181  * @uid: The uid of the contact to check for
7182  * @exists: (out): Return location to store whether the contact exists.
7183  * @error: A location to store any error that may have occurred.
7184  *
7185  * Checks if a contact bearing the UID indicated by @uid is stored in @ebsql.
7186  *
7187  * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
7188  *
7189  * Since: 3.12
7190  **/
7191 gboolean
e_book_sqlite_has_contact(EBookSqlite * ebsql,const gchar * uid,gboolean * exists,GError ** error)7192 e_book_sqlite_has_contact (EBookSqlite *ebsql,
7193                            const gchar *uid,
7194                            gboolean *exists,
7195                            GError **error)
7196 {
7197 	gboolean local_exists = FALSE;
7198 	gboolean success;
7199 
7200 	g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
7201 	g_return_val_if_fail (uid != NULL, FALSE);
7202 	g_return_val_if_fail (exists != NULL, FALSE);
7203 
7204 	EBSQL_LOCK_MUTEX (&ebsql->priv->lock);
7205 	success = ebsql_exec_printf (
7206 		ebsql,
7207 		"SELECT uid FROM %Q WHERE uid = %Q",
7208 		get_exists_cb, &local_exists, NULL, error,
7209 		ebsql->priv->folderid, uid);
7210 	EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
7211 
7212 	*exists = local_exists;
7213 
7214 	return success;
7215 }
7216 
7217 /**
7218  * e_book_sqlite_get_contact:
7219  * @ebsql: An #EBookSqlite
7220  * @uid: The uid of the contact to fetch
7221  * @meta_contact: Whether an entire contact is desired, or only the metadata
7222  * @ret_contact: (out): Return location to store the fetched contact
7223  * @error: A location to store any error that may have occurred.
7224  *
7225  * Fetch the #EContact specified by @uid in @ebsql.
7226  *
7227  * If @meta_contact is specified, then a shallow #EContact will be created
7228  * holding only the %E_CONTACT_UID and %E_CONTACT_REV fields.
7229  *
7230  * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
7231  *
7232  * Since: 3.12
7233  **/
7234 gboolean
e_book_sqlite_get_contact(EBookSqlite * ebsql,const gchar * uid,gboolean meta_contact,EContact ** ret_contact,GError ** error)7235 e_book_sqlite_get_contact (EBookSqlite *ebsql,
7236                            const gchar *uid,
7237                            gboolean meta_contact,
7238                            EContact **ret_contact,
7239                            GError **error)
7240 {
7241 	gboolean success = FALSE;
7242 	gchar *vcard = NULL;
7243 
7244 	g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
7245 	g_return_val_if_fail (uid != NULL, FALSE);
7246 	g_return_val_if_fail (ret_contact != NULL && *ret_contact == NULL, FALSE);
7247 
7248 	success = e_book_sqlite_get_vcard (
7249 		ebsql, uid, meta_contact, &vcard, error);
7250 
7251 	if (success && vcard) {
7252 		*ret_contact = e_contact_new_from_vcard_with_uid (vcard, uid);
7253 		g_free (vcard);
7254 	}
7255 
7256 	return success;
7257 }
7258 
7259 /**
7260  * ebsql_get_contact_unlocked:
7261  * @ebsql: An #EBookSqlite
7262  * @uid: The uid of the contact to fetch
7263  * @meta_contact: Whether an entire contact is desired, or only the metadata
7264  * @contact: (out): Return location to store the fetched contact
7265  * @error: A location to store any error that may have occurred.
7266  *
7267  * Fetch the #EContact specified by @uid in @ebsql without locking internal mutex.
7268  *
7269  * If @meta_contact is specified, then a shallow #EContact will be created
7270  * holding only the %E_CONTACT_UID and %E_CONTACT_REV fields.
7271  *
7272  * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
7273  *
7274  * Since: 3.16
7275  **/
7276 gboolean
ebsql_get_contact_unlocked(EBookSqlite * ebsql,const gchar * uid,gboolean meta_contact,EContact ** contact,GError ** error)7277 ebsql_get_contact_unlocked (EBookSqlite *ebsql,
7278 			    const gchar *uid,
7279 			    gboolean meta_contact,
7280 			    EContact **contact,
7281 			    GError **error)
7282 {
7283 	gboolean success = FALSE;
7284 	gchar *vcard = NULL;
7285 
7286 	g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
7287 	g_return_val_if_fail (uid != NULL, FALSE);
7288 	g_return_val_if_fail (contact != NULL && *contact == NULL, FALSE);
7289 
7290 	success = ebsql_get_vcard_unlocked (ebsql,
7291 					    uid,
7292 					    meta_contact,
7293 					    &vcard,
7294 					    error);
7295 
7296 	if (success && vcard) {
7297 		*contact = e_contact_new_from_vcard_with_uid (vcard, uid);
7298 		g_free (vcard);
7299 	}
7300 
7301 	return success;
7302 }
7303 
7304 /**
7305  * e_book_sqlite_get_vcard:
7306  * @ebsql: An #EBookSqlite
7307  * @uid: The uid of the contact to fetch
7308  * @meta_contact: Whether an entire contact is desired, or only the metadata
7309  * @ret_vcard: (out): Return location to store the fetched vcard string
7310  * @error: A location to store any error that may have occurred.
7311  *
7312  * Fetch a vcard string for @uid in @ebsql.
7313  *
7314  * If @meta_contact is specified, then a shallow vcard representation will be
7315  * created holding only the %E_CONTACT_UID and %E_CONTACT_REV fields.
7316  *
7317  * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
7318  *
7319  * Since: 3.12
7320  **/
7321 gboolean
e_book_sqlite_get_vcard(EBookSqlite * ebsql,const gchar * uid,gboolean meta_contact,gchar ** ret_vcard,GError ** error)7322 e_book_sqlite_get_vcard (EBookSqlite *ebsql,
7323                          const gchar *uid,
7324                          gboolean meta_contact,
7325                          gchar **ret_vcard,
7326                          GError **error)
7327 {
7328 	gboolean success = FALSE;
7329 	gchar *vcard = NULL;
7330 
7331 	g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
7332 	g_return_val_if_fail (uid != NULL, FALSE);
7333 	g_return_val_if_fail (ret_vcard != NULL && *ret_vcard == NULL, FALSE);
7334 
7335 	EBSQL_LOCK_MUTEX (&ebsql->priv->lock);
7336 
7337 	/* Try constructing contacts from only UID/REV first if that's requested */
7338 	if (meta_contact) {
7339 		GSList *vcards = NULL;
7340 
7341 		success = ebsql_exec_printf (
7342 			ebsql, "SELECT summary.uid, summary.Rev FROM %Q AS summary WHERE uid = %Q",
7343 			collect_lean_results_cb, &vcards, NULL, error,
7344 			ebsql->priv->folderid, uid);
7345 
7346 		if (vcards) {
7347 			EbSqlSearchData *search_data = (EbSqlSearchData *) vcards->data;
7348 
7349 			vcard = search_data->vcard;
7350 			search_data->vcard = NULL;
7351 
7352 			g_slist_free_full (vcards, (GDestroyNotify) e_book_sqlite_search_data_free);
7353 			vcards = NULL;
7354 		}
7355 
7356 	} else {
7357 		success = ebsql_exec_printf (
7358 			ebsql, "SELECT %s FROM %Q AS summary WHERE summary.uid = %Q",
7359 			get_string_cb, &vcard, NULL, error,
7360 			EBSQL_VCARD_FRAGMENT (ebsql), ebsql->priv->folderid, uid);
7361 	}
7362 
7363 	EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
7364 
7365 	*ret_vcard = vcard;
7366 
7367 	if (success && !vcard) {
7368 		EBSQL_SET_ERROR (
7369 			error,
7370 			E_BOOK_SQLITE_ERROR_CONTACT_NOT_FOUND,
7371 			_("Contact “%s” not found"), uid);
7372 		success = FALSE;
7373 	}
7374 
7375 	return success;
7376 }
7377 
7378 /**
7379  * ebsql_get_vcard_unlocked:
7380  * @ebsql: An #EBookSqlite
7381  * @uid: The uid of the contact to fetch
7382  * @meta_contact: Whether an entire contact is desired, or only the metadata
7383  * @ret_vcard: (out): Return location to store the fetched vcard string
7384  * @error: A location to store any error that may have occurred.
7385  *
7386  * Fetch a vcard string for @uid in @ebsql without locking internal mutex.
7387  *
7388  * If @meta_contact is specified, then a shallow vcard representation will be
7389  * created holding only the %E_CONTACT_UID and %E_CONTACT_REV fields.
7390  *
7391  * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
7392  *
7393  * Since: 3.16
7394  **/
7395 gboolean
ebsql_get_vcard_unlocked(EBookSqlite * ebsql,const gchar * uid,gboolean meta_contact,gchar ** ret_vcard,GError ** error)7396 ebsql_get_vcard_unlocked (EBookSqlite *ebsql,
7397                          const gchar *uid,
7398                          gboolean meta_contact,
7399                          gchar **ret_vcard,
7400                          GError **error)
7401 {
7402 	gboolean success = FALSE;
7403 	gchar *vcard = NULL;
7404 
7405 	g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
7406 	g_return_val_if_fail (uid != NULL, FALSE);
7407 	g_return_val_if_fail (ret_vcard != NULL && *ret_vcard == NULL, FALSE);
7408 
7409 	/* Try constructing contacts from only UID/REV first if that's requested */
7410 	if (meta_contact) {
7411 		GSList *vcards = NULL;
7412 
7413 		success = ebsql_exec_printf (
7414 			ebsql, "SELECT summary.uid, summary.Rev FROM %Q AS summary WHERE uid = %Q",
7415 			collect_lean_results_cb, &vcards, NULL, error,
7416 			ebsql->priv->folderid, uid);
7417 
7418 		if (vcards) {
7419 			EbSqlSearchData *search_data = (EbSqlSearchData *) vcards->data;
7420 
7421 			vcard = search_data->vcard;
7422 			search_data->vcard = NULL;
7423 
7424 			g_slist_free_full (vcards, (GDestroyNotify) e_book_sqlite_search_data_free);
7425 			vcards = NULL;
7426 		}
7427 
7428        } else {
7429 	       success = ebsql_exec_printf (
7430 		       ebsql, "SELECT %s FROM %Q AS summary WHERE summary.uid = %Q",
7431 		       get_string_cb, &vcard, NULL, error,
7432 		       EBSQL_VCARD_FRAGMENT (ebsql), ebsql->priv->folderid, uid);
7433        }
7434 
7435 	*ret_vcard = vcard;
7436 
7437 	if (success && !vcard) {
7438 		EBSQL_SET_ERROR (error,
7439 				 E_BOOK_SQLITE_ERROR_CONTACT_NOT_FOUND,
7440 				 _("Contact “%s” not found"), uid);
7441 		success = FALSE;
7442 	}
7443 
7444 	return success;
7445 }
7446 
7447 /**
7448  * e_book_sqlite_set_contact_extra:
7449  * @ebsql: An #EBookSqlite
7450  * @uid: The uid of the contact to set the extra data for
7451  * @extra: (nullable): The extra data to set
7452  * @error: A location to store any error that may have occurred.
7453  *
7454  * Sets or replaces the extra data associated with @uid.
7455  *
7456  * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
7457  *
7458  * Since: 3.12
7459  **/
7460 gboolean
e_book_sqlite_set_contact_extra(EBookSqlite * ebsql,const gchar * uid,const gchar * extra,GError ** error)7461 e_book_sqlite_set_contact_extra (EBookSqlite *ebsql,
7462                                  const gchar *uid,
7463                                  const gchar *extra,
7464                                  GError **error)
7465 {
7466 	gboolean success;
7467 
7468 	g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
7469 	g_return_val_if_fail (uid != NULL, FALSE);
7470 
7471 	EBSQL_LOCK_MUTEX (&ebsql->priv->lock);
7472 	success = ebsql_exec_printf (
7473 		ebsql, "UPDATE %Q SET bdata = %Q WHERE uid = %Q",
7474 		NULL, NULL, NULL, error,
7475 		ebsql->priv->folderid, uid);
7476 	EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
7477 
7478 	return success;
7479 }
7480 
7481 /**
7482  * e_book_sqlite_get_contact_extra:
7483  * @ebsql: An #EBookSqlite
7484  * @uid: The uid of the contact to fetch the extra data for
7485  * @ret_extra: (out): Return location to store the extra data
7486  * @error: A location to store any error that may have occurred.
7487  *
7488  * Fetches the extra data previously set for @uid, either with
7489  * e_book_sqlite_set_contact_extra() or when adding contacts.
7490  *
7491  * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
7492  *
7493  * Since: 3.12
7494  **/
7495 gboolean
e_book_sqlite_get_contact_extra(EBookSqlite * ebsql,const gchar * uid,gchar ** ret_extra,GError ** error)7496 e_book_sqlite_get_contact_extra (EBookSqlite *ebsql,
7497                                  const gchar *uid,
7498                                  gchar **ret_extra,
7499                                  GError **error)
7500 {
7501 	gboolean success;
7502 
7503 	g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
7504 	g_return_val_if_fail (uid != NULL, FALSE);
7505 	g_return_val_if_fail (ret_extra != NULL && *ret_extra == NULL, FALSE);
7506 
7507 	EBSQL_LOCK_MUTEX (&ebsql->priv->lock);
7508 	success = ebsql_exec_printf (
7509 		ebsql, "SELECT bdata FROM %Q WHERE uid = %Q",
7510 		get_string_cb, ret_extra, NULL, error,
7511 		ebsql->priv->folderid, uid);
7512 	EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
7513 
7514 	return success;
7515 }
7516 
7517 /**
7518  * ebsql_get_contact_extra_unlocked:
7519  * @ebsql: An #EBookSqlite
7520  * @uid: The uid of the contact to fetch the extra data for
7521  * @ret_extra: (out): Return location to store the extra data
7522  * @error: A location to store any error that may have occurred.
7523  *
7524  * Fetches the extra data previously set for @uid, either with
7525  * e_book_sqlite_set_contact_extra() or when adding contacts,
7526  * without locking internal mutex.
7527  *
7528  * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
7529  *
7530  * Since: 3.16
7531  **/
7532 gboolean
ebsql_get_contact_extra_unlocked(EBookSqlite * ebsql,const gchar * uid,gchar ** ret_extra,GError ** error)7533 ebsql_get_contact_extra_unlocked (EBookSqlite *ebsql,
7534 				  const gchar *uid,
7535 				  gchar **ret_extra,
7536 				  GError **error)
7537 {
7538 	gboolean success;
7539 
7540 	g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
7541 	g_return_val_if_fail (uid != NULL, FALSE);
7542 	g_return_val_if_fail (ret_extra != NULL && *ret_extra == NULL, FALSE);
7543 
7544 	success = ebsql_exec_printf (
7545 		ebsql, "SELECT bdata FROM %Q WHERE uid = %Q",
7546 		get_string_cb, ret_extra, NULL, error,
7547 		ebsql->priv->folderid, uid);
7548 
7549 	return success;
7550 }
7551 
7552 /**
7553  * e_book_sqlite_search:
7554  * @ebsql: An #EBookSqlite
7555  * @sexp: (nullable): search expression; use %NULL or an empty string to list all stored contacts.
7556  * @meta_contacts: Whether entire contacts are desired, or only the metadata
7557  * @ret_list: (out) (transfer full) (element-type EbSqlSearchData): Return location
7558  * to store a #GSList of #EbSqlSearchData structures
7559  * @cancellable: A #GCancellable
7560  * @error: A location to store any error that may have occurred.
7561  *
7562  * Searches @ebsql for contacts matching the search expression indicated by @sexp.
7563  *
7564  * When @sexp refers only to #EContactFields configured in the summary of @ebsql,
7565  * the search should always be quick, when searching for other #EContactFields
7566  * a fallback will be used, possibly invoking any #EbSqlVCardCallback which
7567  * may have been passed to e_book_sqlite_new_full().
7568  *
7569  * The returned @ret_list list should be freed with g_slist_free()
7570  * and all elements freed with e_book_sqlite_search_data_free().
7571  *
7572  * If @meta_contact is specified, then shallow vcard representations will be
7573  * created holding only the %E_CONTACT_UID and %E_CONTACT_REV fields.
7574  *
7575  * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
7576  *
7577  * Since: 3.12
7578  **/
7579 gboolean
e_book_sqlite_search(EBookSqlite * ebsql,const gchar * sexp,gboolean meta_contacts,GSList ** ret_list,GCancellable * cancellable,GError ** error)7580 e_book_sqlite_search (EBookSqlite *ebsql,
7581                       const gchar *sexp,
7582                       gboolean meta_contacts,
7583                       GSList **ret_list,
7584                       GCancellable *cancellable,
7585                       GError **error)
7586 {
7587 	gboolean success;
7588 
7589 	g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
7590 	g_return_val_if_fail (ret_list != NULL && *ret_list == NULL, FALSE);
7591 
7592 	EBSQL_LOCK_OR_RETURN (ebsql, cancellable, FALSE);
7593 	success = ebsql_search_query (
7594 		ebsql, sexp,
7595 		meta_contacts ?
7596 		SEARCH_UID_AND_REV : SEARCH_FULL,
7597 		ret_list,
7598 		cancellable,
7599 		error);
7600 	EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
7601 
7602 	return success;
7603 }
7604 
7605 /**
7606  * e_book_sqlite_search_uids:
7607  * @ebsql: An #EBookSqlite
7608  * @sexp: (nullable): search expression; use %NULL or an empty string to get all stored contacts.
7609  * @ret_list: (out) (transfer full) (element-type utf8): Return location to store a #GSList of contact uids
7610  * @cancellable: A #GCancellable
7611  * @error: A location to store any error that may have occurred.
7612  *
7613  * Similar to e_book_sqlitedb_search(), but fetches only a list of contact UIDs.
7614  *
7615  * The returned @ret_list list should be freed with g_slist_free() and all
7616  * elements freed with g_free().
7617  *
7618  * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
7619  *
7620  * Since: 3.12
7621  **/
7622 gboolean
e_book_sqlite_search_uids(EBookSqlite * ebsql,const gchar * sexp,GSList ** ret_list,GCancellable * cancellable,GError ** error)7623 e_book_sqlite_search_uids (EBookSqlite *ebsql,
7624                            const gchar *sexp,
7625                            GSList **ret_list,
7626                            GCancellable *cancellable,
7627                            GError **error)
7628 {
7629 	gboolean success;
7630 
7631 	g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
7632 	g_return_val_if_fail (ret_list != NULL && *ret_list == NULL, FALSE);
7633 
7634 	EBSQL_LOCK_OR_RETURN (ebsql, cancellable, FALSE);
7635 	success = ebsql_search_query (ebsql, sexp, SEARCH_UID, ret_list, cancellable, error);
7636 	EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
7637 
7638 	return success;
7639 }
7640 
7641 /**
7642  * e_book_sqlite_get_key_value:
7643  * @ebsql: An #EBookSqlite
7644  * @key: The key to fetch a value for
7645  * @value: (out): A return location to store the value for @key
7646  * @error: A location to store any error that may have occurred.
7647  *
7648  * Fetches the value for @key and stores it in @value
7649  *
7650  * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
7651  *
7652  * Since: 3.12
7653  **/
7654 gboolean
e_book_sqlite_get_key_value(EBookSqlite * ebsql,const gchar * key,gchar ** value,GError ** error)7655 e_book_sqlite_get_key_value (EBookSqlite *ebsql,
7656                              const gchar *key,
7657                              gchar **value,
7658                              GError **error)
7659 {
7660 	gboolean success;
7661 
7662 	g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
7663 	g_return_val_if_fail (key != NULL, FALSE);
7664 	g_return_val_if_fail (value != NULL && *value == NULL, FALSE);
7665 
7666 	EBSQL_LOCK_MUTEX (&ebsql->priv->lock);
7667 	success = ebsql_exec_printf (
7668 		ebsql,
7669 		"SELECT value FROM keys WHERE folder_id = %Q AND key = %Q",
7670 		get_string_cb, value, NULL, error,
7671 		ebsql->priv->folderid, key);
7672 	EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
7673 
7674 	return success;
7675 }
7676 
7677 /**
7678  * e_book_sqlite_set_key_value:
7679  * @ebsql: An #EBookSqlite
7680  * @key: The key to fetch a value for
7681  * @value: The new value for @key
7682  * @error: A location to store any error that may have occurred.
7683  *
7684  * Sets the value for @key to be @value
7685  *
7686  * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
7687  *
7688  * Since: 3.12
7689  **/
7690 gboolean
e_book_sqlite_set_key_value(EBookSqlite * ebsql,const gchar * key,const gchar * value,GError ** error)7691 e_book_sqlite_set_key_value (EBookSqlite *ebsql,
7692                              const gchar *key,
7693                              const gchar *value,
7694                              GError **error)
7695 {
7696 	gboolean success;
7697 
7698 	g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
7699 	g_return_val_if_fail (key != NULL, FALSE);
7700 	g_return_val_if_fail (value != NULL, FALSE);
7701 
7702 	EBSQL_LOCK_MUTEX (&ebsql->priv->lock);
7703 	success = ebsql_exec_printf (
7704 		ebsql, "INSERT or REPLACE INTO keys (key, value, folder_id) values (%Q, %Q, %Q)",
7705 		NULL, NULL, NULL, error,
7706 		key, value, ebsql->priv->folderid);
7707 	EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
7708 
7709 	return success;
7710 }
7711 
7712 /**
7713  * e_book_sqlite_get_key_value_int:
7714  * @ebsql: An #EBookSqlite
7715  * @key: The key to fetch a value for
7716  * @value: (out): A return location to store the value for @key
7717  * @error: A location to store any error that may have occurred.
7718  *
7719  * A convenience function to fetch the value of @key as an integer.
7720  *
7721  * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
7722  *
7723  * Since: 3.12
7724  **/
7725 gboolean
e_book_sqlite_get_key_value_int(EBookSqlite * ebsql,const gchar * key,gint * value,GError ** error)7726 e_book_sqlite_get_key_value_int (EBookSqlite *ebsql,
7727                                  const gchar *key,
7728                                  gint *value,
7729                                  GError **error)
7730 {
7731 	gboolean success;
7732 	gchar *str_value = NULL;
7733 
7734 	g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
7735 	g_return_val_if_fail (key != NULL, FALSE);
7736 	g_return_val_if_fail (value != NULL, FALSE);
7737 
7738 	success = e_book_sqlite_get_key_value (ebsql, key, &str_value, error);
7739 
7740 	if (success) {
7741 
7742 		if (str_value)
7743 			*value = g_ascii_strtoll (str_value, NULL, 10);
7744 		else
7745 			*value = 0;
7746 
7747 		g_free (str_value);
7748 	}
7749 
7750 	return success;
7751 }
7752 
7753 /**
7754  * e_book_sqlite_set_key_value_int:
7755  * @ebsql: An #EBookSqlite
7756  * @key: The key to fetch a value for
7757  * @value: The new value for @key
7758  * @error: A location to store any error that may have occurred.
7759  *
7760  * A convenience function to set the value of @key as an integer.
7761  *
7762  * Returns: %TRUE on success, otherwise %FALSE is returned and @error is set appropriately.
7763  *
7764  * Since: 3.12
7765  **/
7766 gboolean
e_book_sqlite_set_key_value_int(EBookSqlite * ebsql,const gchar * key,gint value,GError ** error)7767 e_book_sqlite_set_key_value_int (EBookSqlite *ebsql,
7768                                  const gchar *key,
7769                                  gint value,
7770                                  GError **error)
7771 {
7772 	gboolean success;
7773 	gchar *str_value = NULL;
7774 
7775 	g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
7776 	g_return_val_if_fail (key != NULL, FALSE);
7777 
7778 	str_value = g_strdup_printf ("%d", value);
7779 	success = e_book_sqlite_set_key_value (
7780 		ebsql, key, str_value, error);
7781 	g_free (str_value);
7782 
7783 	return success;
7784 }
7785 
7786 /**
7787  * e_book_sqlite_search_data_free:
7788  * @data: An #EbSqlSearchData
7789  *
7790  * Frees an #EbSqlSearchData
7791  *
7792  * Since: 3.12
7793  **/
7794 void
e_book_sqlite_search_data_free(EbSqlSearchData * data)7795 e_book_sqlite_search_data_free (EbSqlSearchData *data)
7796 {
7797 	if (data) {
7798 		g_free (data->uid);
7799 		g_free (data->vcard);
7800 		g_free (data->extra);
7801 		g_slice_free (EbSqlSearchData, data);
7802 	}
7803 }
7804 
7805 /**
7806  * e_book_sqlite_set_locale:
7807  * @ebsql: An #EBookSqlite
7808  * @lc_collate: The new locale for the addressbook
7809  * @cancellable: A #GCancellable
7810  * @error: A location to store any error that may have occurred
7811  *
7812  * Relocalizes any locale specific data in the specified
7813  * new @lc_collate locale.
7814  *
7815  * The @lc_collate locale setting is stored and remembered on
7816  * subsequent accesses of the addressbook, changing the locale
7817  * will store the new locale and will modify sort keys and any
7818  * locale specific data in the addressbook.
7819  *
7820  * As a side effect, it's possible that changing the locale
7821  * will cause stored vcards to change. Notifications for
7822  * these changes can be caught with the #EbSqlVCardCallback
7823  * provided to e_book_sqlite_new_full().
7824  *
7825  * Returns: Whether the new locale was successfully set.
7826  *
7827  * Since: 3.12
7828  */
7829 gboolean
e_book_sqlite_set_locale(EBookSqlite * ebsql,const gchar * lc_collate,GCancellable * cancellable,GError ** error)7830 e_book_sqlite_set_locale (EBookSqlite *ebsql,
7831                           const gchar *lc_collate,
7832                           GCancellable *cancellable,
7833                           GError **error)
7834 {
7835 	gboolean success;
7836 	gchar *stored_lc_collate = NULL;
7837 
7838 	g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
7839 
7840 	EBSQL_LOCK_OR_RETURN (ebsql, cancellable, FALSE);
7841 
7842 	if (!ebsql_start_transaction (ebsql, EBSQL_LOCK_WRITE, cancellable, error)) {
7843 		EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
7844 		return FALSE;
7845 	}
7846 
7847 	success = ebsql_set_locale_internal (ebsql, lc_collate, error);
7848 
7849 	if (success)
7850 		success = ebsql_exec_printf (
7851 			ebsql, "SELECT lc_collate FROM folders WHERE folder_id = %Q",
7852 			get_string_cb, &stored_lc_collate, NULL, error,
7853 			ebsql->priv->folderid);
7854 
7855 	if (success && g_strcmp0 (stored_lc_collate, lc_collate) != 0)
7856 		success = ebsql_upgrade (ebsql, EBSQL_CHANGE_LOCALE_CHANGED, error);
7857 
7858 	/* If for some reason we failed, then reset the collator to use the old locale */
7859 	if (!success && stored_lc_collate && stored_lc_collate[0])
7860 		ebsql_set_locale_internal (ebsql, stored_lc_collate, NULL);
7861 
7862 	if (success)
7863 		success = ebsql_commit_transaction (ebsql, error);
7864 	else
7865 		/* The GError is already set. */
7866 		ebsql_rollback_transaction (ebsql, NULL);
7867 
7868 	EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
7869 
7870 	g_free (stored_lc_collate);
7871 
7872 	return success;
7873 }
7874 
7875 /**
7876  * e_book_sqlite_get_locale:
7877  * @ebsql: An #EBookSqlite
7878  * @locale_out: (out) (transfer full): The location to return the current locale
7879  * @error: A location to store any error that may have occurred
7880  *
7881  * Fetches the current locale setting for the address-book.
7882  *
7883  * Upon success, @lc_collate_out will hold the returned locale setting,
7884  * otherwise %FALSE will be returned and @error will be updated accordingly.
7885  *
7886  * Returns: Whether the locale was successfully fetched.
7887  *
7888  * Since: 3.12
7889  */
7890 gboolean
e_book_sqlite_get_locale(EBookSqlite * ebsql,gchar ** locale_out,GError ** error)7891 e_book_sqlite_get_locale (EBookSqlite *ebsql,
7892                           gchar **locale_out,
7893                           GError **error)
7894 {
7895 	gboolean success;
7896 	GError *local_error = NULL;
7897 
7898 	g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
7899 	g_return_val_if_fail (locale_out != NULL && *locale_out == NULL, FALSE);
7900 
7901 	EBSQL_LOCK_MUTEX (&ebsql->priv->lock);
7902 
7903 	success = ebsql_exec_printf (
7904 		ebsql, "SELECT lc_collate FROM folders WHERE folder_id = %Q",
7905 		get_string_cb, locale_out, NULL, error,
7906 		ebsql->priv->folderid);
7907 
7908 	if (*locale_out == NULL) {
7909 
7910 		/* This can't realistically happen, if it does we
7911 		 * should warn about it in stdout */
7912 		g_warning ("EBookSqlite has no active locale in the database");
7913 
7914 		*locale_out = g_strdup (ebsql->priv->locale);
7915 	}
7916 
7917 	if (success && !ebsql_set_locale_internal (ebsql, *locale_out, &local_error)) {
7918 		g_warning ("Error loading new locale: %s", local_error->message);
7919 		g_clear_error (&local_error);
7920 	}
7921 
7922 	EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
7923 
7924 	return success;
7925 }
7926 
7927 /**
7928  * e_book_sqlite_cursor_new: (skip)
7929  * @ebsql: An #EBookSqlite
7930  * @sexp: search expression; use NULL or an empty string to get all stored contacts.
7931  * @sort_fields: (array length=n_sort_fields): An array of #EContactFields as sort keys in order of priority
7932  * @sort_types: (array length=n_sort_fields): An array of #EBookCursorSortTypes, one for each field in @sort_fields
7933  * @n_sort_fields: The number of fields to sort results by.
7934  * @error: A return location to store any error that might be reported.
7935  *
7936  * Creates a new #EbSqlCursor.
7937  *
7938  * The cursor should be freed with e_book_sqlite_cursor_free().
7939  *
7940  * Returns: (transfer full): A newly created #EbSqlCursor
7941  *
7942  * Since: 3.12
7943  */
7944 EbSqlCursor *
e_book_sqlite_cursor_new(EBookSqlite * ebsql,const gchar * sexp,const EContactField * sort_fields,const EBookCursorSortType * sort_types,guint n_sort_fields,GError ** error)7945 e_book_sqlite_cursor_new (EBookSqlite *ebsql,
7946                           const gchar *sexp,
7947                           const EContactField *sort_fields,
7948                           const EBookCursorSortType *sort_types,
7949                           guint n_sort_fields,
7950                           GError **error)
7951 {
7952 	EbSqlCursor *cursor;
7953 	gint i;
7954 
7955 	g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), NULL);
7956 
7957 	/* We don't like '\0' sexps, prefer NULL */
7958 	if (sexp && !sexp[0])
7959 		sexp = NULL;
7960 
7961 	EBSQL_LOCK_MUTEX (&ebsql->priv->lock);
7962 
7963 	/* Need one sort key ... */
7964 	if (n_sort_fields == 0) {
7965 		EBSQL_SET_ERROR_LITERAL (
7966 			error, E_BOOK_SQLITE_ERROR_INVALID_QUERY,
7967 			_("At least one sort field must be specified to use an EbSqlCursor"));
7968 		EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
7969 		return NULL;
7970 	}
7971 
7972 	/* We only support string fields to sort the cursor */
7973 	for (i = 0; i < n_sort_fields; i++) {
7974 		EBSQL_NOTE (
7975 			CURSOR,
7976 			g_printerr (
7977 				"Building cursor to sort '%s' in '%s' order\n",
7978 				e_contact_field_name (sort_fields[i]),
7979 				sort_types[i] == E_BOOK_CURSOR_SORT_ASCENDING ?
7980 				"ascending" : "descending"));
7981 
7982 		if (e_contact_field_type (sort_fields[i]) != G_TYPE_STRING) {
7983 			EBSQL_SET_ERROR_LITERAL (
7984 				error, E_BOOK_SQLITE_ERROR_INVALID_QUERY,
7985 				_("Cannot sort by a field that is not a string type"));
7986 			EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
7987 			return NULL;
7988 		}
7989 	}
7990 
7991 	/* Now we need to create the cursor instance before setting up the query
7992 	 * (not really true, but more convenient that way).
7993 	 */
7994 	cursor = ebsql_cursor_new (ebsql, sexp, sort_fields, sort_types, n_sort_fields);
7995 
7996 	/* Setup the cursor's query expression which might fail */
7997 	if (!ebsql_cursor_setup_query (ebsql, cursor, sexp, error)) {
7998 		ebsql_cursor_free (cursor);
7999 		cursor = NULL;
8000 	}
8001 
8002 	EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
8003 
8004 	EBSQL_NOTE (
8005 		CURSOR,
8006 		g_printerr (
8007 			"%s cursor with search expression '%s'\n",
8008 			cursor ? "Successfully created" : "Failed to create",
8009 			sexp));
8010 
8011 	return cursor;
8012 }
8013 
8014 /**
8015  * e_book_sqlite_cursor_free: (skip)
8016  * @ebsql: An #EBookSqlite
8017  * @cursor: The #EbSqlCursor to free
8018  *
8019  * Frees @cursor.
8020  *
8021  * Since: 3.12
8022  */
8023 void
e_book_sqlite_cursor_free(EBookSqlite * ebsql,EbSqlCursor * cursor)8024 e_book_sqlite_cursor_free (EBookSqlite *ebsql,
8025                            EbSqlCursor *cursor)
8026 {
8027 	g_return_if_fail (E_IS_BOOK_SQLITE (ebsql));
8028 
8029 	ebsql_cursor_free (cursor);
8030 }
8031 
8032 typedef struct {
8033 	GSList *results;
8034 	gchar *alloc_vcard;
8035 	const gchar *last_vcard;
8036 
8037 	gboolean collect_results;
8038 	gint n_results;
8039 } CursorCollectData;
8040 
8041 static gint
collect_results_for_cursor_cb(gpointer ref,gint ncol,gchar ** cols,gchar ** names)8042 collect_results_for_cursor_cb (gpointer ref,
8043                                gint ncol,
8044                                gchar **cols,
8045                                gchar **names)
8046 {
8047 	CursorCollectData *data = ref;
8048 
8049 	if (data->collect_results) {
8050 		EbSqlSearchData *search_data;
8051 
8052 		search_data = search_data_from_results (ncol, cols, names);
8053 
8054 		data->results = g_slist_prepend (data->results, search_data);
8055 
8056 		data->last_vcard = search_data->vcard;
8057 	} else {
8058 		g_free (data->alloc_vcard);
8059 		data->alloc_vcard = g_strdup (cols[1]);
8060 
8061 		data->last_vcard = data->alloc_vcard;
8062 	}
8063 
8064 	data->n_results++;
8065 
8066 	return 0;
8067 }
8068 
8069 /**
8070  * e_book_sqlite_cursor_step: (skip)
8071  * @ebsql: An #EBookSqlite
8072  * @cursor: The #EbSqlCursor to use
8073  * @flags: The #EbSqlCursorStepFlags for this step
8074  * @origin: The #EbSqlCursorOrigin from whence to step
8075  * @count: A positive or negative amount of contacts to try and fetch
8076  * @results: (out) (nullable) (element-type EbSqlSearchData) (transfer full):
8077  *   A return location to store the results, or %NULL if %EBSQL_CURSOR_STEP_FETCH is not specified in @flags.
8078  * @cancellable: A #GCancellable
8079  * @error: A return location to store any error that might be reported.
8080  *
8081  * Steps @cursor through its sorted query by a maximum of @count contacts
8082  * starting from @origin.
8083  *
8084  * If @count is negative, then the cursor will move through the list in reverse.
8085  *
8086  * If @cursor reaches the beginning or end of the query results, then the
8087  * returned list might not contain the amount of desired contacts, or might
8088  * return no results if the cursor currently points to the last contact.
8089  * Reaching the end of the list is not considered an error condition. Attempts
8090  * to step beyond the end of the list after having reached the end of the list
8091  * will however trigger an %E_BOOK_SQLITE_ERROR_END_OF_LIST error.
8092  *
8093  * If %EBSQL_CURSOR_STEP_FETCH is specified in @flags, a pointer to
8094  * a %NULL #GSList pointer should be provided for the @results parameter.
8095  *
8096  * The result list will be stored to @results and should be freed with g_slist_free()
8097  * and all elements freed with e_book_sqlite_search_data_free().
8098  *
8099  * Returns: The number of contacts traversed if successful, otherwise -1 is
8100  * returned and @error is set.
8101  *
8102  * Since: 3.12
8103  */
8104 gint
e_book_sqlite_cursor_step(EBookSqlite * ebsql,EbSqlCursor * cursor,EbSqlCursorStepFlags flags,EbSqlCursorOrigin origin,gint count,GSList ** results,GCancellable * cancellable,GError ** error)8105 e_book_sqlite_cursor_step (EBookSqlite *ebsql,
8106                            EbSqlCursor *cursor,
8107                            EbSqlCursorStepFlags flags,
8108                            EbSqlCursorOrigin origin,
8109                            gint count,
8110                            GSList **results,
8111                            GCancellable *cancellable,
8112                            GError **error)
8113 {
8114 	CursorCollectData data = { NULL, NULL, NULL, FALSE, 0 };
8115 	CursorState *state;
8116 	GString *query;
8117 	gboolean success;
8118 	EbSqlCursorOrigin try_position;
8119 
8120 	g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), -1);
8121 	g_return_val_if_fail (cursor != NULL, -1);
8122 	g_return_val_if_fail ((flags & EBSQL_CURSOR_STEP_FETCH) == 0 ||
8123 			      (results != NULL && *results == NULL), -1);
8124 
8125 	/* Lock and check cancellable early */
8126 	EBSQL_LOCK_OR_RETURN (ebsql, cancellable, -1);
8127 
8128 	EBSQL_NOTE (
8129 		CURSOR,
8130 		g_printerr (
8131 			"Cursor requested to step by %d with origin %s will move: %s will fetch: %s\n",
8132 			count, ebsql_origin_str (origin),
8133 			(flags & EBSQL_CURSOR_STEP_MOVE) ? "yes" : "no",
8134 			(flags & EBSQL_CURSOR_STEP_FETCH) ? "yes" : "no"));
8135 
8136 	/* Check if this step should result in an end of list error first */
8137 	try_position = cursor->state.position;
8138 	if (origin != EBSQL_CURSOR_ORIGIN_CURRENT)
8139 		try_position = origin;
8140 
8141 	/* Report errors for requests to run off the end of the list */
8142 	if (try_position == EBSQL_CURSOR_ORIGIN_BEGIN && count < 0) {
8143 		EBSQL_SET_ERROR_LITERAL (
8144 			error, E_BOOK_SQLITE_ERROR_END_OF_LIST,
8145 			_("Tried to step a cursor in reverse, "
8146 			"but cursor is already at the beginning of the contact list"));
8147 
8148 		EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
8149 		return -1;
8150 	} else if (try_position == EBSQL_CURSOR_ORIGIN_END && count > 0) {
8151 		EBSQL_SET_ERROR_LITERAL (
8152 			error, E_BOOK_SQLITE_ERROR_END_OF_LIST,
8153 			_("Tried to step a cursor forwards, "
8154 			"but cursor is already at the end of the contact list"));
8155 
8156 		EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
8157 		return -1;
8158 	}
8159 
8160 	/* Nothing to do, silently return */
8161 	if (count == 0 && try_position == EBSQL_CURSOR_ORIGIN_CURRENT) {
8162 		EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
8163 		return 0;
8164 	}
8165 
8166 	/* If we're not going to modify the position, just use
8167 	 * a copy of the current cursor state.
8168 	 */
8169 	if ((flags & EBSQL_CURSOR_STEP_MOVE) != 0)
8170 		state = &(cursor->state);
8171 	else
8172 		state = cursor_state_copy (cursor, &(cursor->state));
8173 
8174 	/* Every query starts with the STATE_CURRENT position, first
8175 	 * fix up the cursor state according to 'origin'
8176 	 */
8177 	switch (origin) {
8178 	case EBSQL_CURSOR_ORIGIN_CURRENT:
8179 		/* Do nothing, normal operation */
8180 		break;
8181 
8182 	case EBSQL_CURSOR_ORIGIN_BEGIN:
8183 	case EBSQL_CURSOR_ORIGIN_END:
8184 
8185 		/* Prepare the state before executing the query */
8186 		cursor_state_clear (cursor, state, origin);
8187 		break;
8188 	}
8189 
8190 	/* If count is 0 then there is no need to run any
8191 	 * query, however it can be useful if you just want
8192 	 * to move the cursor to the beginning or ending of
8193 	 * the list.
8194 	 */
8195 	if (count == 0) {
8196 
8197 		/* Free the state copy if need be */
8198 		if ((flags & EBSQL_CURSOR_STEP_MOVE) == 0)
8199 			cursor_state_free (cursor, state);
8200 
8201 		EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
8202 		return 0;
8203 	}
8204 
8205 	query = g_string_new (cursor->select_vcards);
8206 
8207 	/* Add the filter constraints (if any) */
8208 	if (cursor->query) {
8209 		g_string_append (query, " WHERE ");
8210 
8211 		g_string_append_c (query, '(');
8212 		g_string_append (query, cursor->query);
8213 		g_string_append_c (query, ')');
8214 	}
8215 
8216 	/* Add the cursor constraints (if any) */
8217 	if (state->values[0] != NULL) {
8218 		gchar *constraints = NULL;
8219 
8220 		if (!cursor->query)
8221 			g_string_append (query, " WHERE ");
8222 		else
8223 			g_string_append (query, " AND ");
8224 
8225 		constraints = ebsql_cursor_constraints (
8226 			ebsql, cursor, state, count < 0, FALSE);
8227 
8228 		g_string_append_c (query, '(');
8229 		g_string_append (query, constraints);
8230 		g_string_append_c (query, ')');
8231 
8232 		g_free (constraints);
8233 	}
8234 
8235 	/* Add the sort order */
8236 	g_string_append_c (query, ' ');
8237 	if (count > 0)
8238 		g_string_append (query, cursor->order);
8239 	else
8240 		g_string_append (query, cursor->reverse_order);
8241 
8242 	/* Add the limit */
8243 	g_string_append_printf (query, " LIMIT %d", ABS (count));
8244 
8245 	/* Specify whether we really want results or not */
8246 	data.collect_results = (flags & EBSQL_CURSOR_STEP_FETCH) != 0;
8247 
8248 	/* Execute the query */
8249 	success = ebsql_exec (
8250 		ebsql, query->str,
8251 		collect_results_for_cursor_cb, &data,
8252 		cancellable, error);
8253 
8254 	/* Lock was obtained above */
8255 	EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
8256 
8257 	g_string_free (query, TRUE);
8258 
8259 	/* If there was no error, update the internal cursor state */
8260 	if (success) {
8261 
8262 		if (data.n_results < ABS (count)) {
8263 
8264 			/* We've reached the end, clear the current state */
8265 			if (count < 0)
8266 				cursor_state_clear (cursor, state, EBSQL_CURSOR_ORIGIN_BEGIN);
8267 			else
8268 				cursor_state_clear (cursor, state, EBSQL_CURSOR_ORIGIN_END);
8269 
8270 		} else if (data.last_vcard) {
8271 
8272 			/* Set the cursor state to the last result */
8273 			cursor_state_set_from_vcard (ebsql, cursor, state, data.last_vcard);
8274 		} else
8275 			/* Should never get here */
8276 			g_warn_if_reached ();
8277 
8278 		/* Assign the results to return (if any) */
8279 		if (results) {
8280 			/* Correct the order of results at the last minute */
8281 			*results = g_slist_reverse (data.results);
8282 			data.results = NULL;
8283 		}
8284 	}
8285 
8286 	/* Cleanup what was allocated by collect_results_for_cursor_cb() */
8287 	if (data.results)
8288 		g_slist_free_full (
8289 			data.results,
8290 			(GDestroyNotify) e_book_sqlite_search_data_free);
8291 	g_free (data.alloc_vcard);
8292 
8293 	/* Free the copy state if we were working with a copy */
8294 	if ((flags & EBSQL_CURSOR_STEP_MOVE) == 0)
8295 		cursor_state_free (cursor, state);
8296 
8297 	if (success)
8298 		return data.n_results;
8299 
8300 	return -1;
8301 }
8302 
8303 /**
8304  * e_book_sqlite_cursor_set_target_alphabetic_index: (skip)
8305  * @ebsql: An #EBookSqlite
8306  * @cursor: The #EbSqlCursor to modify
8307  * @idx: The alphabetic index
8308  *
8309  * Sets the @cursor position to an
8310  * <link linkend="cursor-alphabet">Alphabetic Index</link>
8311  * into the alphabet active in @ebsql's locale.
8312  *
8313  * After setting the target to an alphabetic index, for example the
8314  * index for letter 'E', then further calls to e_book_sqlite_cursor_step()
8315  * will return results starting with the letter 'E' (or results starting
8316  * with the last result in 'D', if moving in a negative direction).
8317  *
8318  * The passed index must be a valid index in the active locale, knowledge
8319  * on the currently active alphabet index must be obtained using #ECollator
8320  * APIs.
8321  *
8322  * Use e_book_sqlite_ref_collator() to obtain the active collator for @ebsql.
8323  *
8324  * Since: 3.12
8325  */
8326 void
e_book_sqlite_cursor_set_target_alphabetic_index(EBookSqlite * ebsql,EbSqlCursor * cursor,gint idx)8327 e_book_sqlite_cursor_set_target_alphabetic_index (EBookSqlite *ebsql,
8328                                                   EbSqlCursor *cursor,
8329                                                   gint idx)
8330 {
8331 	gint n_labels = 0;
8332 
8333 	g_return_if_fail (E_IS_BOOK_SQLITE (ebsql));
8334 	g_return_if_fail (cursor != NULL);
8335 	g_return_if_fail (idx >= 0);
8336 
8337 	e_collator_get_index_labels (
8338 		ebsql->priv->collator, &n_labels,
8339 		NULL, NULL, NULL);
8340 	g_return_if_fail (idx < n_labels);
8341 
8342 	cursor_state_clear (cursor, &(cursor->state), EBSQL_CURSOR_ORIGIN_CURRENT);
8343 	if (cursor->n_sort_fields > 0) {
8344 		SummaryField *field;
8345 		gchar *index_key;
8346 
8347 		index_key = e_collator_generate_key_for_index (ebsql->priv->collator, idx);
8348 		field = summary_field_get (ebsql, cursor->sort_fields[0]);
8349 
8350 		if (field && (field->index & INDEX_FLAG (SORT_KEY)) != 0) {
8351 			cursor->state.values[0] = index_key;
8352 		} else {
8353 			cursor->state.values[0] =
8354 				ebsql_encode_vcard_sort_key (index_key);
8355 			g_free (index_key);
8356 		}
8357 	}
8358 }
8359 
8360 /**
8361  * e_book_sqlite_cursor_set_sexp: (skip)
8362  * @ebsql: An #EBookSqlite
8363  * @cursor: The #EbSqlCursor
8364  * @sexp: The new query expression for @cursor
8365  * @error: A return location to store any error that might be reported.
8366  *
8367  * Modifies the current query expression for @cursor. This will not
8368  * modify @cursor's state, but will change the outcome of any further
8369  * calls to e_book_sqlite_cursor_calculate() or
8370  * e_book_sqlite_cursor_step().
8371  *
8372  * Returns: %TRUE if the expression was valid and accepted by @ebsql
8373  *
8374  * Since: 3.12
8375  */
8376 gboolean
e_book_sqlite_cursor_set_sexp(EBookSqlite * ebsql,EbSqlCursor * cursor,const gchar * sexp,GError ** error)8377 e_book_sqlite_cursor_set_sexp (EBookSqlite *ebsql,
8378                                EbSqlCursor *cursor,
8379                                const gchar *sexp,
8380                                GError **error)
8381 {
8382 	gboolean success;
8383 
8384 	g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
8385 	g_return_val_if_fail (cursor != NULL, FALSE);
8386 
8387 	/* We don't like '\0' sexps, prefer NULL */
8388 	if (sexp && !sexp[0])
8389 		sexp = NULL;
8390 
8391 	EBSQL_LOCK_MUTEX (&ebsql->priv->lock);
8392 	success = ebsql_cursor_setup_query (ebsql, cursor, sexp, error);
8393 	EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
8394 
8395 	return success;
8396 }
8397 
8398 /**
8399  * e_book_sqlite_cursor_calculate: (skip)
8400  * @ebsql: An #EBookSqlite
8401  * @cursor: The #EbSqlCursor
8402  * @total: (out) (optional): A return location to store the total result set for this cursor
8403  * @position: (out) (optional): A return location to store the total results before the cursor value
8404  * @cancellable: A #GCancellable
8405  * @error: A return location to store any error that might be reported.
8406  *
8407  * Calculates the @total amount of results for the @cursor's query expression,
8408  * as well as the current @position of @cursor in the results. @position is
8409  * represented as the amount of results which lead up to the current value
8410  * of @cursor, if @cursor currently points to an exact contact, the position
8411  * also includes the cursor contact.
8412  *
8413  * Returns: Whether @total and @position were successfully calculated.
8414  *
8415  * Since: 3.12
8416  */
8417 gboolean
e_book_sqlite_cursor_calculate(EBookSqlite * ebsql,EbSqlCursor * cursor,gint * total,gint * position,GCancellable * cancellable,GError ** error)8418 e_book_sqlite_cursor_calculate (EBookSqlite *ebsql,
8419                                 EbSqlCursor *cursor,
8420                                 gint *total,
8421                                 gint *position,
8422                                 GCancellable *cancellable,
8423                                 GError **error)
8424 {
8425 	gboolean success = TRUE;
8426 	gint local_total = 0;
8427 
8428 	g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), FALSE);
8429 	g_return_val_if_fail (cursor != NULL, FALSE);
8430 
8431 	/* If we're in a clear cursor state, then the position is 0 */
8432 	if (position && cursor->state.values[0] == NULL) {
8433 
8434 		if (cursor->state.position == EBSQL_CURSOR_ORIGIN_BEGIN) {
8435 			/* Mark the local pointer NULL, no need to calculate this anymore */
8436 			*position = 0;
8437 			position = NULL;
8438 		} else if (cursor->state.position == EBSQL_CURSOR_ORIGIN_END) {
8439 
8440 			/* Make sure that we look up the total so we can
8441 			 * set the position to 'total + 1'
8442 			 */
8443 			if (!total)
8444 				total = &local_total;
8445 		}
8446 	}
8447 
8448 	/* Early return if there is nothing to do */
8449 	if (!total && !position)
8450 		return TRUE;
8451 
8452 	EBSQL_LOCK_OR_RETURN (ebsql, cancellable, -1);
8453 
8454 	/* Start a read transaction, it's important our two queries are atomic */
8455 	if (!ebsql_start_transaction (ebsql, EBSQL_LOCK_READ, cancellable, error)) {
8456 		EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
8457 		return FALSE;
8458 	}
8459 
8460 	if (total)
8461 		success = cursor_count_total_locked (ebsql, cursor, total, error);
8462 
8463 	if (success && position)
8464 		success = cursor_count_position_locked (ebsql, cursor, position, error);
8465 
8466 	if (success)
8467 		success = ebsql_commit_transaction (ebsql, error);
8468 	else
8469 		/* The GError is already set. */
8470 		ebsql_rollback_transaction (ebsql, NULL);
8471 
8472 	EBSQL_UNLOCK_MUTEX (&ebsql->priv->lock);
8473 
8474 	/* In the case we're at the end, we just set the position
8475 	 * to be the total + 1
8476 	 */
8477 	if (success && position && total &&
8478 	    cursor->state.position == EBSQL_CURSOR_ORIGIN_END)
8479 		*position = *total + 1;
8480 
8481 	return success;
8482 }
8483 
8484 /**
8485  * e_book_sqlite_cursor_compare_contact: (skip)
8486  * @ebsql: An #EBookSqlite
8487  * @cursor: The #EbSqlCursor
8488  * @contact: The #EContact to compare
8489  * @matches_sexp: (out) (optional): Whether the contact matches the cursor's search expression
8490  *
8491  * Compares @contact with @cursor and returns whether @contact is less than, equal to, or greater
8492  * than @cursor.
8493  *
8494  * Returns: A value that is less than, equal to, or greater than zero if @contact is found,
8495  * respectively, to be less than, to match, or be greater than the current value of @cursor.
8496  *
8497  * Since: 3.12
8498  */
8499 gint
e_book_sqlite_cursor_compare_contact(EBookSqlite * ebsql,EbSqlCursor * cursor,EContact * contact,gboolean * matches_sexp)8500 e_book_sqlite_cursor_compare_contact (EBookSqlite *ebsql,
8501                                       EbSqlCursor *cursor,
8502                                       EContact *contact,
8503                                       gboolean *matches_sexp)
8504 {
8505 	EBookSqlitePrivate *priv;
8506 	gint i;
8507 	gint comparison = 0;
8508 
8509 	g_return_val_if_fail (E_IS_BOOK_SQLITE (ebsql), -1);
8510 	g_return_val_if_fail (E_IS_CONTACT (contact), -1);
8511 	g_return_val_if_fail (cursor != NULL, -1);
8512 
8513 	priv = ebsql->priv;
8514 
8515 	if (matches_sexp) {
8516 		if (cursor->sexp == NULL)
8517 			*matches_sexp = TRUE;
8518 		else
8519 			*matches_sexp =
8520 				e_book_backend_sexp_match_contact (cursor->sexp, contact);
8521 	}
8522 
8523 	for (i = 0; i < cursor->n_sort_fields && comparison == 0; i++) {
8524 		SummaryField *field;
8525 		gchar *contact_key = NULL;
8526 		const gchar *cursor_key = NULL;
8527 		const gchar *field_value;
8528 		gchar *freeme = NULL;
8529 
8530 		field_value = (const gchar *) e_contact_get_const (contact, cursor->sort_fields[i]);
8531 		if (field_value)
8532 			contact_key = e_collator_generate_key (priv->collator, field_value, NULL);
8533 
8534 		field = summary_field_get (ebsql, cursor->sort_fields[i]);
8535 
8536 		if (field && (field->index & INDEX_FLAG (SORT_KEY)) != 0) {
8537 			cursor_key = cursor->state.values[i];
8538 		} else {
8539 
8540 			if (cursor->state.values[i])
8541 				freeme = ebsql_decode_vcard_sort_key (cursor->state.values[i]);
8542 
8543 			cursor_key = freeme;
8544 		}
8545 
8546 		/* Empty state sorts below any contact value, which means the contact sorts above cursor */
8547 		if (cursor_key == NULL)
8548 			comparison = 1;
8549 		else
8550 			/* Check if contact sorts below, equal to, or above the cursor */
8551 			comparison = g_strcmp0 (contact_key, cursor_key);
8552 
8553 		g_free (contact_key);
8554 		g_free (freeme);
8555 	}
8556 
8557 	/* UID tie-breaker */
8558 	if (comparison == 0) {
8559 		const gchar *uid;
8560 
8561 		uid = (const gchar *) e_contact_get_const (contact, E_CONTACT_UID);
8562 
8563 		if (cursor->state.last_uid == NULL)
8564 			comparison = 1;
8565 		else if (uid == NULL)
8566 			comparison = -1;
8567 		else
8568 			comparison = strcmp (uid, cursor->state.last_uid);
8569 	}
8570 
8571 	return comparison;
8572 }
8573