sqlite addressbook: fix memory corruption in get_revision
[platform/upstream/evolution-data-server.git] / addressbook / libedata-book / e-book-backend-sqlitedb.c
1 /*-*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* e-book-backend-sqlitedb.c
3  *
4  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
5  *
6  * Authors: Chenthill Palanisamy <pchenthill@novell.com>
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of version 2 of the GNU Lesser General Public
10  * License as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  */
21
22 #include "e-book-backend-sqlitedb.h"
23
24 #include <locale.h>
25 #include <string.h>
26 #include <errno.h>
27
28 #include <glib/gi18n.h>
29 #include <glib/gstdio.h>
30
31 #include <sqlite3.h>
32 #include <libebackend/libebackend.h>
33
34 #include "e-book-backend-sexp.h"
35
36 #define E_BOOK_BACKEND_SQLITEDB_GET_PRIVATE(obj) \
37         (G_TYPE_INSTANCE_GET_PRIVATE \
38         ((obj), E_TYPE_BOOK_BACKEND_SQLITEDB, EBookBackendSqliteDBPrivate))
39
40 #define d(x)
41
42 #if d(1)+0
43 #  define LOCK_MUTEX(mutex)                                     \
44         G_STMT_START {                                          \
45                 g_message ("%s: DB Locking ", G_STRFUNC);       \
46                 g_mutex_lock (mutex);                           \
47                 g_message ("%s: DB Locked ", G_STRFUNC);        \
48         } G_STMT_END
49
50 #  define UNLOCK_MUTEX(mutex)                                   \
51         G_STMT_START {                                          \
52                 g_message ("%s: Unlocking ", G_STRFUNC);        \
53                 g_mutex_unlock (mutex);                         \
54                 g_message ("%s: DB Unlocked ", G_STRFUNC);      \
55         } G_STMT_END
56 #else
57 #  define LOCK_MUTEX(mutex)   g_mutex_lock (mutex)
58 #  define UNLOCK_MUTEX(mutex) g_mutex_unlock (mutex)
59 #endif
60
61 #define DB_FILENAME "contacts.db"
62 #define FOLDER_VERSION 6
63
64 typedef enum {
65         INDEX_PREFIX = (1 << 0),
66         INDEX_SUFFIX = (1 << 1),
67         INDEX_PHONE  = (1 << 2)
68 } IndexFlags;
69
70 typedef struct {
71         EContactField field;   /* The EContact field */
72         GType         type;    /* The GType (only support string or gboolean) */
73         const gchar  *dbname;  /* The key for this field in the sqlite3 table */
74         IndexFlags    index;   /* Whether this summary field should have an index in the SQLite DB */
75 } SummaryField;
76
77 struct _EBookBackendSqliteDBPrivate {
78         sqlite3 *db;
79         gchar *path;
80         gchar *hash_key;
81
82         GMutex lock;
83         GMutex updates_lock; /* This is for deprecated e_book_backend_sqlitedb_lock_updates () */
84
85         gboolean store_vcard;
86         guint32 in_transaction;
87
88         SummaryField   *summary_fields;
89         gint            n_summary_fields;
90         guint           have_attr_list : 1;
91         IndexFlags      attr_list_indexes;
92 };
93
94 G_DEFINE_TYPE (EBookBackendSqliteDB, e_book_backend_sqlitedb, G_TYPE_OBJECT)
95
96 static GHashTable *db_connections = NULL;
97 static GMutex dbcon_lock;
98
99 static EContactField default_summary_fields[] = {
100         E_CONTACT_UID,
101         E_CONTACT_REV,
102         E_CONTACT_FILE_AS,
103         E_CONTACT_NICKNAME,
104         E_CONTACT_FULL_NAME,
105         E_CONTACT_GIVEN_NAME,
106         E_CONTACT_FAMILY_NAME,
107         E_CONTACT_EMAIL,
108         E_CONTACT_IS_LIST,
109         E_CONTACT_LIST_SHOW_ADDRESSES,
110         E_CONTACT_WANTS_HTML
111 };
112
113 /* Create indexes on full_name and email fields as autocompletion queries would mainly
114  * rely on this.
115  */
116 static EContactField default_indexed_fields[] = {
117         E_CONTACT_FULL_NAME,
118         E_CONTACT_EMAIL
119 };
120
121 static EBookIndexType default_index_types[] = {
122         E_BOOK_INDEX_PREFIX,
123         E_BOOK_INDEX_PREFIX
124 };
125
126 static SummaryField * append_summary_field (GArray         *array,
127                                             EContactField   field,
128                                             gboolean       *have_attr_list,
129                                             GError        **error);
130
131 static gboolean upgrade_contacts_table (EBookBackendSqliteDB  *ebsdb,
132                                          const gchar           *folderid,
133                                          GError               **error);
134
135 static const gchar *
136 summary_dbname_from_field (EBookBackendSqliteDB *ebsdb,
137                            EContactField field)
138 {
139         gint i;
140
141         for (i = 0; i < ebsdb->priv->n_summary_fields; i++) {
142                 if (ebsdb->priv->summary_fields[i].field == field)
143                         return ebsdb->priv->summary_fields[i].dbname;
144         }
145
146         return NULL;
147 }
148
149 static gint
150 summary_index_from_field_name (EBookBackendSqliteDB *ebsdb,
151                                const gchar *field_name)
152 {
153         gint i;
154         EContactField field;
155
156         field = e_contact_field_id (field_name);
157
158         for (i = 0; i < ebsdb->priv->n_summary_fields; i++) {
159                 if (ebsdb->priv->summary_fields[i].field == field)
160                         return i;
161         }
162
163         return -1;
164 }
165
166 typedef struct {
167         EBookBackendSqliteDB *ebsdb;
168         GSList *list;
169 } StoreVCardData;
170
171 G_DEFINE_QUARK (
172         e-book-backend-sqlitedb-error-quark,
173         e_book_backend_sqlitedb_error)
174
175 static void
176 e_book_backend_sqlitedb_dispose (GObject *object)
177 {
178         EBookBackendSqliteDBPrivate *priv;
179
180         priv = E_BOOK_BACKEND_SQLITEDB_GET_PRIVATE (object);
181
182         g_mutex_lock (&dbcon_lock);
183         if (db_connections != NULL) {
184                 if (priv->hash_key != NULL) {
185                         g_hash_table_remove (db_connections, priv->hash_key);
186
187                         if (g_hash_table_size (db_connections) == 0) {
188                                 g_hash_table_destroy (db_connections);
189                                 db_connections = NULL;
190                         }
191
192                         g_free (priv->hash_key);
193                         priv->hash_key = NULL;
194                 }
195         }
196         g_mutex_unlock (&dbcon_lock);
197
198         /* Chain up to parent's dispose() method. */
199         G_OBJECT_CLASS (e_book_backend_sqlitedb_parent_class)->dispose (object);
200 }
201
202 static void
203 e_book_backend_sqlitedb_finalize (GObject *object)
204 {
205         EBookBackendSqliteDBPrivate *priv;
206
207         priv = E_BOOK_BACKEND_SQLITEDB_GET_PRIVATE (object);
208
209         sqlite3_close (priv->db);
210
211         g_free (priv->path);
212         g_free (priv->summary_fields);
213
214         g_mutex_clear (&priv->lock);
215         g_mutex_clear (&priv->updates_lock);
216
217         /* Chain up to parent's finalize() method. */
218         G_OBJECT_CLASS (e_book_backend_sqlitedb_parent_class)->finalize (object);
219 }
220
221 static void
222 e_book_backend_sqlitedb_class_init (EBookBackendSqliteDBClass *class)
223 {
224         GObjectClass *object_class;
225
226         g_type_class_add_private (class, sizeof (EBookBackendSqliteDBPrivate));
227
228         object_class = G_OBJECT_CLASS (class);
229         object_class->dispose = e_book_backend_sqlitedb_dispose;
230         object_class->finalize = e_book_backend_sqlitedb_finalize;
231 }
232
233 static void
234 e_book_backend_sqlitedb_init (EBookBackendSqliteDB *ebsdb)
235 {
236         ebsdb->priv = E_BOOK_BACKEND_SQLITEDB_GET_PRIVATE (ebsdb);
237
238         ebsdb->priv->store_vcard = TRUE;
239
240         ebsdb->priv->in_transaction = 0;
241         g_mutex_init (&ebsdb->priv->lock);
242         g_mutex_init (&ebsdb->priv->updates_lock);
243 }
244
245 static gint
246 get_string_cb (gpointer ref,
247                gint col,
248                gchar **cols,
249                gchar **name)
250 {
251         gchar **ret = ref;
252
253         *ret = g_strdup (cols [0]);
254
255         return 0;
256 }
257
258 static gint
259 get_bool_cb (gpointer ref,
260              gint col,
261              gchar **cols,
262              gchar **name)
263 {
264         gboolean *ret = ref;
265
266         *ret = cols [0] ? strtoul (cols [0], NULL, 10) : 0;
267
268         return 0;
269 }
270
271 /**
272  * e_book_sql_exec
273  * @db:
274  * @stmt:
275  * @callback:
276  * @data:
277  * @error:
278  *
279  * Callers should hold the rw lock depending on read or write operation
280  * Returns:
281  **/
282 static gboolean
283 book_backend_sql_exec_real (sqlite3 *db,
284                             const gchar *stmt,
285                             gint (*callback)(gpointer ,gint,gchar **,gchar **),
286                             gpointer data,
287                             GError **error)
288 {
289         gchar *errmsg = NULL;
290         gint ret = -1;
291
292         ret = sqlite3_exec (db, stmt, callback, data, &errmsg);
293         while (ret == SQLITE_BUSY || ret == SQLITE_LOCKED || ret == -1) {
294                 if (errmsg) {
295                         sqlite3_free (errmsg);
296                         errmsg = NULL;
297                 }
298                 g_thread_yield ();
299                 ret = sqlite3_exec (db, stmt, callback, data, &errmsg);
300         }
301
302         if (ret != SQLITE_OK) {
303                 d (g_printerr ("Error in SQL EXEC statement: %s [%s].\n", stmt, errmsg));
304                 g_set_error_literal (
305                         error, E_BOOK_SDB_ERROR,
306                         ret == SQLITE_CONSTRAINT ?
307                         E_BOOK_SDB_ERROR_CONSTRAINT : E_BOOK_SDB_ERROR_OTHER,
308                         errmsg);
309                 sqlite3_free (errmsg);
310                 errmsg = NULL;
311                 return FALSE;
312         }
313
314         if (errmsg) {
315                 sqlite3_free (errmsg);
316                 errmsg = NULL;
317         }
318
319         return TRUE;
320 }
321
322 static gint
323 print_debug_cb (gpointer ref,
324                 gint n_cols,
325                 gchar **cols,
326                 gchar **name)
327 {
328         gint i;
329
330         g_printerr ("  DEBUG BEGIN:\n");
331
332         for (i = 0; i < n_cols; i++)
333                 g_printerr ("    NAME: '%s' VALUE: %s\n", name[i], cols[i]);
334
335         g_printerr ("  DEBUG END\n");
336
337         return 0;
338 }
339
340 static gint G_GNUC_CONST
341 booksql_debug (void)
342 {
343         static gint booksql_debug = -1;
344
345         if (booksql_debug == -1) {
346                 const gchar *const tmp = g_getenv ("BOOKSQL_DEBUG");
347                 booksql_debug = (tmp != NULL ? MAX (0, atoi (tmp)) : 0);
348         }
349
350         return booksql_debug;
351 }
352
353 static void
354 book_backend_sql_debug (sqlite3 *db,
355                         const gchar *stmt,
356                         gint (*callback)(gpointer ,gint,gchar **,gchar **),
357                         gpointer data,
358                         GError **error)
359 {
360         GError *local_error = NULL;
361
362         g_printerr ("DEBUG STATEMENT: %s\n", stmt);
363
364         if (booksql_debug () > 1) {
365                 gchar *debug = g_strconcat ("EXPLAIN QUERY PLAN ", stmt, NULL);
366                 book_backend_sql_exec_real (db, debug, print_debug_cb, NULL, &local_error);
367                 g_free (debug);
368         }
369
370         if (local_error) {
371                 g_printerr ("DEBUG STATEMENT END: Error: %s\n", local_error->message);
372         } else if (booksql_debug () > 1) {
373                 g_printerr ("DEBUG STATEMENT END: Success\n");
374         }
375
376         g_clear_error (&local_error);
377 }
378
379 static gboolean
380 book_backend_sql_exec (sqlite3 *db,
381                        const gchar *stmt,
382                        gint (*callback)(gpointer ,gint,gchar **,gchar **),
383                        gpointer data,
384                        GError **error)
385 {
386         if (booksql_debug ())
387                 book_backend_sql_debug (db, stmt, callback, data, error);
388
389         return book_backend_sql_exec_real (db, stmt, callback, data, error);
390 }
391
392 /* This function must always be called with the priv->lock held */
393 static gboolean
394 book_backend_sqlitedb_start_transaction (EBookBackendSqliteDB *ebsdb,
395                                          GError **error)
396 {
397         gboolean success = TRUE;
398
399         g_return_val_if_fail (ebsdb != NULL, FALSE);
400         g_return_val_if_fail (ebsdb->priv != NULL, FALSE);
401         g_return_val_if_fail (ebsdb->priv->db != NULL, FALSE);
402
403         ebsdb->priv->in_transaction++;
404         g_return_val_if_fail (ebsdb->priv->in_transaction > 0, FALSE);
405
406         if (ebsdb->priv->in_transaction == 1) {
407
408                 success = book_backend_sql_exec (
409                         ebsdb->priv->db, "BEGIN", NULL, NULL, error);
410         }
411
412         return success;
413 }
414
415 /* This function must always be called with the priv->lock held */
416 static gboolean
417 book_backend_sqlitedb_commit_transaction (EBookBackendSqliteDB *ebsdb,
418                                           GError **error)
419 {
420         gboolean success = TRUE;
421
422         g_return_val_if_fail (ebsdb != NULL, FALSE);
423         g_return_val_if_fail (ebsdb->priv != NULL, FALSE);
424         g_return_val_if_fail (ebsdb->priv->db != NULL, FALSE);
425
426         g_return_val_if_fail (ebsdb->priv->in_transaction > 0, FALSE);
427
428         ebsdb->priv->in_transaction--;
429
430         if (ebsdb->priv->in_transaction == 0) {
431                 success = book_backend_sql_exec (
432                         ebsdb->priv->db, "COMMIT", NULL, NULL, error);
433         }
434
435         return success;
436 }
437
438 /* This function must always be called with the priv->lock held */
439 static gboolean
440 book_backend_sqlitedb_rollback_transaction (EBookBackendSqliteDB *ebsdb,
441                                             GError **error)
442 {
443         gboolean success = TRUE;
444
445         g_return_val_if_fail (ebsdb != NULL, FALSE);
446         g_return_val_if_fail (ebsdb->priv != NULL, FALSE);
447         g_return_val_if_fail (ebsdb->priv->db != NULL, FALSE);
448
449         g_return_val_if_fail (ebsdb->priv->in_transaction > 0, FALSE);
450
451         ebsdb->priv->in_transaction--;
452
453         if (ebsdb->priv->in_transaction == 0) {
454                 success = book_backend_sql_exec (
455                         ebsdb->priv->db, "ROLLBACK", NULL, NULL, error);
456
457         }
458         return success;
459 }
460
461 static gint
462 collect_versions_cb (gpointer ref,
463                      gint col,
464                      gchar **cols,
465                      gchar **name)
466 {
467         gint *ret = ref;
468
469         /* Just collect the first result, all folders
470          * should always have the same DB version. */
471         *ret = cols [0] ? strtoul (cols [0], NULL, 10) : 0;
472
473         return 0;
474 }
475
476 static gboolean
477 create_folders_table (EBookBackendSqliteDB *ebsdb,
478                       gint *previous_schema,
479                       GError **error)
480 {
481         gboolean success;
482         gint version = 0;
483
484         /* sync_data points to syncronization data, it could be last_modified
485          * time or a sequence number or some text depending on the backend.
486          *
487          * partial_content says whether the contents are partially downloaded
488          * for auto-completion or if it has the complete content.
489          *
490          * Have not included a bdata here since the keys table should suffice
491          * any additional need that arises.
492          */
493         const gchar *stmt =
494                 "CREATE TABLE IF NOT EXISTS folders"
495                 "( folder_id  TEXT PRIMARY KEY,"
496                 " folder_name TEXT,"
497                 "  sync_data TEXT,"
498                 " is_populated INTEGER DEFAULT 0,"
499                 "  partial_content INTEGER DEFAULT 0,"
500                 " version INTEGER,"
501                 "  revision TEXT,"
502                 " multivalues TEXT )";
503
504         if (!book_backend_sqlitedb_start_transaction (ebsdb, error))
505                 return FALSE;
506
507         if (!book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error))
508                 goto rollback;
509
510         /* Create a child table to store key/value pairs for a folder. */
511         stmt =  "CREATE TABLE IF NOT EXISTS keys"
512                 "( key TEXT PRIMARY KEY, value TEXT,"
513                 " folder_id TEXT REFERENCES folders)";
514         if (!book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error))
515                 goto rollback;
516
517         stmt = "CREATE INDEX IF NOT EXISTS keysindex ON keys(folder_id)";
518         if (!book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error))
519                 goto rollback;
520
521         /* Fetch the version, it should be the
522          * same for all folders (hence the LIMIT). */
523         stmt = "SELECT version FROM folders LIMIT 1";
524         success = book_backend_sql_exec (
525                 ebsdb->priv->db, stmt, collect_versions_cb, &version, error);
526
527         if (!success)
528                 goto rollback;
529
530         /* Upgrade DB to version 2, add revision column
531          *
532          * (version = 0 indicates that it did not exist and we just
533          * created the table)
534          */
535         if (version >= 1 && version < 2) {
536                 stmt = "ALTER TABLE folders ADD COLUMN revision TEXT";
537                 success = book_backend_sql_exec (
538                         ebsdb->priv->db, stmt, NULL, NULL, error);
539
540                 if (!success)
541                         goto rollback;
542         }
543
544         /* Upgrade DB to version 3, add multivalues introspection columns
545          */
546         if (version >= 1 && version < 3) {
547                 stmt = "ALTER TABLE folders ADD COLUMN multivalues TEXT";
548                 success = book_backend_sql_exec (
549                         ebsdb->priv->db, stmt, NULL, NULL, error);
550
551                 if (!success)
552                         goto rollback;
553         }
554
555         /* Upgrade DB to version 4: Nothing to do. The country-code column it
556          * added got redundant already.
557          */
558
559         /* Upgrade DB to version 5: Drop the reverse_multivalues column, but
560          * wait with converting phone summary values to new format until
561          * create_contacts_table() as we need introspection details for doing
562          * that.
563          */
564         if (version >= 3 && version < 5) {
565                 stmt = "UPDATE folders SET "
566                                 "multivalues = REPLACE(RTRIM(REPLACE("
567                                         "multivalues || ':', ':', "
568                                         "CASE reverse_multivalues "
569                                                 "WHEN 0 THEN ';prefix ' "
570                                                 "ELSE ';prefix;suffix ' "
571                                         "END)), ' ', ':'), "
572                                 "reverse_multivalues = NULL";
573
574                 success = book_backend_sql_exec (
575                         ebsdb->priv->db, stmt, NULL, NULL, error);
576
577                 if (!success)
578                         goto rollback;
579         }
580
581         /* Finish the eventual upgrade by storing the current schema version.
582          */
583         if (version >= 1 && version < FOLDER_VERSION) {
584                 gchar *version_update_stmt =
585                         sqlite3_mprintf ("UPDATE folders SET version = %d", FOLDER_VERSION);
586
587                 success = book_backend_sql_exec (
588                         ebsdb->priv->db, version_update_stmt, NULL, NULL, error);
589
590                 sqlite3_free (version_update_stmt);
591         }
592
593         if (!success)
594                 goto rollback;
595
596         *previous_schema = version;
597         return book_backend_sqlitedb_commit_transaction (ebsdb, error);
598
599 rollback:
600         /* The GError is already set. */
601         book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
602
603         *previous_schema = 0;
604         return FALSE;
605 }
606
607 static gchar *
608 format_multivalues (EBookBackendSqliteDB *ebsdb)
609 {
610         gint i;
611         GString *string;
612         gboolean first = TRUE;
613
614         string = g_string_new (NULL);
615
616         for (i = 0; i < ebsdb->priv->n_summary_fields; i++) {
617                 if (ebsdb->priv->summary_fields[i].type == E_TYPE_CONTACT_ATTR_LIST) {
618                         if (first)
619                                 first = FALSE;
620                         else
621                                 g_string_append_c (string, ':');
622
623                         g_string_append (string, ebsdb->priv->summary_fields[i].dbname);
624
625                         if ((ebsdb->priv->summary_fields[i].index & INDEX_PREFIX) != 0)
626                                 g_string_append (string, ";prefix");
627                         if ((ebsdb->priv->summary_fields[i].index & INDEX_SUFFIX) != 0)
628                                 g_string_append (string, ";suffix");
629                         if ((ebsdb->priv->summary_fields[i].index & INDEX_PHONE) != 0)
630                                 g_string_append (string, ";phone");
631                 }
632         }
633
634         return g_string_free (string, FALSE);
635 }
636
637 static gboolean
638 add_folder_into_db (EBookBackendSqliteDB *ebsdb,
639                     const gchar *folderid,
640                     const gchar *folder_name,
641                     GError **error)
642 {
643         gchar *stmt;
644         gboolean success;
645         gchar *multivalues;
646
647         if (!book_backend_sqlitedb_start_transaction (ebsdb, error))
648                 return FALSE;
649
650         multivalues = format_multivalues (ebsdb);
651
652         stmt = sqlite3_mprintf (
653                 "INSERT OR IGNORE INTO "
654                 "folders ( folder_id, folder_name, version, multivalues ) "
655                 "VALUES ( %Q, %Q, %d, %Q ) ",
656                 folderid, folder_name, FOLDER_VERSION, multivalues);
657         success = book_backend_sql_exec (
658                 ebsdb->priv->db, stmt, NULL, NULL, error);
659         sqlite3_free (stmt);
660         g_free (multivalues);
661
662         if (!success)
663                 goto rollback;
664
665         return book_backend_sqlitedb_commit_transaction (ebsdb, error);
666
667 rollback:
668         book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
669
670         return FALSE;
671 }
672
673 static gint
674 collect_columns_cb (gpointer ref,
675                     gint col,
676                     gchar **cols,
677                     gchar **name)
678 {
679         GList **columns = (GList **) ref;
680         gint i;
681
682         for (i = 0; i < col; i++) {
683
684                 if (strcmp (name[i], "name") == 0) {
685
686                         if (strcmp (cols[i], "vcard") != 0 &&
687                             strcmp (cols[i], "bdata") != 0) {
688
689                                 gchar *column = g_strdup (cols[i]);
690
691                                 *columns = g_list_prepend (*columns, column);
692                         }
693
694                         break;
695                 }
696         }
697
698         return 0;
699 }
700
701 static gboolean
702 introspect_summary (EBookBackendSqliteDB *ebsdb,
703                     const gchar *folderid,
704                     GError **error)
705 {
706         gboolean success;
707         gchar *stmt;
708         GList *summary_columns = NULL, *l;
709         GArray *summary_fields = NULL;
710         gchar *multivalues = NULL;
711         gint i, j;
712
713         stmt = sqlite3_mprintf ("PRAGMA table_info (%Q);", folderid);
714         success = book_backend_sql_exec (
715                 ebsdb->priv->db, stmt, collect_columns_cb, &summary_columns, error);
716         sqlite3_free (stmt);
717
718         if (!success)
719                 goto introspect_summary_finish;
720
721         summary_columns = g_list_reverse (summary_columns);
722         summary_fields = g_array_new (FALSE, FALSE, sizeof (SummaryField));
723
724         /* Introspect the normal summary fields */
725         for (l = summary_columns; l; l = l->next) {
726                 EContactField field;
727                 gchar *col = l->data;
728                 gchar *p;
729                 IndexFlags computed = 0;
730
731                 /* Check if we're parsing a reverse field */
732                 if ((p = strstr (col, "_reverse")) != NULL) {
733                         computed = INDEX_SUFFIX;
734                         *p = '\0';
735                 } else  if ((p = strstr (col, "_phone")) != NULL) {
736                         computed = INDEX_PHONE;
737                         *p = '\0';
738                 }
739
740                 /* First check exception fields */
741                 if (g_ascii_strcasecmp (col, "uid") == 0)
742                         field = E_CONTACT_UID;
743                 else if (g_ascii_strcasecmp (col, "is_list") == 0)
744                         field = E_CONTACT_IS_LIST;
745                 else
746                         field = e_contact_field_id (col);
747
748                 /* Check for parse error */
749                 if (field == 0) {
750                         g_set_error (
751                                 error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
752                                 _("Error introspecting unknown summary field '%s'"), col);
753                         success = FALSE;
754                         break;
755                 }
756
757                 /* Computed columns are always declared after the normal columns,
758                  * if a reverse field is encountered we need to set the suffix
759                  * index on the coresponding summary field
760                  */
761                 if (computed) {
762                         for (i = 0; i < summary_fields->len; i++) {
763                                 SummaryField *iter = &g_array_index (summary_fields, SummaryField, i);
764
765                                 if (iter->field == field) {
766                                         iter->index |= computed;
767                                         break;
768                                 }
769                         }
770                 } else {
771                         append_summary_field (summary_fields, field, NULL, NULL);
772                 }
773         }
774
775         if (!success)
776                 goto introspect_summary_finish;
777
778         /* Introspect the multivalied summary fields */
779         stmt = sqlite3_mprintf (
780                 "SELECT multivalues FROM folders WHERE folder_id = %Q", folderid);
781         success = book_backend_sql_exec (
782                 ebsdb->priv->db, stmt, get_string_cb, &multivalues, error);
783         sqlite3_free (stmt);
784
785         if (!success)
786                 goto introspect_summary_finish;
787
788         ebsdb->priv->attr_list_indexes = 0;
789
790         if (multivalues) {
791                 gchar **fields = g_strsplit (multivalues, ":", 0);
792
793                 for (i = 0; fields[i] != NULL; i++) {
794                         EContactField field;
795                         SummaryField *iter;
796                         gchar **params;
797
798                         params = g_strsplit (fields[i], ";", 0);
799                         field = e_contact_field_id (params[0]);
800                         iter = append_summary_field (summary_fields, field, NULL, NULL);
801
802                         if (iter) {
803                                 for (j = 1; params[j]; ++j) {
804                                         if (strcmp (params[j], "prefix") == 0) {
805                                                 iter->index |= INDEX_PREFIX;
806                                         } else if (strcmp (params[j], "suffix") == 0) {
807                                                 iter->index |= INDEX_SUFFIX;
808                                         } else if (strcmp (params[j], "phone") == 0) {
809                                                 iter->index |= INDEX_PHONE;
810                                         }
811                                 }
812
813                                 ebsdb->priv->attr_list_indexes |= iter->index;
814                         }
815
816                         g_strfreev (params);
817                 }
818
819                 g_strfreev (fields);
820         }
821
822  introspect_summary_finish:
823
824         g_list_free_full (summary_columns, (GDestroyNotify) g_free);
825         g_free (multivalues);
826
827         /* Apply the introspected summary fields */
828         if (success) {
829                 g_free (ebsdb->priv->summary_fields);
830                 ebsdb->priv->n_summary_fields = summary_fields->len;
831                 ebsdb->priv->summary_fields = (SummaryField *) g_array_free (summary_fields, FALSE);
832         } else if (summary_fields) {
833                 g_array_free (summary_fields, TRUE);
834         }
835
836         return success;
837 }
838
839 /* The column names match the fields used in book-backend-sexp */
840 static gboolean
841 create_contacts_table (EBookBackendSqliteDB *ebsdb,
842                        const gchar *folderid,
843                        gint previous_schema,
844                        GError **error)
845 {
846         gint i;
847         gboolean success;
848         gchar *stmt, *tmp;
849         GString *string;
850
851         /* Construct the create statement from the summary fields table */
852         string = g_string_new (
853                 "CREATE TABLE IF NOT EXISTS %Q ( uid TEXT PRIMARY KEY, ");
854
855         for (i = 1; i < ebsdb->priv->n_summary_fields; i++) {
856                 if (ebsdb->priv->summary_fields[i].type == G_TYPE_STRING) {
857                         g_string_append (string, ebsdb->priv->summary_fields[i].dbname);
858                         g_string_append (string, " TEXT, ");
859                 } else if (ebsdb->priv->summary_fields[i].type == G_TYPE_BOOLEAN) {
860                         g_string_append (string, ebsdb->priv->summary_fields[i].dbname);
861                         g_string_append (string, " INTEGER, ");
862                 } else if (ebsdb->priv->summary_fields[i].type != E_TYPE_CONTACT_ATTR_LIST)
863                         g_warn_if_reached ();
864
865                 /* Additional columns holding normalized reverse values for suffix matching */
866                 if (ebsdb->priv->summary_fields[i].type == G_TYPE_STRING) {
867                         if (ebsdb->priv->summary_fields[i].index & INDEX_SUFFIX) {
868                                 g_string_append  (string, ebsdb->priv->summary_fields[i].dbname);
869                                 g_string_append  (string, "_reverse TEXT, ");
870                         }
871
872                         if (ebsdb->priv->summary_fields[i].index & INDEX_PHONE) {
873                                 g_string_append  (string, ebsdb->priv->summary_fields[i].dbname);
874                                 g_string_append  (string, "_phone TEXT, ");
875                         }
876                 }
877         }
878         g_string_append (string, "vcard TEXT, bdata TEXT)");
879
880         stmt = sqlite3_mprintf (string->str, folderid);
881         g_string_free (string, TRUE);
882
883         success = book_backend_sql_exec (
884                 ebsdb->priv->db, stmt, NULL, NULL , error);
885
886         sqlite3_free (stmt);
887
888         /* Construct the create statement from the attribute list summary table */
889         if (success && ebsdb->priv->have_attr_list) {
890                 string = g_string_new ("CREATE TABLE IF NOT EXISTS %Q ( uid TEXT NOT NULL REFERENCES %Q(uid), "
891                         "field TEXT, value TEXT");
892
893                 if ((ebsdb->priv->attr_list_indexes & INDEX_SUFFIX) != 0)
894                         g_string_append (string, ", value_reverse TEXT");
895                 if ((ebsdb->priv->attr_list_indexes & INDEX_PHONE) != 0)
896                         g_string_append (string, ", value_phone TEXT");
897
898                 g_string_append_c (string, ')');
899
900                 tmp = g_strdup_printf ("%s_lists", folderid);
901                 stmt = sqlite3_mprintf (string->str, tmp, folderid);
902                 g_string_free (string, TRUE);
903
904                 success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
905                 sqlite3_free (stmt);
906
907                 /* Give the UID an index in this table, always */
908                 stmt = sqlite3_mprintf ("CREATE INDEX IF NOT EXISTS LISTINDEX ON %Q (uid)", tmp);
909                 success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
910                 sqlite3_free (stmt);
911
912                 /* Create indexes if specified */
913                 if (success && (ebsdb->priv->attr_list_indexes & INDEX_PREFIX) != 0) {
914                         stmt = sqlite3_mprintf ("CREATE INDEX IF NOT EXISTS VALINDEX ON %Q (value)", tmp);
915                         success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
916                         sqlite3_free (stmt);
917                 }
918
919                 if (success && (ebsdb->priv->attr_list_indexes & INDEX_SUFFIX) != 0) {
920                         stmt = sqlite3_mprintf ("CREATE INDEX IF NOT EXISTS RVALINDEX ON %Q (value_reverse)", tmp);
921                         success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
922                         sqlite3_free (stmt);
923                 }
924
925                 if (success && (ebsdb->priv->attr_list_indexes & INDEX_PHONE) != 0) {
926                         stmt = sqlite3_mprintf ("CREATE INDEX IF NOT EXISTS PVALINDEX ON %Q (value_phone)", tmp);
927                         success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
928                         sqlite3_free (stmt);
929                 }
930
931                 g_free (tmp);
932         }
933
934         if (success)
935                 success = introspect_summary (ebsdb, folderid, error);
936
937         /* Create indexes on the summary fields configured for indexing */
938         for (i = 0; success && i < ebsdb->priv->n_summary_fields; i++) {
939                 if ((ebsdb->priv->summary_fields[i].index & INDEX_PREFIX) != 0 &&
940                     ebsdb->priv->summary_fields[i].type != E_TYPE_CONTACT_ATTR_LIST) {
941                         /* Derive index name from field & folder */
942                         tmp = g_strdup_printf (
943                                 "INDEX_%s_%s",
944                                 summary_dbname_from_field (ebsdb, ebsdb->priv->summary_fields[i].field),
945                                 folderid);
946                         stmt = sqlite3_mprintf (
947                                 "CREATE INDEX IF NOT EXISTS %Q ON %Q (%s)", tmp, folderid,
948                                                 summary_dbname_from_field (ebsdb, ebsdb->priv->summary_fields[i].field));
949                         success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
950                         sqlite3_free (stmt);
951                         g_free (tmp);
952                 }
953
954                 if (success &&
955                     (ebsdb->priv->summary_fields[i].index & INDEX_SUFFIX) != 0 &&
956                     ebsdb->priv->summary_fields[i].type != E_TYPE_CONTACT_ATTR_LIST) {
957                         /* Derive index name from field & folder */
958                         tmp = g_strdup_printf (
959                                 "RINDEX_%s_%s",
960                                 summary_dbname_from_field (ebsdb, ebsdb->priv->summary_fields[i].field),
961                                 folderid);
962                         stmt = sqlite3_mprintf (
963                                 "CREATE INDEX IF NOT EXISTS %Q ON %Q (%s_reverse)", tmp, folderid,
964                                                 summary_dbname_from_field (ebsdb, ebsdb->priv->summary_fields[i].field));
965                         success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
966                         sqlite3_free (stmt);
967                         g_free (tmp);
968                 }
969
970                 if ((ebsdb->priv->summary_fields[i].index & INDEX_PHONE) != 0 &&
971                     ebsdb->priv->summary_fields[i].type != E_TYPE_CONTACT_ATTR_LIST) {
972                         /* Derive index name from field & folder */
973                         tmp = g_strdup_printf ("PINDEX_%s_%s",
974                                                summary_dbname_from_field (ebsdb, ebsdb->priv->summary_fields[i].field),
975                                                folderid);
976                         stmt = sqlite3_mprintf ("CREATE INDEX IF NOT EXISTS %Q ON %Q (%s_phone)", tmp, folderid,
977                                                 summary_dbname_from_field (ebsdb, ebsdb->priv->summary_fields[i].field));
978                         success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
979                         sqlite3_free (stmt);
980                         g_free (tmp);
981                 }
982         }
983
984         /* Until version 6, the whole contacts table requires a re-normalization of the data */
985         if (success && previous_schema < 6)
986                 success = upgrade_contacts_table (ebsdb, folderid, error);
987
988         return success;
989 }
990
991 typedef struct {
992         sqlite3 *db;
993         const gchar *collation;
994         const gchar *table;
995 } CollationInfo;
996
997 static gint
998 create_phone_indexes_for_columns (gpointer data,
999                                   gint n_cols,
1000                                   gchar **cols,
1001                                   gchar **name)
1002 {
1003         const gchar *column_name = cols[1];
1004         CollationInfo *info = data;
1005
1006         if (g_str_has_suffix (column_name, "_phone")) {
1007                 gchar *index_name, *stmt;
1008                 GError *error = NULL;
1009
1010                 index_name = g_strdup_printf (
1011                         "PINDEX_%s_ON_%s_WITH_%s", column_name, info->table, info->collation);
1012                 stmt = sqlite3_mprintf (
1013                         "CREATE INDEX IF NOT EXISTS %Q ON %Q (%s COLLATE %Q)",
1014                         index_name, info->table, column_name, info->collation);
1015
1016                 if (!book_backend_sql_exec (info->db, stmt, NULL, NULL, &error)) {
1017                         g_warning ("%s: %s", G_STRFUNC, error->message);
1018                         g_error_free (error);
1019                 }
1020
1021                 sqlite3_free (stmt);
1022                 g_free (index_name);
1023         }
1024
1025         return 0;
1026 }
1027
1028 static gint
1029 create_phone_indexes_for_tables (gpointer data,
1030                                  gint n_cols,
1031                                  gchar **cols,
1032                                  gchar **name)
1033 {
1034         CollationInfo *info = data;
1035         GError *error = NULL;
1036         gchar *tmp, *stmt;
1037
1038         info->table = cols[0];
1039         stmt = sqlite3_mprintf ("PRAGMA table_info(%Q)", info->table);
1040
1041         if (!book_backend_sql_exec (
1042                 info->db, stmt, create_phone_indexes_for_columns, info, &error)) {
1043                 g_warning ("%s: %s", G_STRFUNC, error->message);
1044                 g_clear_error (&error);
1045         }
1046
1047         sqlite3_free (stmt);
1048
1049         info->table = tmp = g_strconcat (info->table, "_lists", NULL);
1050         stmt = sqlite3_mprintf ("PRAGMA table_info(%Q)", info->table);
1051
1052         if (!book_backend_sql_exec (
1053                 info->db, stmt, create_phone_indexes_for_columns, info, &error)) {
1054                 g_warning ("%s: %s", G_STRFUNC, error->message);
1055                 g_clear_error (&error);
1056         }
1057
1058         sqlite3_free (stmt);
1059         g_free (tmp);
1060
1061         return 0;
1062 }
1063
1064 static GString *
1065 ixphone_str (gint country_code,
1066              const gchar *const national_str,
1067              gint national_len)
1068 {
1069         GString *const str = g_string_sized_new (6 + national_len);
1070         g_string_append_printf (str, "+%d|", country_code);
1071         g_string_append_len (str, national_str, national_len);
1072         return str;
1073 }
1074
1075 static gint
1076 e_strcmp2n (const gchar *str1,
1077             size_t len1,
1078             const gchar *str2,
1079             size_t len2)
1080 {
1081         const gint cmp = memcmp (str1, str2, MIN (len1, len2));
1082
1083         return (cmp != 0 ? cmp :
1084                 len1 == len2 ? 0 :
1085                 len1 < len2 ? -1 : 1);
1086 }
1087
1088 static gint
1089 ixphone_compare_for_country (gpointer data,
1090                              gint len1,
1091                              gconstpointer arg1,
1092                              gint len2,
1093                              gconstpointer arg2)
1094 {
1095         const gchar *const str1 = arg1;
1096         const gchar *const str2 = arg2;
1097         const gchar *const sep1 = memchr (str1, '|', len1);
1098         const gchar *const sep2 = memchr (str2, '|', len2);
1099         const gint country_code = GPOINTER_TO_INT (data);
1100
1101         g_return_val_if_fail (sep1 != NULL, 0);
1102         g_return_val_if_fail (sep2 != NULL, 0);
1103
1104         if ((str1 == sep1) == (str2 == sep2))
1105                 return e_strcmp2n (str1, len1, str2, len2);
1106
1107         if (str1 == sep1) {
1108                 GString *const tmp = ixphone_str (country_code, str1, len1);
1109                 const gint cmp = e_strcmp2n (tmp->str, tmp->len, str2, len2);
1110                 g_string_free (tmp, TRUE);
1111                 return cmp;
1112         } else {
1113                 GString *const tmp = ixphone_str (country_code, str2, len2);
1114                 const gint cmp = e_strcmp2n (str1, len1, tmp->str, tmp->len);
1115                 g_string_free (tmp, TRUE);
1116                 return cmp;
1117         }
1118 }
1119
1120 static gint
1121 ixphone_compare_national (gpointer data,
1122                           gint len1,
1123                           gconstpointer arg1,
1124                           gint len2,
1125                           gconstpointer arg2)
1126 {
1127         const gchar *const country_code = data;
1128         const gchar *const str1 = arg1;
1129         const gchar *const str2 = arg2;
1130         const gchar *sep1 = memchr (str1, '|', len1);
1131         const gchar *sep2 = memchr (str2, '|', len2);
1132
1133         gint cmp;
1134
1135         g_return_val_if_fail (sep1 != NULL, 0);
1136         g_return_val_if_fail (sep2 != NULL, 0);
1137
1138         /* First only check national portions */
1139         cmp = e_strcmp2n (
1140                 sep1 + 1, len1 - (sep1 + 1 - str1),
1141                 sep2 + 1, len2 - (sep2 + 1 - str2));
1142
1143         /* On match we also have to check for potential country codes.
1144          * Note that we can't just compare the full phone number string
1145          * in the case that both numbers have a country code, because
1146          * this would break the collations sorting order. As a result
1147          * the binary search performed on the index would miss matches.
1148          * Consider the index contains "|2215423789" and "+31|2215423789"
1149          * while we look for "+1|2215423789". By performing full string
1150          * compares in case of fully qualified numbers, we might check
1151          * "+31|2215423789" first and then miss "|2215423789" because
1152          * we traverse the binary tree in wrong direction.
1153          */
1154         if (cmp == 0) {
1155                 if (sep1 == str1) {
1156                         if (sep2 != str2)
1157                                 cmp = e_strcmp2n (country_code, strlen (country_code), str2, sep2 - str2);
1158                 } else if (sep2 == str2) {
1159                         cmp = e_strcmp2n (str1, sep1 - str1, country_code, 2);
1160                 } else {
1161                         /* Also compare the country code if the national number
1162                          * matches and both numbers have a country code. */
1163                         cmp = e_strcmp2n (str1, sep1 - str1, str2, sep2 - str2);
1164                 }
1165         }
1166
1167         if (booksql_debug ()) {
1168                 gchar *const tmp1 = g_strndup (str1, len1);
1169                 gchar *const tmp2 = g_strndup (str2, len2);
1170
1171                 g_printerr
1172                         ("  DEBUG %s('%s', '%s') = %d\n",
1173                          G_STRFUNC, tmp1, tmp2, cmp);
1174
1175                 g_free (tmp2);
1176                 g_free (tmp1);
1177         }
1178
1179         return cmp;
1180 }
1181
1182 static void
1183 create_collation (gpointer data,
1184                   sqlite3 *db,
1185                   gint encoding,
1186                   const gchar *name)
1187 {
1188         gint ret = SQLITE_DONE;
1189         gint country_code;
1190
1191         g_warn_if_fail (encoding == SQLITE_UTF8);
1192
1193         if  (1 == sscanf (name, "ixphone_%d", &country_code)) {
1194                 ret = sqlite3_create_collation (
1195                         db, name, SQLITE_UTF8, GINT_TO_POINTER (country_code),
1196                         ixphone_compare_for_country);
1197         } else if (strcmp (name, "ixphone_national") == 0) {
1198                 country_code = e_phone_number_get_country_code_for_region (NULL, NULL);
1199
1200                 ret = sqlite3_create_collation_v2 (
1201                         db, name, SQLITE_UTF8,
1202                         g_strdup_printf ("+%d", country_code),
1203                         ixphone_compare_national, g_free);
1204         }
1205
1206         if (ret == SQLITE_OK) {
1207                 CollationInfo info = { db, name };
1208                 GError *error = NULL;
1209
1210                 if (!book_backend_sql_exec (
1211                         db, "SELECT folder_id FROM folders",
1212                         create_phone_indexes_for_tables, &info, &error)) {
1213                         g_warning ("%s(%s): %s", G_STRFUNC, name, error->message);
1214                         g_error_free (error);
1215                 }
1216         } else if (ret != SQLITE_DONE) {
1217                 g_warning ("%s(%s): %s", G_STRFUNC, name, sqlite3_errmsg (db));
1218         }
1219 }
1220
1221 static gboolean
1222 book_backend_sqlitedb_load (EBookBackendSqliteDB *ebsdb,
1223                             const gchar *filename,
1224                             gint *previous_schema,
1225                             GError **error)
1226 {
1227         gint ret;
1228
1229         e_sqlite3_vfs_init ();
1230
1231         ret = sqlite3_open (filename, &ebsdb->priv->db);
1232
1233         if (ret == SQLITE_OK)
1234                 ret = sqlite3_collation_needed (ebsdb->priv->db, ebsdb, create_collation);
1235
1236         if (ret != SQLITE_OK) {
1237                 if (!ebsdb->priv->db) {
1238                         g_set_error (
1239                                 error, E_BOOK_SDB_ERROR,
1240                                 E_BOOK_SDB_ERROR_OTHER,
1241                                 _("Insufficient memory"));
1242                 } else {
1243                         const gchar *errmsg;
1244                         errmsg = sqlite3_errmsg (ebsdb->priv->db);
1245                         d (g_printerr ("Can't open database %s: %s\n", path, errmsg));
1246                         g_set_error_literal (
1247                                 error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER, errmsg);
1248                         sqlite3_close (ebsdb->priv->db);
1249                 }
1250                 return FALSE;
1251         }
1252
1253         book_backend_sql_exec (
1254                 ebsdb->priv->db,
1255                 "ATTACH DATABASE ':memory:' AS mem",
1256                 NULL, NULL, NULL);
1257         book_backend_sql_exec (
1258                 ebsdb->priv->db,
1259                 "PRAGMA foreign_keys = ON",
1260                 NULL, NULL, NULL);
1261         book_backend_sql_exec (
1262                 ebsdb->priv->db,
1263                 "PRAGMA case_sensitive_like = ON",
1264                 NULL, NULL, NULL);
1265
1266         return create_folders_table (ebsdb, previous_schema, error);
1267 }
1268
1269 static EBookBackendSqliteDB *
1270 e_book_backend_sqlitedb_new_internal (const gchar *path,
1271                                       const gchar *emailid,
1272                                       const gchar *folderid,
1273                                       const gchar *folder_name,
1274                                       gboolean store_vcard,
1275                                       SummaryField *fields,
1276                                       gint n_fields,
1277                                       gboolean have_attr_list,
1278                                       IndexFlags attr_list_indexes,
1279                                       GError **error)
1280 {
1281         EBookBackendSqliteDB *ebsdb;
1282         gchar *hash_key, *filename;
1283         gint previous_schema = 0;
1284
1285         g_return_val_if_fail (path != NULL, NULL);
1286         g_return_val_if_fail (emailid != NULL, NULL);
1287         g_return_val_if_fail (folderid != NULL, NULL);
1288         g_return_val_if_fail (folder_name != NULL, NULL);
1289
1290         g_mutex_lock (&dbcon_lock);
1291
1292         hash_key = g_strdup_printf ("%s@%s", emailid, path);
1293         if (db_connections != NULL) {
1294                 ebsdb = g_hash_table_lookup (db_connections, hash_key);
1295
1296                 if (ebsdb) {
1297                         g_object_ref (ebsdb);
1298                         g_free (hash_key);
1299                         goto exit;
1300                 }
1301         }
1302
1303         ebsdb = g_object_new (E_TYPE_BOOK_BACKEND_SQLITEDB, NULL);
1304         ebsdb->priv->path = g_strdup (path);
1305         ebsdb->priv->summary_fields = fields;
1306         ebsdb->priv->n_summary_fields = n_fields;
1307         ebsdb->priv->have_attr_list = have_attr_list;
1308         ebsdb->priv->attr_list_indexes = attr_list_indexes;
1309         ebsdb->priv->store_vcard = store_vcard;
1310         if (g_mkdir_with_parents (path, 0777) < 0) {
1311                 g_mutex_unlock (&dbcon_lock);
1312                 g_set_error (
1313                         error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
1314                         "Can not make parent directory: errno %d", errno);
1315                 return NULL;
1316         }
1317         filename = g_build_filename (path, DB_FILENAME, NULL);
1318
1319         if (!book_backend_sqlitedb_load (ebsdb, filename, &previous_schema, error)) {
1320                 g_mutex_unlock (&dbcon_lock);
1321                 g_object_unref (ebsdb);
1322                 g_free (filename);
1323                 return NULL;
1324         }
1325         g_free (filename);
1326
1327         if (db_connections == NULL)
1328                 db_connections = g_hash_table_new_full (
1329                         (GHashFunc) g_str_hash,
1330                         (GEqualFunc) g_str_equal,
1331                         (GDestroyNotify) g_free,
1332                         (GDestroyNotify) NULL);
1333         g_hash_table_insert (db_connections, hash_key, ebsdb);
1334         ebsdb->priv->hash_key = g_strdup (hash_key);
1335
1336  exit:
1337         /* While the global dbcon_lock is held, hold the ebsdb specific lock and
1338          * prolong the locking on that instance until the folders are all set up
1339          */
1340         LOCK_MUTEX (&ebsdb->priv->lock);
1341         g_mutex_unlock (&dbcon_lock);
1342
1343         if (!add_folder_into_db (ebsdb, folderid, folder_name, error)) {
1344                 UNLOCK_MUTEX (&ebsdb->priv->lock);
1345                 g_object_unref (ebsdb);
1346                 return NULL;
1347         }
1348
1349         if (!create_contacts_table (ebsdb, folderid, previous_schema, error)) {
1350                 UNLOCK_MUTEX (&ebsdb->priv->lock);
1351                 g_object_unref (ebsdb);
1352                 return NULL;
1353         }
1354
1355         UNLOCK_MUTEX (&ebsdb->priv->lock);
1356
1357         return ebsdb;
1358 }
1359
1360 static SummaryField *
1361 append_summary_field (GArray *array,
1362                       EContactField field,
1363                       gboolean *have_attr_list,
1364                       GError **error)
1365 {
1366         const gchar *dbname = NULL;
1367         GType        type = G_TYPE_INVALID;
1368         gint         i;
1369         SummaryField new_field = { 0, };
1370
1371         if (field < 1 || field >= E_CONTACT_FIELD_LAST) {
1372                 g_set_error (
1373                         error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
1374                         _("Invalid contact field '%d' specified in summary"), field);
1375                 return NULL;
1376         }
1377
1378         /* Avoid including the same field twice in the summary */
1379         for (i = 0; i < array->len; i++) {
1380                 SummaryField *iter = &g_array_index (array, SummaryField, i);
1381                 if (field == iter->field)
1382                         return iter;
1383         }
1384
1385         /* Resolve some exceptions, we store these
1386          * specific contact fields with different names
1387          * than those found in the EContactField table
1388          */
1389         switch (field) {
1390         case E_CONTACT_UID:
1391                 dbname = "uid";
1392                 break;
1393         case E_CONTACT_IS_LIST:
1394                 dbname = "is_list";
1395                 break;
1396         default:
1397                 dbname = e_contact_field_name (field);
1398                 break;
1399         }
1400
1401         type = e_contact_field_type (field);
1402
1403         if (type != G_TYPE_STRING &&
1404             type != G_TYPE_BOOLEAN &&
1405             type != E_TYPE_CONTACT_ATTR_LIST) {
1406                 g_set_error (
1407                         error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
1408                         _("Contact field '%s' of type '%s' specified in summary, "
1409                         "but only boolean, string and string list field types are supported"),
1410                         e_contact_pretty_name (field), g_type_name (type));
1411                 return NULL;
1412         }
1413
1414         if (type == E_TYPE_CONTACT_ATTR_LIST && have_attr_list)
1415                 *have_attr_list = TRUE;
1416
1417         new_field.field  = field;
1418         new_field.dbname = dbname;
1419         new_field.type   = type;
1420         new_field.index  = 0;
1421         g_array_append_val (array, new_field);
1422
1423         return &g_array_index (array, SummaryField, array->len - 1);
1424 }
1425
1426 static void
1427 summary_fields_add_indexes (GArray *array,
1428                             EContactField *indexes,
1429                             EBookIndexType *index_types,
1430                             gint n_indexes,
1431                             IndexFlags *attr_list_indexes)
1432 {
1433         gint i, j;
1434
1435         for (i = 0; i < array->len; i++) {
1436                 SummaryField *sfield = &g_array_index (array, SummaryField, i);
1437
1438                 for (j = 0; j < n_indexes; j++) {
1439                         if (sfield->field == indexes[j]) {
1440                                 switch (index_types[j]) {
1441                                 case E_BOOK_INDEX_PREFIX:
1442                                         sfield->index |= INDEX_PREFIX;
1443
1444                                         if (sfield->type == E_TYPE_CONTACT_ATTR_LIST)
1445                                                 *attr_list_indexes |= INDEX_PREFIX;
1446                                         break;
1447                                 case E_BOOK_INDEX_SUFFIX:
1448                                         sfield->index |= INDEX_SUFFIX;
1449
1450                                         if (sfield->type == E_TYPE_CONTACT_ATTR_LIST)
1451                                                 *attr_list_indexes |= INDEX_SUFFIX;
1452                                         break;
1453                                 case E_BOOK_INDEX_PHONE:
1454                                         sfield->index |= INDEX_PHONE;
1455
1456                                         if (sfield->type == E_TYPE_CONTACT_ATTR_LIST)
1457                                                 *attr_list_indexes |= INDEX_PHONE;
1458                                         break;
1459                                 default:
1460                                         g_warn_if_reached ();
1461                                         break;
1462                                 }
1463                         }
1464                 }
1465         }
1466 }
1467
1468 /**
1469  * e_book_backend_sqlitedb_new_full:
1470  * @path: location where the db would be created
1471  * @emailid: email id of the user
1472  * @folderid: folder id of the address-book
1473  * @folder_name: name of the address-book
1474  * @store_vcard: True if the vcard should be stored inside db, if FALSE only the summary fields would be stored inside db.
1475  * @setup: an #ESourceBackendSummarySetup describing how the summary should be setup
1476  * @error: A location to store any error that may have occurred
1477  *
1478  * Like e_book_backend_sqlitedb_new(), but allows configuration of which contact fields
1479  * will be stored for quick reference in the summary. The configuration indicated by
1480  * @setup will only be taken into account when initially creating the underlying table,
1481  * further configurations will be ignored.
1482  *
1483  * The fields %E_CONTACT_UID and %E_CONTACT_REV are not optional,
1484  * they will be stored in the summary regardless of this function's parameters
1485  *
1486  * <note><para>Only #EContactFields with the type #G_TYPE_STRING, #G_TYPE_BOOLEAN or
1487  * #E_TYPE_CONTACT_ATTR_LIST are currently supported.</para></note>
1488  *
1489  * Returns: (transfer full): The newly created #EBookBackendSqliteDB
1490  *
1491  * Since: 3.8
1492  **/
1493 EBookBackendSqliteDB *
1494 e_book_backend_sqlitedb_new_full (const gchar *path,
1495                                   const gchar *emailid,
1496                                   const gchar *folderid,
1497                                   const gchar *folder_name,
1498                                   gboolean store_vcard,
1499                                   ESourceBackendSummarySetup *setup,
1500                                   GError **error)
1501 {
1502         EBookBackendSqliteDB *ebsdb = NULL;
1503         EContactField *fields;
1504         EContactField *indexed_fields;
1505         EBookIndexType *index_types = NULL;
1506         gboolean have_attr_list = FALSE;
1507         IndexFlags attr_list_indexes = 0;
1508         gboolean had_error = FALSE;
1509         GArray *summary_fields;
1510         gint n_fields = 0, n_indexed_fields = 0, i;
1511
1512         fields         = e_source_backend_summary_setup_get_summary_fields (setup, &n_fields);
1513         indexed_fields = e_source_backend_summary_setup_get_indexed_fields (setup, &index_types, &n_indexed_fields);
1514
1515         /* No specified summary fields indicates the default summary configuration should be used */
1516         if (n_fields <= 0) {
1517                 ebsdb = e_book_backend_sqlitedb_new (path, emailid, folderid, folder_name, store_vcard, error);
1518                 g_free (fields);
1519                 g_free (index_types);
1520                 g_free (indexed_fields);
1521
1522                 return ebsdb;
1523         }
1524
1525         summary_fields = g_array_new (FALSE, FALSE, sizeof (SummaryField));
1526
1527         /* Ensure the non-optional fields first */
1528         append_summary_field (summary_fields, E_CONTACT_UID, &have_attr_list, error);
1529         append_summary_field (summary_fields, E_CONTACT_REV, &have_attr_list, error);
1530
1531         for (i = 0; i < n_fields; i++) {
1532                 if (!append_summary_field (summary_fields, fields[i], &have_attr_list, error)) {
1533                         had_error = TRUE;
1534                         break;
1535                 }
1536         }
1537
1538         if (had_error) {
1539                 g_array_free (summary_fields, TRUE);
1540                 g_free (fields);
1541                 g_free (index_types);
1542                 g_free (indexed_fields);
1543                 return NULL;
1544         }
1545
1546         /* Add the 'indexed' flag to the SummaryField structs */
1547         summary_fields_add_indexes (
1548                 summary_fields, indexed_fields, index_types, n_indexed_fields,
1549                 &attr_list_indexes);
1550
1551         ebsdb = e_book_backend_sqlitedb_new_internal (
1552                 path, emailid, folderid, folder_name,
1553                 store_vcard,
1554                 (SummaryField *) summary_fields->data,
1555                 summary_fields->len,
1556                 have_attr_list,
1557                 attr_list_indexes,
1558                 error);
1559
1560         g_free (fields);
1561         g_free (index_types);
1562         g_free (indexed_fields);
1563         g_array_free (summary_fields, FALSE);
1564
1565         return ebsdb;
1566 }
1567
1568 /**
1569  * e_book_backend_sqlitedb_new
1570  * @path: location where the db would be created
1571  * @emailid: email id of the user
1572  * @folderid: folder id of the address-book
1573  * @folder_name: name of the address-book
1574  * @store_vcard: True if the vcard should be stored inside db, if FALSE only the summary fields would be stored inside db.
1575  * @error:
1576  *
1577  * If the path for multiple addressbooks are same, the contacts from all addressbooks
1578  * would be stored in same db in different tables.
1579  *
1580  * Returns:
1581  *
1582  * Since: 3.2
1583  **/
1584 EBookBackendSqliteDB *
1585 e_book_backend_sqlitedb_new (const gchar *path,
1586                              const gchar *emailid,
1587                              const gchar *folderid,
1588                              const gchar *folder_name,
1589                              gboolean store_vcard,
1590                              GError **error)
1591 {
1592         EBookBackendSqliteDB *ebsdb;
1593         GArray *summary_fields;
1594         gboolean have_attr_list = FALSE;
1595         IndexFlags attr_list_indexes = 0;
1596         gint i;
1597
1598         /* Create the default summary structs */
1599         summary_fields = g_array_new (FALSE, FALSE, sizeof (SummaryField));
1600         for (i = 0; i < G_N_ELEMENTS (default_summary_fields); i++)
1601                 append_summary_field (summary_fields, default_summary_fields[i], &have_attr_list, NULL);
1602
1603         /* Add the default index flags */
1604         summary_fields_add_indexes (
1605                 summary_fields,
1606                 default_indexed_fields,
1607                 default_index_types,
1608                 G_N_ELEMENTS (default_indexed_fields),
1609                 &attr_list_indexes);
1610
1611         ebsdb = e_book_backend_sqlitedb_new_internal (
1612                 path, emailid, folderid, folder_name,
1613                 store_vcard,
1614                 (SummaryField *) summary_fields->data,
1615                 summary_fields->len,
1616                 have_attr_list,
1617                 attr_list_indexes,
1618                 error);
1619
1620         g_array_free (summary_fields, FALSE);
1621
1622         return ebsdb;
1623 }
1624
1625 gboolean
1626 e_book_backend_sqlitedb_lock_updates (EBookBackendSqliteDB *ebsdb,
1627                                       GError **error)
1628 {
1629         gboolean success;
1630
1631         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
1632
1633         LOCK_MUTEX (&ebsdb->priv->updates_lock);
1634
1635         LOCK_MUTEX (&ebsdb->priv->lock);
1636         success = book_backend_sqlitedb_start_transaction (ebsdb, error);
1637         UNLOCK_MUTEX (&ebsdb->priv->lock);
1638
1639         return success;
1640 }
1641
1642 gboolean
1643 e_book_backend_sqlitedb_unlock_updates (EBookBackendSqliteDB *ebsdb,
1644                                         gboolean do_commit,
1645                                         GError **error)
1646 {
1647         gboolean success;
1648
1649         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
1650
1651         LOCK_MUTEX (&ebsdb->priv->lock);
1652         success = do_commit ?
1653                 book_backend_sqlitedb_commit_transaction (ebsdb, error) :
1654                 book_backend_sqlitedb_rollback_transaction (ebsdb, error);
1655         UNLOCK_MUTEX (&ebsdb->priv->lock);
1656
1657         UNLOCK_MUTEX (&ebsdb->priv->updates_lock);
1658
1659         return success;
1660 }
1661
1662 static gchar *
1663 mprintf_suffix (const gchar *normal)
1664 {
1665         gchar *reverse = normal ? g_utf8_strreverse (normal, -1) : NULL;
1666         gchar *stmt = sqlite3_mprintf ("%Q", reverse);
1667
1668         g_free (reverse);
1669         return stmt;
1670 }
1671
1672 static EPhoneNumber *
1673 phone_number_from_string (const gchar *normal,
1674                           const gchar *default_region)
1675 {
1676         EPhoneNumber *number = NULL;
1677
1678         /* Don't warn about erronous phone number strings, it's a perfectly normal
1679          * use case for users to enter notes instead of phone numbers in the phone
1680          * number contact fields, such as "Ask Jenny for Lisa's phone number"
1681          */
1682         if (normal && e_phone_number_is_supported ())
1683                 number = e_phone_number_from_string (normal, default_region, NULL);
1684
1685         return number;
1686 }
1687
1688 static gchar *
1689 convert_phone (const gchar *normal,
1690                const gchar *default_region)
1691 {
1692         EPhoneNumber *number = phone_number_from_string (normal, default_region);
1693         gchar *indexed_phone_number = NULL;
1694         gchar *national_number = NULL;
1695         gint country_code = 0;
1696
1697         if (number) {
1698                 EPhoneNumberCountrySource source;
1699
1700                 national_number = e_phone_number_get_national_number (number);
1701                 country_code = e_phone_number_get_country_code (number, &source);
1702                 e_phone_number_free (number);
1703
1704                 if (source == E_PHONE_NUMBER_COUNTRY_FROM_DEFAULT)
1705                         country_code = 0;
1706         }
1707
1708         if (national_number) {
1709                 indexed_phone_number = country_code
1710                         ? g_strdup_printf ("+%d|%s", country_code, national_number)
1711                         : g_strconcat ("|", national_number, NULL);
1712
1713                 g_free (national_number);
1714         }
1715
1716         return indexed_phone_number;
1717 }
1718
1719 static gchar *
1720 mprintf_phone (const gchar *normal,
1721                const gchar *default_region)
1722 {
1723         gchar *phone = convert_phone (normal, default_region);
1724         gchar *stmt = NULL;
1725
1726         if (phone) {
1727                 stmt = sqlite3_mprintf ("%Q", phone);
1728                 g_free (phone);
1729         }
1730
1731         return stmt;
1732 }
1733
1734 /* Add Contact (free the result with g_free() ) */
1735 static gchar *
1736 insert_stmt_from_contact (EBookBackendSqliteDB *ebsdb,
1737                           EContact *contact,
1738                           const gchar *folderid,
1739                           gboolean store_vcard,
1740                           gboolean replace_existing,
1741                           const gchar *default_region)
1742 {
1743         GString *string;
1744         gchar *str, *vcard_str;
1745         gint i;
1746
1747         str = sqlite3_mprintf (
1748                 "INSERT or %s INTO %Q VALUES (",
1749                 replace_existing ? "REPLACE" : "FAIL", folderid);
1750         string = g_string_new (str);
1751         sqlite3_free (str);
1752
1753         for (i = 0; i < ebsdb->priv->n_summary_fields; i++) {
1754                 if (ebsdb->priv->summary_fields[i].type == G_TYPE_STRING) {
1755                         gchar *val;
1756                         gchar *normal;
1757
1758                         if (i > 0)
1759                                 g_string_append (string, ", ");
1760
1761                         val = e_contact_get (contact, ebsdb->priv->summary_fields[i].field);
1762
1763                         /* Special exception, never normalize the UID or REV string */
1764                         if (ebsdb->priv->summary_fields[i].field != E_CONTACT_UID &&
1765                             ebsdb->priv->summary_fields[i].field != E_CONTACT_REV)
1766                                 normal = e_util_utf8_normalize (val);
1767                         else
1768                                 normal = g_strdup (val);
1769
1770                         str = sqlite3_mprintf ("%Q", normal);
1771                         g_string_append (string, str);
1772                         sqlite3_free (str);
1773
1774                         if ((ebsdb->priv->summary_fields[i].index & INDEX_SUFFIX) != 0) {
1775                                 str = mprintf_suffix (normal);
1776                                 g_string_append (string, ", ");
1777                                 g_string_append (string, str);
1778                                 sqlite3_free (str);
1779                         }
1780
1781                         if ((ebsdb->priv->summary_fields[i].index & INDEX_PHONE) != 0) {
1782                                 str = mprintf_phone (normal, default_region);
1783                                 g_string_append (string, ", ");
1784                                 g_string_append (string, str ? str : "NULL");
1785                                 sqlite3_free (str);
1786                         }
1787
1788                         g_free (normal);
1789                         g_free (val);
1790                 } else if (ebsdb->priv->summary_fields[i].type == G_TYPE_BOOLEAN) {
1791                         gboolean val;
1792
1793                         if (i > 0)
1794                                 g_string_append (string, ", ");
1795
1796                         val = e_contact_get (contact, ebsdb->priv->summary_fields[i].field) ? TRUE : FALSE;
1797                         g_string_append_printf (string, "%d", val ? 1 : 0);
1798
1799                 } else if (ebsdb->priv->summary_fields[i].type != E_TYPE_CONTACT_ATTR_LIST)
1800                         g_warn_if_reached ();
1801         }
1802
1803         vcard_str = store_vcard ? e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30) : NULL;
1804         str = sqlite3_mprintf (", %Q, %Q)", vcard_str, NULL);
1805
1806         g_string_append (string, str);
1807
1808         sqlite3_free (str);
1809         g_free (vcard_str);
1810
1811         return g_string_free (string, FALSE);
1812 }
1813
1814 static void
1815 update_e164_attribute_params (EVCard *vcard,
1816                               const gchar *default_region)
1817 {
1818         GList *attr_list;
1819
1820         for (attr_list = e_vcard_get_attributes (vcard); attr_list; attr_list = attr_list->next) {
1821                 EVCardAttribute *const attr = attr_list->data;
1822                 EVCardAttributeParam *param = NULL;
1823                 gchar *e164 = NULL, *cc, *nn;
1824                 GList *param_list, *values;
1825
1826                 /* We only attach E164 parameters to TEL attributes. */
1827                 if (strcmp (e_vcard_attribute_get_name (attr), EVC_TEL) != 0)
1828                         continue;
1829
1830                 /* Compute E164 number. */
1831                 values = e_vcard_attribute_get_values (attr);
1832
1833                 e164 = values && values->data
1834                         ? convert_phone (values->data, default_region)
1835                         : NULL;
1836
1837                 if (e164 == NULL) {
1838                         e_vcard_attribute_remove_param (attr, EVC_X_E164);
1839                         continue;
1840                 }
1841
1842                 /* Find already exisiting parameter, so that we can reuse it. */
1843                 for (param_list = e_vcard_attribute_get_params (attr); param_list; param_list = param_list->next) {
1844                         if (strcmp (e_vcard_attribute_param_get_name (param_list->data), EVC_X_E164) == 0) {
1845                                 param = param_list->data;
1846                                 break;
1847                         }
1848                 }
1849
1850                 /* Create a new parameter instance if needed. Otherwise clean
1851                  * the existing parameter's values: This is much cheaper than
1852                  * checking for modifications. */
1853                 if (param == NULL) {
1854                         param = e_vcard_attribute_param_new (EVC_X_E164);
1855                         e_vcard_attribute_add_param (attr, param);
1856                 } else {
1857                         e_vcard_attribute_param_remove_values (param);
1858                 }
1859
1860                 /* Split the phone number into country calling code and
1861                  * national number code. */
1862                 nn = strchr (e164, '|');
1863
1864                 if (nn == NULL) {
1865                         g_warn_if_reached ();
1866                         continue;
1867                 }
1868
1869                 *nn++ = '\0';
1870                 cc = e164;
1871
1872                 /* Assign the parameter values. It seems odd that we revert
1873                  * the order of NN and CC, but at least EVCard's parser doesn't
1874                  * permit an empty first param value. Which of course could be
1875                  * fixed - in order to create a nice potential IOP problem with
1876                  ** other vCard parsers. */
1877                 e_vcard_attribute_param_add_values (param, nn, cc, NULL);
1878
1879                 g_free (e164);
1880         }
1881 }
1882
1883 static gboolean
1884 insert_contact (EBookBackendSqliteDB *ebsdb,
1885                 EContact *contact,
1886                 const gchar *folderid,
1887                 gboolean replace_existing,
1888                 const gchar *default_region,
1889                 GError **error)
1890 {
1891         EBookBackendSqliteDBPrivate *priv;
1892         gboolean success;
1893         gchar *stmt;
1894
1895         priv = ebsdb->priv;
1896
1897         /* Update E.164 parameters in vcard if needed */
1898         if (priv->store_vcard)
1899                 update_e164_attribute_params (E_VCARD (contact), default_region);
1900
1901         /* Update main summary table */
1902         stmt = insert_stmt_from_contact (ebsdb, contact, folderid, priv->store_vcard, replace_existing, default_region);
1903         success = book_backend_sql_exec (priv->db, stmt, NULL, NULL, error);
1904         g_free (stmt);
1905
1906         /* Update attribute list table */
1907         if (success && priv->have_attr_list) {
1908                 gchar *list_folder = g_strdup_printf ("%s_lists", folderid);
1909                 gchar *uid;
1910                 gint   i;
1911                 GList *values, *l;
1912
1913                 /* First remove all entries for this UID */
1914                 uid = e_contact_get (contact, E_CONTACT_UID);
1915                 stmt = sqlite3_mprintf ("DELETE FROM %Q WHERE uid = %Q", list_folder, uid);
1916                 success = book_backend_sql_exec (priv->db, stmt, NULL, NULL, error);
1917                 sqlite3_free (stmt);
1918
1919                 for (i = 0; success && i < priv->n_summary_fields; i++) {
1920                         if (priv->summary_fields[i].type != E_TYPE_CONTACT_ATTR_LIST)
1921                                 continue;
1922
1923                         values = e_contact_get (contact, priv->summary_fields[i].field);
1924
1925                         for (l = values; success && l != NULL; l = l->next) {
1926                                 gchar *value = (gchar *) l->data;
1927                                 gchar *normal = e_util_utf8_normalize (value);
1928                                 gchar *stmt_suffix = NULL;
1929                                 gchar *stmt_phone = NULL;
1930
1931                                 if ((priv->attr_list_indexes & INDEX_SUFFIX) != 0
1932                                         && (priv->summary_fields[i].index & INDEX_SUFFIX) != 0)
1933                                         stmt_suffix = mprintf_suffix (normal);
1934
1935                                 if ((priv->attr_list_indexes & INDEX_PHONE) != 0
1936                                         && (priv->summary_fields[i].index & INDEX_PHONE) != 0)
1937                                         stmt_phone = mprintf_phone (normal, default_region);
1938
1939                                 stmt = sqlite3_mprintf (
1940                                         "INSERT INTO %Q (uid, field, value%s%s) "
1941                                         "VALUES (%Q, %Q, %Q%s%s%s%s)",
1942                                         list_folder,
1943                                         stmt_suffix ? ", value_reverse" : "",
1944                                         stmt_phone ? ", value_phone" : "",
1945                                         uid, priv->summary_fields[i].dbname, normal,
1946                                         stmt_suffix ? ", " : "",
1947                                         stmt_suffix ? stmt_suffix : "",
1948                                         stmt_phone ? ", " : "",
1949                                         stmt_phone ? stmt_phone : "");
1950
1951                                 if (stmt_suffix)
1952                                         sqlite3_free (stmt_suffix);
1953                                 if (stmt_phone)
1954                                         sqlite3_free (stmt_phone);
1955
1956                                 success = book_backend_sql_exec (priv->db, stmt, NULL, NULL, error);
1957                                 sqlite3_free (stmt);
1958                                 g_free (normal);
1959                         }
1960
1961                         /* Free the list of allocated strings */
1962                         e_contact_attr_list_free (values);
1963                 }
1964
1965                 g_free (list_folder);
1966                 g_free (uid);
1967         }
1968
1969         return success;
1970 }
1971
1972 /**
1973  * e_book_backend_sqlitedb_new_contact
1974  * @ebsdb: An #EBookBackendSqliteDB
1975  * @folderid: folder id
1976  * @contact: EContact to be added
1977  * @replace_existing: Whether this contact should replace another contact with the same UID.
1978  * @error: A location to store any error that may have occurred.
1979  *
1980  * This is a convenience wrapper for e_book_backend_sqlitedb_new_contacts,
1981  * which is the preferred means to add or modify multiple contacts when possible.
1982  *
1983  * Returns: TRUE on success.
1984  *
1985  * Since: 3.8
1986  **/
1987 gboolean
1988 e_book_backend_sqlitedb_new_contact (EBookBackendSqliteDB *ebsdb,
1989                                      const gchar *folderid,
1990                                      EContact *contact,
1991                                      gboolean replace_existing,
1992                                      GError **error)
1993 {
1994         GSList l;
1995
1996         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
1997         g_return_val_if_fail (folderid != NULL, FALSE);
1998         g_return_val_if_fail (E_IS_CONTACT (contact), FALSE);
1999
2000         l.data = contact;
2001         l.next = NULL;
2002
2003         return e_book_backend_sqlitedb_new_contacts (
2004                 ebsdb, folderid, &l,
2005                 replace_existing, error);
2006 }
2007
2008 /**
2009  * e_book_backend_sqlitedb_new_contacts
2010  * @ebsdb: An #EBookBackendSqliteDB
2011  * @folderid: folder id
2012  * @contacts: list of EContacts
2013  * @replace_existing: Whether this contact should replace another contact with the same UID.
2014  * @error: A location to store any error that may have occurred.
2015  *
2016  * Adds or replaces contacts in @ebsdb. If @replace_existing is specified then existing
2017  * contacts with the same UID will be replaced, otherwise adding an existing contact
2018  * will return an error.
2019  *
2020  * Returns: TRUE on success.
2021  *
2022  * Since: 3.8
2023  **/
2024 gboolean
2025 e_book_backend_sqlitedb_new_contacts (EBookBackendSqliteDB *ebsdb,
2026                                       const gchar *folderid,
2027                                       GSList *contacts,
2028                                       gboolean replace_existing,
2029                                       GError **error)
2030 {
2031         GSList *l;
2032         gboolean success = TRUE;
2033         gchar *default_region = NULL;
2034
2035         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
2036         g_return_val_if_fail (folderid != NULL, FALSE);
2037         g_return_val_if_fail (contacts != NULL, FALSE);
2038
2039         LOCK_MUTEX (&ebsdb->priv->lock);
2040
2041         if (!book_backend_sqlitedb_start_transaction (ebsdb, error)) {
2042                 UNLOCK_MUTEX (&ebsdb->priv->lock);
2043                 return FALSE;
2044         }
2045
2046         if (e_phone_number_is_supported ()) {
2047                 default_region = e_phone_number_get_default_region (error);
2048
2049                 if (default_region == NULL)
2050                         success = FALSE;
2051         }
2052
2053         for (l = contacts; success && l != NULL; l = g_slist_next (l)) {
2054                 EContact *contact = (EContact *) l->data;
2055
2056                 success = insert_contact (
2057                         ebsdb, contact, folderid, replace_existing,
2058                         default_region, error);
2059         }
2060
2061         g_free (default_region);
2062
2063         if (success)
2064                 success = book_backend_sqlitedb_commit_transaction (ebsdb, error);
2065         else
2066                 /* The GError is already set. */
2067                 book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
2068
2069         UNLOCK_MUTEX (&ebsdb->priv->lock);
2070
2071         return success;
2072 }
2073
2074 /**
2075  * e_book_backend_sqlitedb_add_contact
2076  * @ebsdb:
2077  * @folderid: folder id
2078  * @contact: EContact to be added
2079  * @partial_content: contact does not contain full information. Used when
2080  * the backend cache's partial information for auto-completion.
2081  * @error:
2082  *
2083  * This is a convenience wrapper for e_book_backend_sqlitedb_add_contacts,
2084  * which is the preferred means to add multiple contacts when possible.
2085  *
2086  * Returns: TRUE on success.
2087  *
2088  * Since: 3.2
2089  *
2090  * Deprecated: 3.8: Use e_book_backend_sqlitedb_new_contact() instead.
2091  **/
2092 gboolean
2093 e_book_backend_sqlitedb_add_contact (EBookBackendSqliteDB *ebsdb,
2094                                      const gchar *folderid,
2095                                      EContact *contact,
2096                                      gboolean partial_content,
2097                                      GError **error)
2098 {
2099         return e_book_backend_sqlitedb_new_contact (ebsdb, folderid, contact, TRUE, error);
2100 }
2101
2102 /**
2103  * e_book_backend_sqlitedb_add_contacts
2104  * @ebsdb:
2105  * @folderid: folder id
2106  * @contacts: list of EContacts
2107  * @partial_content: contact does not contain full information. Used when
2108  * the backend cache's partial information for auto-completion.
2109  * @error:
2110  *
2111  *
2112  * Returns: TRUE on success.
2113  *
2114  * Since: 3.2
2115  *
2116  * Deprecated: 3.8: Use e_book_backend_sqlitedb_new_contacts() instead.
2117  **/
2118 gboolean
2119 e_book_backend_sqlitedb_add_contacts (EBookBackendSqliteDB *ebsdb,
2120                                       const gchar *folderid,
2121                                       GSList *contacts,
2122                                       gboolean partial_content,
2123                                       GError **error)
2124 {
2125         return e_book_backend_sqlitedb_new_contacts (ebsdb, folderid, contacts, TRUE, error);
2126 }
2127
2128 /**
2129  * e_book_backend_sqlitedb_remove_contact:
2130  *
2131  * FIXME: Document me.
2132  *
2133  * Since: 3.2
2134  **/
2135 gboolean
2136 e_book_backend_sqlitedb_remove_contact (EBookBackendSqliteDB *ebsdb,
2137                                         const gchar *folderid,
2138                                         const gchar *uid,
2139                                         GError **error)
2140 {
2141         GSList l;
2142
2143         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
2144         g_return_val_if_fail (folderid != NULL, FALSE);
2145         g_return_val_if_fail (uid != NULL, FALSE);
2146
2147         l.data = (gchar *) uid; /* Won't modify it, I promise :) */
2148         l.next = NULL;
2149
2150         return e_book_backend_sqlitedb_remove_contacts (
2151                 ebsdb, folderid, &l, error);
2152 }
2153
2154 static gchar *
2155 generate_uid_list_for_stmt (GSList *uids)
2156 {
2157         GString *str = g_string_new (NULL);
2158         GSList  *l;
2159         gboolean first = TRUE;
2160
2161         for (l = uids; l; l = l->next) {
2162                 gchar *uid = (gchar *) l->data;
2163                 gchar *tmp;
2164
2165                 /* First uid with no comma */
2166                 if (!first)
2167                         g_string_append_printf (str, ", ");
2168                 else
2169                         first = FALSE;
2170
2171                 tmp = sqlite3_mprintf ("%Q", uid);
2172                 g_string_append (str, tmp);
2173                 sqlite3_free (tmp);
2174         }
2175
2176         return g_string_free (str, FALSE);
2177 }
2178
2179 static gchar *
2180 generate_delete_stmt (const gchar *table,
2181                       GSList *uids)
2182 {
2183         GString *str = g_string_new (NULL);
2184         gchar *tmp;
2185
2186         tmp = sqlite3_mprintf ("DELETE FROM %Q WHERE uid IN (", table);
2187         g_string_append (str, tmp);
2188         sqlite3_free (tmp);
2189
2190         tmp = generate_uid_list_for_stmt (uids);
2191         g_string_append (str, tmp);
2192         g_free (tmp);
2193         g_string_append_c (str, ')');
2194
2195         return g_string_free (str, FALSE);
2196 }
2197
2198 /**
2199  * e_book_backend_sqlitedb_remove_contacts:
2200  *
2201  * FIXME: Document me.
2202  *
2203  * Since: 3.2
2204  **/
2205 gboolean
2206 e_book_backend_sqlitedb_remove_contacts (EBookBackendSqliteDB *ebsdb,
2207                                          const gchar *folderid,
2208                                          GSList *uids,
2209                                          GError **error)
2210 {
2211         gboolean success = TRUE;
2212         gchar *stmt;
2213
2214         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
2215         g_return_val_if_fail (folderid != NULL, FALSE);
2216         g_return_val_if_fail (uids != NULL, FALSE);
2217
2218         LOCK_MUTEX (&ebsdb->priv->lock);
2219
2220         if (!book_backend_sqlitedb_start_transaction (ebsdb, error)) {
2221                 UNLOCK_MUTEX (&ebsdb->priv->lock);
2222                 return FALSE;
2223         }
2224
2225         /* Delete the auxillary contact infos first */
2226         if (success && ebsdb->priv->have_attr_list) {
2227                 gchar *lists_folder = g_strdup_printf ("%s_lists", folderid);
2228
2229                 stmt = generate_delete_stmt (lists_folder, uids);
2230                 g_free (lists_folder);
2231
2232                 success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
2233                 g_free (stmt);
2234         }
2235
2236         if (success) {
2237                 stmt = generate_delete_stmt (folderid, uids);
2238                 success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
2239                 g_free (stmt);
2240         }
2241
2242         if (success)
2243                 success = book_backend_sqlitedb_commit_transaction (ebsdb, error);
2244         else
2245                 /* The GError is already set. */
2246                 book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
2247
2248         UNLOCK_MUTEX (&ebsdb->priv->lock);
2249
2250         return success;
2251 }
2252
2253 struct _contact_info {
2254         gboolean exists;
2255         gboolean partial_content;
2256 };
2257
2258 static gint
2259 contact_found_cb (gpointer ref,
2260                   gint col,
2261                   gchar **cols,
2262                   gchar **name)
2263 {
2264         struct _contact_info *cinfo = ref;
2265
2266         cinfo->exists = TRUE;
2267         cinfo->partial_content = cols[0] ? strtoul (cols[0], NULL, 10) : 0;
2268
2269         return 0;
2270 }
2271
2272 /**
2273  * e_book_backend_sqlitedb_has_contact:
2274  *
2275  * FIXME: Document me.
2276  *
2277  * Since: 3.2
2278  **/
2279 gboolean
2280 e_book_backend_sqlitedb_has_contact (EBookBackendSqliteDB *ebsdb,
2281                                      const gchar *folderid,
2282                                      const gchar *uid,
2283                                      gboolean *partial_content,
2284                                      GError **error)
2285 {
2286         struct _contact_info cinfo;
2287         gboolean success;
2288         gchar *stmt;
2289
2290         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
2291         g_return_val_if_fail (folderid != NULL, FALSE);
2292         g_return_val_if_fail (uid != NULL, FALSE);
2293
2294         cinfo.exists = FALSE;
2295         cinfo.partial_content = FALSE;
2296
2297         LOCK_MUTEX (&ebsdb->priv->lock);
2298
2299         stmt = sqlite3_mprintf (
2300                 "SELECT partial_content FROM %Q WHERE uid = %Q",
2301                 folderid, uid);
2302         success = book_backend_sql_exec (
2303                 ebsdb->priv->db, stmt, contact_found_cb , &cinfo, error);
2304         sqlite3_free (stmt);
2305
2306         if (success)
2307                 *partial_content = cinfo.partial_content;
2308
2309         UNLOCK_MUTEX (&ebsdb->priv->lock);
2310
2311         /* FIXME Returning FALSE can mean either "contact not found" or
2312          *       "error occurred".  Add a boolean (out) "exists" parameter. */
2313         return success && cinfo.exists;
2314 }
2315
2316 static gint
2317 get_vcard_cb (gpointer ref,
2318               gint col,
2319               gchar **cols,
2320               gchar **name)
2321 {
2322         gchar **vcard_str = ref;
2323
2324         if (cols[0])
2325                 *vcard_str = g_strdup (cols [0]);
2326
2327         return 0;
2328 }
2329
2330 /**
2331  * e_book_backend_sqlitedb_get_contact:
2332  *
2333  * FIXME: Document me.
2334  *
2335  * Since: 3.2
2336  **/
2337 EContact *
2338 e_book_backend_sqlitedb_get_contact (EBookBackendSqliteDB *ebsdb,
2339                                      const gchar *folderid,
2340                                      const gchar *uid,
2341                                      GHashTable *fields_of_interest,
2342                                      gboolean *with_all_required_fields,
2343                                      GError **error)
2344 {
2345         EContact *contact = NULL;
2346         gchar *vcard;
2347
2348         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
2349         g_return_val_if_fail (folderid != NULL, NULL);
2350         g_return_val_if_fail (uid != NULL, NULL);
2351
2352         vcard = e_book_backend_sqlitedb_get_vcard_string (
2353                 ebsdb, folderid, uid,
2354                 fields_of_interest, with_all_required_fields, error);
2355
2356         if (vcard != NULL) {
2357                 contact = e_contact_new_from_vcard_with_uid (vcard, uid);
2358                 g_free (vcard);
2359         }
2360
2361         return contact;
2362 }
2363
2364 static gboolean
2365 uid_rev_fields (GHashTable *fields_of_interest)
2366 {
2367         GHashTableIter iter;
2368         gpointer key, value;
2369
2370         if (!fields_of_interest || g_hash_table_size (fields_of_interest) > 2)
2371                 return FALSE;
2372
2373         g_hash_table_iter_init (&iter, fields_of_interest);
2374         while (g_hash_table_iter_next (&iter, &key, &value)) {
2375                 const gchar *field_name = key;
2376                 EContactField field = e_contact_field_id (field_name);
2377
2378                 if (field != E_CONTACT_UID &&
2379                     field != E_CONTACT_REV)
2380                         return FALSE;
2381         }
2382
2383         return TRUE;
2384 }
2385
2386 /**
2387  * e_book_backend_sqlitedb_is_summary_fields:
2388  * @fields_of_interest: A hash table containing the fields of interest
2389  * 
2390  * This only checks if all the fields are part of the default summary fields,
2391  * not part of the configured summary fields.
2392  *
2393  * Since: 3.2
2394  *
2395  * Deprecated: 3.8: Use e_book_backend_sqlitedb_check_summary_fields() instead.
2396  **/
2397 gboolean
2398 e_book_backend_sqlitedb_is_summary_fields (GHashTable *fields_of_interest)
2399 {
2400         gboolean summary_fields = TRUE;
2401         GHashTableIter iter;
2402         gpointer key, value;
2403         gint     i;
2404
2405         if (!fields_of_interest)
2406                 return FALSE;
2407
2408         g_hash_table_iter_init (&iter, fields_of_interest);
2409         while (g_hash_table_iter_next (&iter, &key, &value)) {
2410                 const gchar  *field_name = key;
2411                 EContactField field      = e_contact_field_id (field_name);
2412                 gboolean      found      = FALSE;
2413
2414                 for (i = 0; i < G_N_ELEMENTS (default_summary_fields); i++) {
2415                         if (field == default_summary_fields[i]) {
2416                                 found = TRUE;
2417                                 break;
2418                         }
2419                 }
2420
2421                 if (!found) {
2422                         summary_fields = FALSE;
2423                         break;
2424                 }
2425         }
2426
2427         return summary_fields;
2428 }
2429
2430 /**
2431  * e_book_backend_sqlitedb_check_summary_fields:
2432  * @ebsdb: An #EBookBackendSqliteDB
2433  * @fields_of_interest: A hash table containing the fields of interest
2434  * 
2435  * Checks if all the specified fields are part of the configured summary
2436  * fields for @ebsdb
2437  *
2438  * Since: 3.8
2439  **/
2440 gboolean
2441 e_book_backend_sqlitedb_check_summary_fields (EBookBackendSqliteDB *ebsdb,
2442                                               GHashTable *fields_of_interest)
2443 {
2444         gboolean summary_fields = TRUE;
2445         GHashTableIter iter;
2446         gpointer key, value;
2447
2448         if (!fields_of_interest)
2449                 return FALSE;
2450
2451         LOCK_MUTEX (&ebsdb->priv->lock);
2452
2453         g_hash_table_iter_init (&iter, fields_of_interest);
2454         while (g_hash_table_iter_next (&iter, &key, &value)) {
2455                 const gchar  *field_name = key;
2456                 EContactField field      = e_contact_field_id (field_name);
2457
2458                 if (summary_dbname_from_field (ebsdb, field) == NULL) {
2459                         summary_fields = FALSE;
2460                         break;
2461                 }
2462         }
2463
2464         UNLOCK_MUTEX (&ebsdb->priv->lock);
2465
2466         return summary_fields;
2467 }
2468
2469 /* free return value with g_free */
2470 static gchar *
2471 summary_select_stmt (GHashTable *fields_of_interest,
2472                      gboolean distinct)
2473 {
2474         GString *string;
2475
2476         if (distinct)
2477                 string = g_string_new ("SELECT DISTINCT summary.uid");
2478         else
2479                 string = g_string_new ("SELECT summary.uid");
2480
2481         /* Add the E_CONTACT_REV field if they are both requested */
2482         if (g_hash_table_size (fields_of_interest) == 2)
2483                 g_string_append (string, ", Rev");
2484
2485         return g_string_free (string, FALSE);
2486 }
2487
2488 static gint
2489 store_data_to_vcard (gpointer ref,
2490                      gint ncol,
2491                      gchar **cols,
2492                      gchar **name)
2493 {
2494         GSList **vcard_data = ref;
2495         EbSdbSearchData *search_data = g_slice_new0 (EbSdbSearchData);
2496         EContact *contact = e_contact_new ();
2497         gchar *vcard;
2498         gint i;
2499
2500         /* parse through cols, this will be useful if the api starts supporting field restrictions */
2501         for (i = 0; i < ncol; i++)
2502         {
2503                 if (!name[i] || !cols[i])
2504                         continue;
2505
2506                 /* Only UID & REV can be used to create contacts from the summary columns */
2507                 if (!g_ascii_strcasecmp (name[i], "uid")) {
2508                         e_contact_set (contact, E_CONTACT_UID, cols[i]);
2509                         search_data->uid = g_strdup (cols[i]);
2510                 } else if (!g_ascii_strcasecmp (name[i], "Rev")) {
2511                         e_contact_set (contact, E_CONTACT_REV, cols[i]);
2512                 } else if (!g_ascii_strcasecmp (name[i], "bdata"))
2513                         search_data->bdata = g_strdup (cols[i]);
2514         }
2515
2516         vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
2517         search_data->vcard = vcard;
2518         *vcard_data = g_slist_prepend (*vcard_data, search_data);
2519
2520         g_object_unref (contact);
2521         return 0;
2522 }
2523
2524 /**
2525  * e_book_backend_sqlitedb_get_vcard_string:
2526  * @ebsdb: An #EBookBackendSqliteDB
2527  * @folderid: The folder id
2528  * @uid: The uid to fetch a vcard for
2529  * @fields_of_interest: The required fields for this vcard, or %NULL to require all fields.
2530  * @with_all_required_fields: (allow none) (out): Whether all the required fields are present in the returned vcard.
2531  * @error: A location to store any error that may have occurred.
2532  *
2533  * Searches @ebsdb in the context of @folderid for @uid.
2534  *
2535  * If @ebsdb is configured to store the whole vcards, the whole vcard will be returned.
2536  * Otherwise the summary cache will be searched and the virtual vcard will be built
2537  * from the summary cache.
2538  *
2539  * In either case, @with_all_required_fields if specified, will be updated to reflect whether
2540  * the returned vcard string satisfies the passed 'fields_of_interest' parameter.
2541  * 
2542  * Returns: (transfer full): The vcard string for @uid or %NULL if @uid was not found.
2543  *
2544  * Since: 3.2
2545  */
2546 gchar *
2547 e_book_backend_sqlitedb_get_vcard_string (EBookBackendSqliteDB *ebsdb,
2548                                           const gchar *folderid,
2549                                           const gchar *uid,
2550                                           GHashTable *fields_of_interest,
2551                                           gboolean *with_all_required_fields,
2552                                           GError **error)
2553 {
2554         gchar *stmt;
2555         gchar *vcard_str = NULL;
2556         gboolean local_with_all_required_fields = FALSE;
2557
2558         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
2559         g_return_val_if_fail (folderid != NULL, NULL);
2560         g_return_val_if_fail (uid != NULL, NULL);
2561
2562         LOCK_MUTEX (&ebsdb->priv->lock);
2563
2564         /* Try constructing contacts from only UID/REV first if that's requested */
2565         if (uid_rev_fields (fields_of_interest)) {
2566                 GSList *vcards = NULL;
2567                 gchar *select_portion;
2568
2569                 select_portion = summary_select_stmt (fields_of_interest, FALSE);
2570
2571                 stmt = sqlite3_mprintf (
2572                         "%s FROM %Q AS summary WHERE summary.uid = %Q",
2573                         select_portion, folderid, uid);
2574                 book_backend_sql_exec (ebsdb->priv->db, stmt, store_data_to_vcard, &vcards, error);
2575                 sqlite3_free (stmt);
2576                 g_free (select_portion);
2577
2578                 if (vcards) {
2579                         EbSdbSearchData *s_data = (EbSdbSearchData *) vcards->data;
2580
2581                         vcard_str = s_data->vcard;
2582                         s_data->vcard = NULL;
2583
2584                         e_book_backend_sqlitedb_search_data_free (s_data);
2585
2586                         g_slist_free (vcards);
2587                         vcards = NULL;
2588                 }
2589
2590                 local_with_all_required_fields = TRUE;
2591         } else if (ebsdb->priv->store_vcard) {
2592                 stmt = sqlite3_mprintf (
2593                         "SELECT vcard FROM %Q WHERE uid = %Q", folderid, uid);
2594                 book_backend_sql_exec (
2595                         ebsdb->priv->db, stmt,
2596                         get_vcard_cb , &vcard_str, error);
2597                 sqlite3_free (stmt);
2598
2599                 local_with_all_required_fields = TRUE;
2600         } else {
2601                 g_set_error (
2602                         error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
2603                         _("Full search_contacts are not stored in cache. vcards cannot be returned."));
2604
2605         }
2606
2607         UNLOCK_MUTEX (&ebsdb->priv->lock);
2608
2609         if (with_all_required_fields)
2610                 *with_all_required_fields = local_with_all_required_fields;
2611
2612         if (!vcard_str && error && !*error)
2613                 g_set_error (
2614                         error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_CONTACT_NOT_FOUND,
2615                         _("Contact '%s' not found"), uid ? uid : "NULL");
2616
2617         return vcard_str;
2618 }
2619
2620 enum {
2621         CHECK_IS_SUMMARY   = (1 << 0),
2622         CHECK_IS_LIST_ATTR = (1 << 1),
2623         CHECK_UNSUPPORTED  = (1 << 2),
2624         CHECK_INVALID      = (1 << 3)
2625 };
2626
2627 static ESExpResult *
2628 func_check_subset (ESExp *f,
2629                    gint argc,
2630                    struct _ESExpTerm **argv,
2631                    gpointer data)
2632 {
2633         ESExpResult *r, *r1;
2634         gboolean one_non_summary_query = FALSE;
2635         gint result = 0;
2636         gint i;
2637
2638         for (i = 0; i < argc; i++) {
2639                 r1 = e_sexp_term_eval (f, argv[i]);
2640
2641                 if (r1->type != ESEXP_RES_INT) {
2642                         e_sexp_result_free (f, r1);
2643                         continue;
2644                 }
2645
2646                 result |= r1->value.number;
2647
2648                 if ((r1->value.number & CHECK_IS_SUMMARY) == 0)
2649                         one_non_summary_query = TRUE;
2650
2651                 e_sexp_result_free (f, r1);
2652         }
2653
2654         /* If at least one subset is not a summary query,
2655          * then the whole query is not a summary query and
2656          * thus cannot be done with an SQL statement
2657          */
2658         if (one_non_summary_query)
2659                 result &= ~CHECK_IS_SUMMARY;
2660
2661         r = e_sexp_result_new (f, ESEXP_RES_INT);
2662         r->value.number = result;
2663
2664         return r;
2665 }
2666
2667 static gint
2668 func_check_field_test (EBookBackendSqliteDB *ebsdb,
2669                         const gchar *query_name,
2670                         const gchar *query_value)
2671 {
2672         gint i;
2673         gint ret_val = 0;
2674
2675         if (ebsdb) {
2676                 for (i = 0; i < ebsdb->priv->n_summary_fields; i++) {
2677                         if (!g_ascii_strcasecmp (e_contact_field_name (ebsdb->priv->summary_fields[i].field), query_name)) {
2678                                 ret_val |= CHECK_IS_SUMMARY;
2679
2680                                 if (ebsdb->priv->summary_fields[i].type == E_TYPE_CONTACT_ATTR_LIST)
2681                                         ret_val |= CHECK_IS_LIST_ATTR;
2682
2683                                 break;
2684                         }
2685                 }
2686         } else {
2687                 for (i = 0; i < G_N_ELEMENTS (default_summary_fields); i++) {
2688                         if (!g_ascii_strcasecmp (e_contact_field_name (default_summary_fields[i]), query_name)) {
2689                                 ret_val |= CHECK_IS_SUMMARY;
2690
2691                                 if (e_contact_field_type (default_summary_fields[i]) == E_TYPE_CONTACT_ATTR_LIST)
2692                                         ret_val |= CHECK_IS_LIST_ATTR;
2693
2694                                 break;
2695                         }
2696                 }
2697         }
2698
2699         return ret_val;
2700 }
2701
2702 static ESExpResult *
2703 func_check (struct _ESExp *f,
2704             gint argc,
2705             struct _ESExpResult **argv,
2706             gpointer data)
2707 {
2708         EBookBackendSqliteDB *ebsdb = data;
2709         ESExpResult *r;
2710         gint ret_val = 0;
2711
2712         if (argc == 2
2713             && argv[0]->type == ESEXP_RES_STRING
2714             && argv[1]->type == ESEXP_RES_STRING) {
2715                 const gchar *query_name = argv[0]->value.string;
2716                 const gchar *query_value = argv[1]->value.string;
2717
2718                 /* Special case, when testing the special symbolic 'any field' we can
2719                  * consider it a summary query (it's similar to a 'no query'). */
2720                 if (g_strcmp0 (query_name, "x-evolution-any-field") == 0 &&
2721                     g_strcmp0 (query_value, "") == 0) {
2722                         ret_val |= CHECK_IS_SUMMARY;
2723                         goto check_finish;
2724                 }
2725
2726                 ret_val |= func_check_field_test (ebsdb, query_name, query_value);
2727         } else if (argc == 3
2728             && argv[0]->type == ESEXP_RES_STRING
2729             && argv[1]->type == ESEXP_RES_STRING
2730             && argv[2]->type == ESEXP_RES_STRING) {
2731                 const gchar *query_name = argv[0]->value.string;
2732                 const gchar *query_value = argv[1]->value.string;
2733                 ret_val |= func_check_field_test (ebsdb, query_name, query_value);
2734         }
2735
2736  check_finish:
2737         r = e_sexp_result_new (f, ESEXP_RES_INT);
2738         r->value.number = ret_val;
2739
2740         return r;
2741 }
2742
2743 static ESExpResult *
2744 func_check_phone (struct _ESExp *f,
2745                   gint argc,
2746                   struct _ESExpResult **argv,
2747                   gpointer data)
2748 {
2749         ESExpResult *const r = func_check (f, argc, argv, data);
2750         const gchar *const query_value = argv[1]->value.string;
2751         EPhoneNumber *number;
2752
2753         /* Here we need to catch unsupported queries and invalid queries
2754          * so we perform validity checks even if func_check() reports this
2755          * as not a part of the summary.
2756          */
2757         if (!e_phone_number_is_supported ()) {
2758                 r->value.number |= CHECK_UNSUPPORTED;
2759                 return r;
2760         }
2761
2762         number = e_phone_number_from_string (query_value, NULL, NULL);
2763
2764         if (number == NULL) {
2765                 /* Could not construct a phone number from the query input,
2766                  * an invalid query error will be propagated to the client.
2767                  */
2768                 r->value.number |= CHECK_INVALID;
2769         } else {
2770                 e_phone_number_free (number);
2771         }
2772
2773         return r;
2774 }
2775
2776 /* 'builtin' functions */
2777 static const struct {
2778         const gchar *name;
2779         ESExpFunc *func;
2780         gint type;              /* set to 1 if a function can perform shortcut evaluation, or
2781                                    doesn't execute everything, 0 otherwise */
2782 } check_symbols[] = {
2783         { "and", (ESExpFunc *) func_check_subset, 1},
2784         { "or", (ESExpFunc *) func_check_subset, 1},
2785
2786         { "contains", func_check, 0 },
2787         { "is", func_check, 0 },
2788         { "beginswith", func_check, 0 },
2789         { "endswith", func_check, 0 },
2790         { "exists", func_check, 0 },
2791         { "eqphone", func_check_phone, 0 },
2792         { "eqphone_national", func_check_phone, 0 },
2793         { "eqphone_short", func_check_phone, 0 }
2794 };
2795
2796 static gboolean
2797 e_book_backend_sqlitedb_check_summary_query_locked (EBookBackendSqliteDB *ebsdb,
2798                                                     const gchar *query,
2799                                                     gboolean *with_list_attrs,
2800                                                     gboolean *unsupported_query,
2801                                                     gboolean *invalid_query)
2802 {
2803         ESExp *sexp;
2804         ESExpResult *r;
2805         gboolean retval = FALSE;
2806         gint i;
2807         gint esexp_error;
2808
2809         g_return_val_if_fail (query != NULL, FALSE);
2810         g_return_val_if_fail (*query != '\0', FALSE);
2811
2812         sexp = e_sexp_new ();
2813
2814         for (i = 0; i < G_N_ELEMENTS (check_symbols); i++) {
2815                 if (check_symbols[i].type == 1) {
2816                         e_sexp_add_ifunction (
2817                                 sexp, 0, check_symbols[i].name,
2818                                 (ESExpIFunc *) check_symbols[i].func, ebsdb);
2819                 } else {
2820                         e_sexp_add_function (
2821                                 sexp, 0, check_symbols[i].name,
2822                                 check_symbols[i].func, ebsdb);
2823                 }
2824         }
2825
2826         e_sexp_input_text (sexp, query, strlen (query));
2827         esexp_error = e_sexp_parse (sexp);
2828
2829         if (esexp_error == -1) {
2830                 if (invalid_query)
2831                         *invalid_query = TRUE;
2832
2833                 return FALSE;
2834         }
2835
2836         r = e_sexp_eval (sexp);
2837         if (r && r->type == ESEXP_RES_INT) {
2838                 retval = (r->value.number & CHECK_IS_SUMMARY) != 0;
2839
2840                 if (with_list_attrs)
2841                         *with_list_attrs = (r->value.number & CHECK_IS_LIST_ATTR) != 0;
2842
2843                 if (unsupported_query)
2844                         *unsupported_query = (r->value.number & CHECK_UNSUPPORTED) != 0;
2845
2846                 if (invalid_query)
2847                         *invalid_query = (r->value.number & CHECK_INVALID) != 0;
2848         }
2849
2850         e_sexp_result_free (sexp, r);
2851         e_sexp_unref (sexp);
2852
2853         return retval;
2854 }
2855
2856 /**
2857  * e_book_backend_sqlitedb_check_summary_query:
2858  * @ebsdb: an #EBookBackendSqliteDB
2859  * @query: the query to check
2860  * @with_list_attrs: Return location to store whether the query touches upon list attributes
2861  *
2862  * Checks whether @query contains only checks for the summary fields
2863  * configured in @ebsdb
2864  *
2865  * Since: 3.8
2866  **/
2867 gboolean
2868 e_book_backend_sqlitedb_check_summary_query (EBookBackendSqliteDB *ebsdb,
2869                                              const gchar *query,
2870                                              gboolean *with_list_attrs)
2871 {
2872         gboolean is_summary;
2873
2874         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
2875
2876         LOCK_MUTEX (&ebsdb->priv->lock);
2877         is_summary = e_book_backend_sqlitedb_check_summary_query_locked (ebsdb, query, with_list_attrs, NULL, NULL);
2878         UNLOCK_MUTEX (&ebsdb->priv->lock);
2879
2880         return is_summary;
2881 }
2882
2883 /**
2884  * e_book_backend_sqlitedb_is_summary_query:
2885  *
2886  * Checks whether the query contains only checks for the default summary fields
2887  *
2888  * Since: 3.2
2889  *
2890  * Deprecated: 3.8: Use e_book_backend_sqlitedb_check_summary_query() instead
2891  **/
2892 gboolean
2893 e_book_backend_sqlitedb_is_summary_query (const gchar *query)
2894 {
2895         return e_book_backend_sqlitedb_check_summary_query_locked (NULL, query, NULL, NULL, NULL);
2896 }
2897
2898 static ESExpResult *
2899 func_and (ESExp *f,
2900           gint argc,
2901           struct _ESExpTerm **argv,
2902           gpointer data)
2903 {
2904         ESExpResult *r, *r1;
2905         GString *string;
2906         gint i;
2907
2908         string = g_string_new ("( ");
2909         for (i = 0; i < argc; i++) {
2910                 r1 = e_sexp_term_eval (f, argv[i]);
2911
2912                 if (r1->type != ESEXP_RES_STRING) {
2913                         e_sexp_result_free (f, r1);
2914                         continue;
2915                 }
2916                 if (r1->value.string && *r1->value.string)
2917                         g_string_append_printf (string, "%s%s", r1->value.string, ((argc > 1) && (i != argc - 1)) ? " AND ":"");
2918                 e_sexp_result_free (f, r1);
2919         }
2920         g_string_append (string, " )");
2921         r = e_sexp_result_new (f, ESEXP_RES_STRING);
2922
2923         if (strlen (string->str) == 4) {
2924                 r->value.string = g_strdup ("");
2925                 g_string_free (string, TRUE);
2926         } else {
2927                 r->value.string = g_string_free (string, FALSE);
2928         }
2929
2930         return r;
2931 }
2932
2933 static ESExpResult *
2934 func_or (ESExp *f,
2935          gint argc,
2936          struct _ESExpTerm **argv,
2937          gpointer data)
2938 {
2939         ESExpResult *r, *r1;
2940         GString *string;
2941         gint i;
2942
2943         string = g_string_new ("( ");
2944         for (i = 0; i < argc; i++) {
2945                 r1 = e_sexp_term_eval (f, argv[i]);
2946
2947                 if (r1->type != ESEXP_RES_STRING) {
2948                         e_sexp_result_free (f, r1);
2949                         continue;
2950                 }
2951                 if (r1->value.string && *r1->value.string)
2952                         g_string_append_printf (string, "%s%s", r1->value.string, ((argc > 1) && (i != argc - 1)) ? " OR ":"");
2953                 e_sexp_result_free (f, r1);
2954         }
2955         g_string_append (string, " )");
2956
2957         r = e_sexp_result_new (f, ESEXP_RES_STRING);
2958         if (strlen (string->str) == 4) {
2959                 r->value.string = g_strdup ("");
2960                 g_string_free (string, TRUE);
2961         } else {
2962                 r->value.string = g_string_free (string, FALSE);
2963         }
2964
2965         return r;
2966 }
2967
2968 typedef enum {
2969         MATCH_CONTAINS,
2970         MATCH_IS,
2971         MATCH_BEGINS_WITH,
2972         MATCH_ENDS_WITH,
2973         MATCH_PHONE_NUMBER,
2974         MATCH_NATIONAL_PHONE_NUMBER,
2975         MATCH_SHORT_PHONE_NUMBER
2976 } MatchType;
2977
2978 typedef enum {
2979         CONVERT_NOTHING   =  0,
2980         CONVERT_NORMALIZE = (1 << 0),
2981         CONVERT_REVERSE   = (1 << 1),
2982         CONVERT_PHONE     = (1 << 2)
2983 } ConvertFlags;
2984
2985 static gchar *
2986 extract_digits (const gchar *normal)
2987 {
2988         gchar *digits = g_new (char, strlen (normal) + 1);
2989         const gchar *src = normal;
2990         gchar *dst = digits;
2991
2992         /* extract digits also considering eastern arabic numerals */
2993         for (src = normal; *src; src = g_utf8_next_char (src)) {
2994                 const gunichar uc = g_utf8_get_char_validated (src, -1);
2995                 const gint value = g_unichar_digit_value (uc);
2996
2997                 if (uc == -1)
2998                         break;
2999
3000                 if (value != -1)
3001                         *dst++ = '0' + value;
3002         }
3003
3004         *dst = '\0';
3005
3006         return digits;
3007 }
3008
3009 static gchar *
3010 convert_string_value (EBookBackendSqliteDB *ebsdb,
3011                       const gchar          *value,
3012                       const gchar          *region,
3013                       ConvertFlags          flags,
3014                       MatchType             match)
3015 {
3016         GString *str;
3017         size_t len;
3018         gchar c;
3019         gboolean escape_modifier_needed = FALSE;
3020         const gchar *escape_modifier = " ESCAPE '^'";
3021         gchar *computed = NULL;
3022         gchar *normal;
3023         const gchar *ptr;
3024
3025         g_return_val_if_fail (value != NULL, NULL);
3026
3027         if (flags & CONVERT_NORMALIZE)
3028                 normal = e_util_utf8_normalize (value);
3029         else
3030                 normal = g_strdup (value);
3031
3032         /* Just assume each character must be escaped. The result of this function
3033          * is discarded shortly after calling this function. Therefore it's
3034          * acceptable to possibly allocate twice the memory needed.
3035          */
3036         len = strlen (normal);
3037         str = g_string_sized_new (2 * len + 4 + strlen (escape_modifier) - 1);
3038         g_string_append_c (str, '\'');
3039
3040         switch (match) {
3041         case MATCH_CONTAINS:
3042         case MATCH_ENDS_WITH:
3043         case MATCH_SHORT_PHONE_NUMBER:
3044                 g_string_append_c (str, '%');
3045                 break;
3046
3047         case MATCH_BEGINS_WITH:
3048         case MATCH_IS:
3049         case MATCH_PHONE_NUMBER:
3050         case MATCH_NATIONAL_PHONE_NUMBER:
3051                 break;
3052         }
3053
3054         if (flags & CONVERT_REVERSE) {
3055                 computed = g_utf8_strreverse (normal, -1);
3056                 ptr = computed;
3057         } else if (flags & CONVERT_PHONE) {
3058                 computed = convert_phone (normal, region);
3059                 ptr = computed;
3060         } else {
3061                 ptr = normal;
3062         }
3063
3064         while ((c = *ptr++)) {
3065                 if (c == '\'') {
3066                         g_string_append_c (str, '\'');
3067                 } else if (c == '%' || c == '^') {
3068                         g_string_append_c (str, '^');
3069                         escape_modifier_needed = TRUE;
3070                 }
3071
3072                 g_string_append_c (str, c);
3073         }
3074
3075         switch (match) {
3076         case MATCH_CONTAINS:
3077         case MATCH_BEGINS_WITH:
3078                 g_string_append_c (str, '%');
3079                 break;
3080
3081         case MATCH_ENDS_WITH:
3082         case MATCH_IS:
3083         case MATCH_PHONE_NUMBER:
3084         case MATCH_NATIONAL_PHONE_NUMBER:
3085         case MATCH_SHORT_PHONE_NUMBER:
3086                 break;
3087         }
3088
3089         g_string_append_c (str, '\'');
3090
3091         if (escape_modifier_needed)
3092                 g_string_append (str, escape_modifier);
3093
3094         g_free (computed);
3095         g_free (normal);
3096
3097         return g_string_free (str, FALSE);
3098 }
3099
3100 static gchar *
3101 field_name_and_query_term (EBookBackendSqliteDB *ebsdb,
3102                            const gchar          *folderid,
3103                            const gchar          *field_name_input,
3104                            const gchar          *query_term_input,
3105                            const gchar          *region,
3106                            MatchType             match,
3107                            gboolean             *is_list_attr,
3108                            gchar               **query_term,
3109                            gchar               **extra_term)
3110 {
3111         gint summary_index;
3112         gchar *field_name = NULL;
3113         gchar *value = NULL;
3114         gchar *extra = NULL;
3115         gboolean list_attr = FALSE;
3116
3117         summary_index = summary_index_from_field_name (ebsdb, field_name_input);
3118
3119         if (summary_index < 0) {
3120                 g_critical ("Only summary field matches should be converted to sql queries");
3121                 field_name = g_strconcat (folderid, ".", field_name_input, NULL);
3122                 value = convert_string_value (
3123                         ebsdb, query_term_input, region,
3124                         CONVERT_NORMALIZE, match);
3125         } else {
3126                 gboolean suffix_search = FALSE;
3127                 gboolean phone_search = FALSE;
3128
3129                 /* If its a suffix search and we have reverse data to search... */
3130                 if (match == MATCH_ENDS_WITH &&
3131                     (ebsdb->priv->summary_fields[summary_index].index & INDEX_SUFFIX) != 0)
3132                         suffix_search = TRUE;
3133
3134                 /* If its a phone-number search and we have E.164 data to search... */
3135                 else if ((match == MATCH_PHONE_NUMBER ||
3136                                 match == MATCH_NATIONAL_PHONE_NUMBER ||
3137                                 match == MATCH_SHORT_PHONE_NUMBER) &&
3138                     (ebsdb->priv->summary_fields[summary_index].index & INDEX_PHONE) != 0)
3139                         phone_search = TRUE;
3140
3141                 /* Or also if its an exact match, and we *only* have reverse data which is indexed,
3142                  * then prefer the indexed reverse search. */
3143                 else if (match == MATCH_IS &&
3144                          (ebsdb->priv->summary_fields[summary_index].index & INDEX_SUFFIX) != 0 &&
3145                          (ebsdb->priv->summary_fields[summary_index].index & INDEX_PREFIX) == 0)
3146                         suffix_search = TRUE;
3147
3148                 if (suffix_search) {
3149                         /* Special case for suffix matching:
3150                          *  o Reverse the string
3151                          *  o Check the reversed column instead
3152                          *  o Make it a prefix search
3153                          */
3154                         if (ebsdb->priv->summary_fields[summary_index].type == E_TYPE_CONTACT_ATTR_LIST) {
3155                                 field_name = g_strdup ("multi.value_reverse");
3156                                 list_attr = TRUE;
3157                         } else
3158                                 field_name = g_strconcat (
3159                                         "summary.",
3160                                         ebsdb->priv->summary_fields[summary_index].dbname,
3161                                         "_reverse", NULL);
3162
3163                         if (ebsdb->priv->summary_fields[summary_index].field == E_CONTACT_UID ||
3164                             ebsdb->priv->summary_fields[summary_index].field == E_CONTACT_REV)
3165                                 value = convert_string_value (
3166                                         ebsdb, query_term_input, region, CONVERT_REVERSE,
3167                                         (match == MATCH_ENDS_WITH) ? MATCH_BEGINS_WITH : MATCH_IS);
3168                         else
3169                                 value = convert_string_value (
3170                                         ebsdb, query_term_input, region,
3171                                         CONVERT_REVERSE | CONVERT_NORMALIZE,
3172                                         (match == MATCH_ENDS_WITH) ? MATCH_BEGINS_WITH : MATCH_IS);
3173                 } else if (phone_search) {
3174                         /* Special case for E.164 matching:
3175                          *  o Normalize the string
3176                          *  o Check the E.164 column instead
3177                          */
3178                         const gint country_code = e_phone_number_get_country_code_for_region (region, NULL);
3179
3180                         if (ebsdb->priv->summary_fields[summary_index].type == E_TYPE_CONTACT_ATTR_LIST) {
3181                                 field_name = g_strdup ("multi.value_phone");
3182                                 list_attr = TRUE;
3183                         } else {
3184                                 field_name = g_strdup_printf (
3185                                         "summary.%s_phone",
3186                                         ebsdb->priv->summary_fields[summary_index].dbname);
3187                         }
3188
3189                         if (match == MATCH_PHONE_NUMBER) {
3190                                 value = convert_string_value (
3191                                         ebsdb, query_term_input, region,
3192                                         CONVERT_NORMALIZE | CONVERT_PHONE, match);
3193
3194                                 extra = sqlite3_mprintf (" COLLATE ixphone_%d", country_code);
3195                         } else {
3196                                 if (match == MATCH_NATIONAL_PHONE_NUMBER) {
3197                                         value = convert_string_value (
3198                                                 ebsdb, query_term_input, region,
3199                                                 CONVERT_PHONE, MATCH_NATIONAL_PHONE_NUMBER);
3200
3201                                         extra = sqlite3_mprintf (" COLLATE ixphone_national");
3202                                 } else {
3203                                         gchar *const digits = extract_digits (query_term_input);
3204                                         value = convert_string_value (
3205                                                 ebsdb, digits, region,
3206                                                 CONVERT_NOTHING, MATCH_ENDS_WITH);
3207                                         g_free (digits);
3208
3209                                         extra = sqlite3_mprintf (
3210                                                 " AND (%q LIKE '|%%' OR %q LIKE '+%d|%%')",
3211                                                 field_name, field_name, country_code);
3212                                 }
3213
3214                         }
3215                 } else {
3216                         if (ebsdb->priv->summary_fields[summary_index].type == E_TYPE_CONTACT_ATTR_LIST) {
3217                                 field_name = g_strdup ("multi.value");
3218                                 list_attr = TRUE;
3219                         } else
3220                                 field_name = g_strconcat (
3221                                         "summary.",
3222                                         ebsdb->priv->summary_fields[summary_index].dbname, NULL);
3223
3224                         if (ebsdb->priv->summary_fields[summary_index].field == E_CONTACT_UID ||
3225                             ebsdb->priv->summary_fields[summary_index].field == E_CONTACT_REV) {
3226                                 value = convert_string_value (
3227                                         ebsdb, query_term_input, region,
3228                                         CONVERT_NOTHING, match);
3229                         } else {
3230                                 value = convert_string_value (
3231                                         ebsdb, query_term_input, region,
3232                                         CONVERT_NORMALIZE, match);
3233                         }
3234                 }
3235         }
3236
3237         if (is_list_attr)
3238                 *is_list_attr = list_attr;
3239
3240         *query_term = value;
3241
3242         if (extra_term)
3243                 *extra_term = extra;
3244
3245         return field_name;
3246 }
3247
3248 typedef struct {
3249         EBookBackendSqliteDB *ebsdb;
3250         const gchar          *folderid;
3251 } BuildQueryData;
3252
3253 static const gchar *
3254 field_oper (MatchType match)
3255 {
3256         switch (match) {
3257         case MATCH_IS:
3258         case MATCH_PHONE_NUMBER:
3259         case MATCH_NATIONAL_PHONE_NUMBER:
3260                 return "=";
3261
3262         case MATCH_CONTAINS:
3263         case MATCH_BEGINS_WITH:
3264         case MATCH_ENDS_WITH:
3265         case MATCH_SHORT_PHONE_NUMBER:
3266                 break;
3267         }
3268
3269         return "LIKE";
3270 }
3271
3272 static ESExpResult *
3273 convert_match_exp (struct _ESExp *f,
3274                    gint argc,
3275                    struct _ESExpResult **argv,
3276                    gpointer data,
3277                    MatchType match)
3278 {
3279         BuildQueryData *qdata = (BuildQueryData *) data;
3280         EBookBackendSqliteDB *ebsdb = qdata->ebsdb;
3281         ESExpResult *r;
3282         gchar *str = NULL;
3283
3284         /* are we inside a match-all? */
3285         if (argc > 1 && argv[0]->type == ESEXP_RES_STRING) {
3286                 const gchar *field;
3287
3288                 /* only a subset of headers are supported .. */
3289                 field = argv[0]->value.string;
3290
3291                 if (argv[1]->type == ESEXP_RES_STRING && argv[1]->value.string[0] != 0) {
3292                         const gchar *const oper = field_oper (match);
3293                         gchar *field_name, *query_term, *extra_term;
3294
3295                         if (!g_ascii_strcasecmp (field, "full_name")) {
3296                                 GString *names = g_string_new (NULL);
3297
3298                                 field_name = field_name_and_query_term (
3299                                         ebsdb, qdata->folderid, "full_name",
3300                                         argv[1]->value.string, NULL,
3301                                         match, NULL, &query_term, NULL);
3302                                 g_string_append_printf (
3303                                         names, "(%s IS NOT NULL AND %s %s %s)",
3304                                         field_name, field_name, oper, query_term);
3305                                 g_free (field_name);
3306                                 g_free (query_term);
3307
3308                                 if (summary_dbname_from_field (ebsdb, E_CONTACT_FAMILY_NAME)) {
3309                                         field_name = field_name_and_query_term (
3310                                                 ebsdb, qdata->folderid, "family_name",
3311                                                 argv[1]->value.string, NULL,
3312                                                 match, NULL, &query_term, NULL);
3313                                         g_string_append_printf (
3314                                                 names, " OR (%s IS NOT NULL AND %s %s %s)",
3315                                                 field_name, field_name, oper, query_term);
3316                                         g_free (field_name);
3317                                         g_free (query_term);
3318                                 }
3319
3320                                 if (summary_dbname_from_field (ebsdb, E_CONTACT_GIVEN_NAME)) {
3321                                         field_name = field_name_and_query_term (
3322                                                 ebsdb, qdata->folderid, "given_name",
3323                                                 argv[1]->value.string, NULL,
3324                                                 match, NULL, &query_term, NULL);
3325                                         g_string_append_printf (
3326                                                 names, " OR (%s IS NOT NULL AND %s %s %s)",
3327                                                 field_name, field_name, oper, query_term);
3328                                         g_free (field_name);
3329                                         g_free (query_term);
3330                                 }
3331
3332                                 if (summary_dbname_from_field (ebsdb, E_CONTACT_NICKNAME)) {
3333                                         field_name = field_name_and_query_term (
3334                                                 ebsdb, qdata->folderid, "nickname",
3335                                                 argv[1]->value.string, NULL,
3336                                                 match, NULL, &query_term, NULL);
3337                                         g_string_append_printf (
3338                                                 names, " OR (%s IS NOT NULL AND %s %s %s)",
3339                                                 field_name, field_name, oper, query_term);
3340                                         g_free (field_name);
3341                                         g_free (query_term);
3342                                 }
3343
3344                                 str = names->str;
3345                                 g_string_free (names, FALSE);
3346
3347                         } else {
3348                                 const gchar *const region =
3349                                         argc > 2 && argv[2]->type == ESEXP_RES_STRING ?
3350                                         argv[2]->value.string : NULL;
3351
3352                                 gboolean is_list = FALSE;
3353
3354                                 /* This should ideally be the only valid case from all the above special casing, but oh well... */
3355                                 field_name = field_name_and_query_term (
3356                                         ebsdb, qdata->folderid, field,
3357                                         argv[1]->value.string, region,
3358                                         match, &is_list, &query_term, &extra_term);
3359
3360                                 /* User functions like eqphone_national() cannot utilize indexes. Therefore we
3361                                  * should reduce the result set first before applying any user functions. This
3362                                  * is done by applying a seemingly redundant suffix match first.
3363                                  */
3364                                 if (is_list) {
3365                                         gchar *tmp;
3366
3367                                         tmp = sqlite3_mprintf ("summary.uid = multi.uid AND multi.field = %Q", field);
3368                                         str = g_strdup_printf (
3369                                                 "(%s AND (%s %s %s%s))",
3370                                                 tmp, field_name, oper, query_term,
3371                                                 extra_term ? extra_term : "");
3372                                         sqlite3_free (tmp);
3373                                 } else
3374                                         str = g_strdup_printf (
3375                                                 "(%s IS NOT NULL AND (%s %s %s%s))",
3376                                                 field_name, field_name, oper, query_term,
3377                                                 extra_term ? extra_term : "");
3378
3379                                 g_free (field_name);
3380                                 g_free (query_term);
3381
3382                                 sqlite3_free (extra_term);
3383                         }
3384                 }
3385         }
3386
3387         r = e_sexp_result_new (f, ESEXP_RES_STRING);
3388         r->value.string = str;
3389
3390         return r;
3391 }
3392
3393 static ESExpResult *
3394 func_contains (struct _ESExp *f,
3395                gint argc,
3396                struct _ESExpResult **argv,
3397                gpointer data)
3398 {
3399         return convert_match_exp (f, argc, argv, data, MATCH_CONTAINS);
3400 }
3401
3402 static ESExpResult *
3403 func_is (struct _ESExp *f,
3404          gint argc,
3405          struct _ESExpResult **argv,
3406          gpointer data)
3407 {
3408         return convert_match_exp (f, argc, argv, data, MATCH_IS);
3409 }
3410
3411 static ESExpResult *
3412 func_beginswith (struct _ESExp *f,
3413                  gint argc,
3414                  struct _ESExpResult **argv,
3415                  gpointer data)
3416 {
3417         return convert_match_exp (f, argc, argv, data, MATCH_BEGINS_WITH);
3418 }
3419
3420 static ESExpResult *
3421 func_endswith (struct _ESExp *f,
3422                gint argc,
3423                struct _ESExpResult **argv,
3424                gpointer data)
3425 {
3426         return convert_match_exp (f, argc, argv, data, MATCH_ENDS_WITH);
3427 }
3428
3429 static ESExpResult *
3430 func_eqphone (struct _ESExp *f,
3431               gint argc,
3432               struct _ESExpResult **argv,
3433               gpointer data)
3434 {
3435         return convert_match_exp (f, argc, argv, data, MATCH_PHONE_NUMBER);
3436 }
3437
3438 static ESExpResult *
3439 func_eqphone_national (struct _ESExp *f,
3440                        gint argc,
3441                        struct _ESExpResult **argv,
3442                        gpointer data)
3443 {
3444         return convert_match_exp (f, argc, argv, data, MATCH_NATIONAL_PHONE_NUMBER);
3445 }
3446
3447 static ESExpResult *
3448 func_eqphone_short (struct _ESExp *f,
3449                     gint argc,
3450                     struct _ESExpResult **argv,
3451                     gpointer data)
3452 {
3453         return convert_match_exp (f, argc, argv, data, MATCH_SHORT_PHONE_NUMBER);
3454 }
3455
3456 /* 'builtin' functions */
3457 static struct {
3458         const gchar *name;
3459         ESExpFunc *func;
3460         guint immediate :1;
3461 } symbols[] = {
3462         { "and", (ESExpFunc *) func_and, 1},
3463         { "or", (ESExpFunc *) func_or, 1},
3464
3465         { "contains", func_contains, 0 },
3466         { "is", func_is, 0 },
3467         { "beginswith", func_beginswith, 0 },
3468         { "endswith", func_endswith, 0 },
3469         { "eqphone", func_eqphone, 0 },
3470         { "eqphone_national", func_eqphone_national, 0 },
3471         { "eqphone_short", func_eqphone_short, 0 }
3472 };
3473
3474 static gchar *
3475 sexp_to_sql_query (EBookBackendSqliteDB *ebsdb,
3476                    const gchar *folderid,
3477                    const gchar *query)
3478 {
3479         BuildQueryData data = { ebsdb, folderid };
3480         ESExp *sexp;
3481         ESExpResult *r;
3482         gint i;
3483         gchar *res;
3484
3485         sexp = e_sexp_new ();
3486
3487         for (i = 0; i < G_N_ELEMENTS (symbols); i++) {
3488                 if (symbols[i].immediate)
3489                         e_sexp_add_ifunction (
3490                                 sexp, 0, symbols[i].name,
3491                                 (ESExpIFunc *) symbols[i].func, &data);
3492                 else
3493                         e_sexp_add_function (
3494                                 sexp, 0, symbols[i].name,
3495                                 symbols[i].func, &data);
3496         }
3497
3498         e_sexp_input_text (sexp, query, strlen (query));
3499         e_sexp_parse (sexp);
3500
3501         r = e_sexp_eval (sexp);
3502         if (!r)
3503                 return NULL;
3504         if (r->type == ESEXP_RES_STRING) {
3505                 if (r->value.string && *r->value.string)
3506                         res = g_strdup (r->value.string);
3507                 else
3508                         res = NULL;
3509         } else {
3510                 g_warn_if_reached ();
3511                 res = NULL;
3512         }
3513
3514         e_sexp_result_free (sexp, r);
3515         e_sexp_unref (sexp);
3516
3517         return res;
3518 }
3519
3520 static gint
3521 addto_vcard_list_cb (gpointer ref,
3522                      gint col,
3523                      gchar **cols,
3524                      gchar **name)
3525 {
3526         GSList **vcard_data = ref;
3527         EbSdbSearchData *s_data = g_slice_new0 (EbSdbSearchData);
3528
3529         if (cols[0])
3530                 s_data->uid = g_strdup (cols[0]);
3531
3532         if (cols[1])
3533                 s_data->vcard = g_strdup (cols[1]);
3534
3535         if (cols[2])
3536                 s_data->bdata = g_strdup (cols[2]);
3537
3538         *vcard_data = g_slist_prepend (*vcard_data, s_data);
3539
3540         return 0;
3541 }
3542
3543 static gint
3544 addto_slist_cb (gpointer ref,
3545                 gint col,
3546                 gchar **cols,
3547                 gchar **name)
3548 {
3549         GSList **uids = ref;
3550
3551         if (cols[0])
3552                 *uids = g_slist_prepend (*uids, g_strdup (cols [0]));
3553
3554         return 0;
3555 }
3556
3557 static GSList *
3558 book_backend_sqlitedb_search_query (EBookBackendSqliteDB *ebsdb,
3559                                     const gchar *sql,
3560                                     const gchar *folderid,
3561                                     GHashTable *fields_of_interest,
3562                                     gboolean *with_all_required_fields,
3563                                     gboolean query_with_list_attrs,
3564                                     GError **error)
3565 {
3566         GSList *vcard_data = NULL;
3567         gchar  *stmt;
3568         gboolean local_with_all_required_fields = FALSE;
3569         gboolean success = TRUE;
3570
3571         /* Try constructing contacts from only UID/REV first if that's requested */
3572         if (uid_rev_fields (fields_of_interest)) {
3573                 gchar *select_portion;
3574
3575                 select_portion = summary_select_stmt (
3576                         fields_of_interest, query_with_list_attrs);
3577
3578                 if (sql && sql[0]) {
3579
3580                         if (query_with_list_attrs) {
3581                                 gchar *list_table = g_strconcat (folderid, "_lists", NULL);
3582
3583                                 stmt = sqlite3_mprintf (
3584                                         "%s FROM %Q AS summary, %Q AS multi WHERE %s",
3585                                         select_portion, folderid, list_table, sql);
3586                                 g_free (list_table);
3587                         } else {
3588                                 stmt = sqlite3_mprintf (
3589                                         "%s FROM %Q AS summary WHERE %s",
3590                                         select_portion, folderid, sql);
3591                         }
3592
3593                         success = book_backend_sql_exec (
3594                                 ebsdb->priv->db, stmt,
3595                                 store_data_to_vcard, &vcard_data, error);
3596
3597                         sqlite3_free (stmt);
3598                 } else {
3599                         stmt = sqlite3_mprintf ("%s FROM %Q AS summary", select_portion, folderid);
3600                         success = book_backend_sql_exec (
3601                                 ebsdb->priv->db, stmt,
3602                                 store_data_to_vcard, &vcard_data, error);
3603                         sqlite3_free (stmt);
3604                 }
3605
3606                 local_with_all_required_fields = TRUE;
3607                 g_free (select_portion);
3608
3609         } else if (ebsdb->priv->store_vcard) {
3610
3611                 if (sql && sql[0]) {
3612
3613                         if (query_with_list_attrs) {
3614                                 gchar *list_table = g_strconcat (folderid, "_lists", NULL);
3615
3616                                 stmt = sqlite3_mprintf (
3617                                         "SELECT DISTINCT summary.uid, vcard, bdata "
3618                                         "FROM %Q AS summary, %Q AS multi WHERE %s",
3619                                         folderid, list_table, sql);
3620                                 g_free (list_table);
3621                         } else {
3622                                 stmt = sqlite3_mprintf (
3623                                         "SELECT uid, vcard, bdata FROM %Q as summary WHERE %s", folderid, sql);
3624                         }
3625
3626                         success = book_backend_sql_exec (
3627                                 ebsdb->priv->db, stmt,
3628                                 addto_vcard_list_cb , &vcard_data, error);
3629
3630                         sqlite3_free (stmt);
3631                 } else {
3632                         stmt = sqlite3_mprintf (
3633                                 "SELECT uid, vcard, bdata FROM %Q", folderid);
3634                         success = book_backend_sql_exec (
3635                                 ebsdb->priv->db, stmt,
3636                                 addto_vcard_list_cb , &vcard_data, error);
3637                         sqlite3_free (stmt);
3638                 }
3639
3640                 local_with_all_required_fields = TRUE;
3641         } else {
3642                 g_set_error (
3643                         error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
3644                         _("Full search_contacts are not stored in cache. vcards cannot be returned."));
3645         }
3646
3647         if (!success) {
3648                 g_warn_if_fail (vcard_data == NULL);
3649                 return NULL;
3650         }
3651
3652         if (with_all_required_fields)
3653                 *with_all_required_fields = local_with_all_required_fields;
3654
3655         return g_slist_reverse (vcard_data);
3656 }
3657
3658 static GSList *
3659 book_backend_sqlitedb_search_full (EBookBackendSqliteDB *ebsdb,
3660                                    const gchar *sexp,
3661                                    const gchar *folderid,
3662                                    gboolean return_uids,
3663                                    GError **error)
3664 {
3665         GSList *r_list = NULL, *all = NULL, *l;
3666         EBookBackendSExp *bsexp = NULL;
3667         gboolean success;
3668         gchar *stmt;
3669
3670         stmt = sqlite3_mprintf ("SELECT uid, vcard, bdata FROM %Q", folderid);
3671         success = book_backend_sql_exec (
3672                 ebsdb->priv->db, stmt, addto_vcard_list_cb , &all, error);
3673         sqlite3_free (stmt);
3674
3675         if (!success) {
3676                 g_warn_if_fail (all == NULL);
3677                 return NULL;
3678         }
3679
3680         bsexp = e_book_backend_sexp_new (sexp);
3681
3682         for (l = all; l != NULL; l = g_slist_next (l)) {
3683                 EbSdbSearchData *s_data = (EbSdbSearchData *) l->data;
3684
3685                 if (e_book_backend_sexp_match_vcard (bsexp, s_data->vcard)) {
3686                         if (!return_uids)
3687                                 r_list = g_slist_prepend (r_list, s_data);
3688                         else {
3689                                 r_list = g_slist_prepend (r_list, g_strdup (s_data->uid));
3690                                 e_book_backend_sqlitedb_search_data_free (s_data);
3691                         }
3692                 } else
3693                         e_book_backend_sqlitedb_search_data_free (s_data);
3694         }
3695
3696         g_object_unref (bsexp);
3697
3698         g_slist_free (all);
3699
3700         return r_list;
3701 }
3702
3703 /**
3704  * e_book_backend_sqlitedb_search 
3705  * @ebsdb: 
3706  * @folderid: 
3707  * @sexp: search expression; use NULL or an empty string to get all stored
3708  * contacts.
3709  * @fields_of_interest: a #GHashTable containing the names of fields to return,
3710  * or NULL for all.  At the moment if this is non-null, the vcard will be
3711  * populated with summary fields, else it would return the whole vcard if
3712  * its stored in the db. [not implemented fully]
3713  * @searched: (allow none) (out): Whether @ebsdb was capable of searching
3714  * for the provided query @sexp.
3715  * @with_all_required_fields: (allow none) (out): Whether all the required
3716  * fields are present in the returned vcards.
3717  * @error: 
3718  *
3719  * Searching with summary fields is always supported. Search expressions
3720  * containing any other field is supported only if backend chooses to store
3721  * the vcard inside the db.
3722  *
3723  * Summary fields - uid, rev, nickname, given_name, family_name, file_as
3724  * email_1, email_2, email_3, email_4, is_list, list_show_addresses, wants_html
3725  *
3726  * If @ebsdb was incapable of returning vcards with results that satisfy
3727  * @fields_of_interest, then @with_all_required_fields will be updated to
3728  * @FALSE and only uid fields will be present in the returned vcards. This
3729  * can be useful when a summary query succeeds and the returned list can be
3730  * used to iterate and fetch for full required data from another persistance.
3731  *
3732  * Returns: List of EbSdbSearchData.
3733  *
3734  * Since: 3.2
3735  **/
3736 GSList *
3737 e_book_backend_sqlitedb_search (EBookBackendSqliteDB *ebsdb,
3738                                 const gchar *folderid,
3739                                 const gchar *sexp,
3740                                 GHashTable *fields_of_interest,
3741                                 gboolean *searched,
3742                                 gboolean *with_all_required_fields,
3743                                 GError **error)
3744 {
3745         GSList *search_contacts = NULL;
3746         gboolean local_searched = FALSE;
3747         gboolean local_with_all_required_fields = FALSE;
3748         gboolean query_with_list_attrs = FALSE;
3749         gboolean query_unsupported = FALSE;
3750         gboolean query_invalid = FALSE;
3751         gboolean summary_query = FALSE;
3752
3753         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
3754         g_return_val_if_fail (folderid != NULL, NULL);
3755
3756         if (sexp && !*sexp)
3757                 sexp = NULL;
3758
3759         LOCK_MUTEX (&ebsdb->priv->lock);
3760
3761         if (sexp)
3762                 summary_query = e_book_backend_sqlitedb_check_summary_query_locked (
3763                         ebsdb, sexp,
3764                         &query_with_list_attrs,
3765                         &query_unsupported, &query_invalid);
3766
3767         if (query_unsupported)
3768                 g_set_error (
3769                         error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_NOT_SUPPORTED,
3770                         _("Query contained unsupported elements"));
3771         else if (query_invalid)
3772                 g_set_error (
3773                         error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_INVALID_QUERY,
3774                         _("Invalid Query"));
3775         else if (!sexp || summary_query) {
3776                 gchar *sql_query;
3777
3778                 sql_query = sexp ? sexp_to_sql_query (ebsdb, folderid, sexp) : NULL;
3779                 search_contacts = book_backend_sqlitedb_search_query (
3780                         ebsdb, sql_query, folderid,
3781                         fields_of_interest,
3782                         &local_with_all_required_fields,
3783                         query_with_list_attrs, error);
3784                 g_free (sql_query);
3785
3786                 local_searched = TRUE;
3787
3788         } else if (ebsdb->priv->store_vcard) {
3789                 search_contacts = book_backend_sqlitedb_search_full (
3790                         ebsdb, sexp, folderid, FALSE, error);
3791
3792                 local_searched = TRUE;
3793                 local_with_all_required_fields = TRUE;
3794
3795         } else {
3796                 g_set_error (
3797                         error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
3798                         _("Full search_contacts are not stored in cache. "
3799                         "Hence only summary query is supported."));
3800         }
3801
3802         UNLOCK_MUTEX (&ebsdb->priv->lock);
3803
3804         if (searched)
3805                 *searched = local_searched;
3806         if (with_all_required_fields)
3807                 *with_all_required_fields = local_with_all_required_fields;
3808
3809         return search_contacts;
3810 }
3811
3812 /**
3813  * e_book_backend_sqlitedb_search_uids:
3814  *
3815  * FIXME: Document me.
3816  *
3817  * Since: 3.2
3818  **/
3819 GSList *
3820 e_book_backend_sqlitedb_search_uids (EBookBackendSqliteDB *ebsdb,
3821                                      const gchar *folderid,
3822                                      const gchar *sexp,
3823                                      gboolean *searched,
3824                                      GError **error)
3825 {
3826         GSList *uids = NULL;
3827         gboolean local_searched = FALSE;
3828         gboolean query_with_list_attrs = FALSE;
3829         gboolean query_unsupported = FALSE;
3830         gboolean summary_query = FALSE;
3831         gboolean query_invalid = FALSE;
3832
3833         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
3834         g_return_val_if_fail (folderid != NULL, NULL);
3835
3836         if (sexp && !*sexp)
3837                 sexp = NULL;
3838
3839         LOCK_MUTEX (&ebsdb->priv->lock);
3840
3841         if (sexp)
3842                 summary_query = e_book_backend_sqlitedb_check_summary_query_locked (
3843                         ebsdb, sexp,
3844                         &query_with_list_attrs,
3845                         &query_unsupported,
3846                         &query_invalid);
3847
3848         if (query_unsupported)
3849                 g_set_error (
3850                         error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_NOT_SUPPORTED,
3851                         _("Query contained unsupported elements"));
3852         else if (query_invalid)
3853                 g_set_error (
3854                         error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_INVALID_QUERY,
3855                         _("Invalid query"));
3856         else if (!sexp || summary_query) {
3857                 gchar *stmt;
3858                 gchar *sql_query = sexp ? sexp_to_sql_query (ebsdb, folderid, sexp) : NULL;
3859
3860                 if (sql_query && sql_query[0]) {
3861
3862                         if (query_with_list_attrs) {
3863                                 gchar *list_table = g_strconcat (folderid, "_lists", NULL);
3864
3865                                 stmt = sqlite3_mprintf (
3866                                         "SELECT DISTINCT summary.uid FROM %Q AS summary, %Q AS multi WHERE %s",
3867                                         folderid, list_table, sql_query);
3868
3869                                 g_free (list_table);
3870                         } else
3871                                 stmt = sqlite3_mprintf (
3872                                         "SELECT summary.uid FROM %Q AS summary WHERE %s",
3873                                         folderid, sql_query);
3874
3875                         book_backend_sql_exec (ebsdb->priv->db, stmt, addto_slist_cb, &uids, error);
3876                         sqlite3_free (stmt);
3877
3878                 } else {
3879                         stmt = sqlite3_mprintf ("SELECT uid FROM %Q", folderid);
3880                         book_backend_sql_exec (ebsdb->priv->db, stmt, addto_slist_cb, &uids, error);
3881                         sqlite3_free (stmt);
3882                 }
3883
3884                 local_searched = TRUE;
3885
3886                 g_free (sql_query);
3887
3888         } else if (ebsdb->priv->store_vcard) {
3889                 uids = book_backend_sqlitedb_search_full (
3890                         ebsdb, sexp, folderid, TRUE, error);
3891
3892                 local_searched = TRUE;
3893
3894         } else {
3895                 g_set_error (
3896                         error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
3897                         _("Full vcards are not stored in cache. "
3898                         "Hence only summary query is supported."));
3899         }
3900
3901         UNLOCK_MUTEX (&ebsdb->priv->lock);
3902
3903         if (searched)
3904                 *searched = local_searched;
3905
3906         return uids;
3907 }
3908
3909 static gint
3910 get_uids_and_rev_cb (gpointer user_data,
3911                      gint col,
3912                      gchar **cols,
3913                      gchar **name)
3914 {
3915         GHashTable *uids_and_rev = user_data;
3916
3917         if (col == 2 && cols[0])
3918                 g_hash_table_insert (uids_and_rev, g_strdup (cols[0]), g_strdup (cols[1] ? cols[1] : ""));
3919
3920         return 0;
3921 }
3922
3923 /**
3924  * e_book_backend_sqlitedb_get_uids_and_rev:
3925  *
3926  * Gets hash table of all uids (key) and rev (value) pairs stored
3927  * for each contact in the cache. The hash table should be freed
3928  * with g_hash_table_destroy(), if not needed anymore. Each key
3929  * and value is a newly allocated string.
3930  *
3931  * Since: 3.4
3932  **/
3933 GHashTable *
3934 e_book_backend_sqlitedb_get_uids_and_rev (EBookBackendSqliteDB *ebsdb,
3935                                           const gchar *folderid,
3936                                           GError **error)
3937 {
3938         GHashTable *uids_and_rev;
3939         gchar *stmt;
3940
3941         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
3942         g_return_val_if_fail (folderid != NULL, NULL);
3943
3944         uids_and_rev = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
3945
3946         LOCK_MUTEX (&ebsdb->priv->lock);
3947
3948         stmt = sqlite3_mprintf ("SELECT uid,rev FROM %Q", folderid);
3949         book_backend_sql_exec (
3950                 ebsdb->priv->db, stmt,
3951                 get_uids_and_rev_cb, uids_and_rev, error);
3952         sqlite3_free (stmt);
3953
3954         UNLOCK_MUTEX (&ebsdb->priv->lock);
3955
3956         return uids_and_rev;
3957 }
3958
3959 /**
3960  * e_book_backend_sqlitedb_get_is_populated:
3961  *
3962  * FIXME: Document me.
3963  *
3964  * Since: 3.2
3965  **/
3966 gboolean
3967 e_book_backend_sqlitedb_get_is_populated (EBookBackendSqliteDB *ebsdb,
3968                                           const gchar *folderid,
3969                                           GError **error)
3970 {
3971         gchar *stmt;
3972         gboolean ret = FALSE;
3973
3974         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
3975         g_return_val_if_fail (folderid != NULL, FALSE);
3976
3977         LOCK_MUTEX (&ebsdb->priv->lock);
3978
3979         stmt = sqlite3_mprintf (
3980                 "SELECT is_populated FROM folders WHERE folder_id = %Q",
3981                 folderid);
3982         book_backend_sql_exec (
3983                 ebsdb->priv->db, stmt, get_bool_cb , &ret, error);
3984         sqlite3_free (stmt);
3985
3986         UNLOCK_MUTEX (&ebsdb->priv->lock);
3987
3988         return ret;
3989
3990 }
3991
3992 /**
3993  * e_book_backend_sqlitedb_set_is_populated:
3994  *
3995  * FIXME: Document me.
3996  *
3997  * Since: 3.2
3998  **/
3999 gboolean
4000 e_book_backend_sqlitedb_set_is_populated (EBookBackendSqliteDB *ebsdb,
4001                                           const gchar *folderid,
4002                                           gboolean populated,
4003                                           GError **error)
4004 {
4005         gchar *stmt = NULL;
4006         gboolean success;
4007
4008         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
4009         g_return_val_if_fail (folderid != NULL, FALSE);
4010
4011         LOCK_MUTEX (&ebsdb->priv->lock);
4012
4013         if (!book_backend_sqlitedb_start_transaction (ebsdb, error)) {
4014                 UNLOCK_MUTEX (&ebsdb->priv->lock);
4015                 return FALSE;
4016         }
4017
4018         stmt = sqlite3_mprintf (
4019                 "UPDATE folders SET is_populated = %d "
4020                 "WHERE folder_id = %Q", populated, folderid);
4021         success = book_backend_sql_exec (
4022                 ebsdb->priv->db, stmt, NULL, NULL, error);
4023         sqlite3_free (stmt);
4024
4025         if (success)
4026                 success = book_backend_sqlitedb_commit_transaction (ebsdb, error);
4027         else
4028                 /* The GError is already set. */
4029                 book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
4030
4031         UNLOCK_MUTEX (&ebsdb->priv->lock);
4032
4033         return success;
4034 }
4035
4036 /**
4037  * e_book_backend_sqlitedb_get_revision:
4038  * @ebsdb: An #EBookBackendSqliteDB
4039  * @folderid: folder id of the address-book
4040  * @revision_out: (out) (transfer full): The location to return the current
4041  * revision
4042  * @error: A location to store any error that may have occurred
4043  *
4044  * Fetches the current revision for the address-book indicated by @folderid.
4045  *
4046  * Upon success, @revision_out will hold the returned revision, otherwise
4047  * %FALSE will be returned and @error will be updated accordingly.
4048  *
4049  * Returns: Whether the revision was successfully fetched.
4050  *
4051  * Since: 3.8
4052  */
4053 gboolean
4054 e_book_backend_sqlitedb_get_revision (EBookBackendSqliteDB *ebsdb,
4055                                       const gchar *folderid,
4056                                       gchar **revision_out,
4057                                       GError **error)
4058 {
4059         gchar *stmt;
4060         gboolean success;
4061
4062         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
4063         g_return_val_if_fail (folderid && folderid[0], FALSE);
4064         g_return_val_if_fail (revision_out != NULL && *revision_out == NULL, FALSE);
4065
4066         LOCK_MUTEX (&ebsdb->priv->lock);
4067
4068         stmt = sqlite3_mprintf (
4069                 "SELECT revision FROM folders WHERE folder_id = %Q", folderid);
4070         success = book_backend_sql_exec (
4071                 ebsdb->priv->db, stmt, get_string_cb, revision_out, error);
4072         sqlite3_free (stmt);
4073
4074         UNLOCK_MUTEX (&ebsdb->priv->lock);
4075
4076         return success;
4077 }
4078
4079 /**
4080  * e_book_backend_sqlitedb_set_revision:
4081  * @ebsdb: An #EBookBackendSqliteDB
4082  * @folderid: folder id of the address-book
4083  * @revision: The new revision
4084  * @error: A location to store any error that may have occurred
4085  *
4086  * Sets the current revision for the address-book indicated by @folderid to be @revision.
4087  *
4088  * Returns: Whether the revision was successfully set.
4089  *
4090  * Since: 3.8
4091  */
4092 gboolean
4093 e_book_backend_sqlitedb_set_revision (EBookBackendSqliteDB *ebsdb,
4094                                       const gchar *folderid,
4095                                       const gchar *revision,
4096                                       GError **error)
4097 {
4098         gchar *stmt = NULL;
4099         gboolean success;
4100
4101         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
4102         g_return_val_if_fail (folderid && folderid[0], FALSE);
4103
4104         LOCK_MUTEX (&ebsdb->priv->lock);
4105
4106         if (!book_backend_sqlitedb_start_transaction (ebsdb, error)) {
4107                 UNLOCK_MUTEX (&ebsdb->priv->lock);
4108                 return FALSE;
4109         }
4110
4111         stmt = sqlite3_mprintf (
4112                 "UPDATE folders SET revision = %Q "
4113                 "WHERE folder_id = %Q", revision, folderid);
4114         success = book_backend_sql_exec (
4115                 ebsdb->priv->db, stmt, NULL, NULL, error);
4116         sqlite3_free (stmt);
4117
4118         if (success)
4119                 success = book_backend_sqlitedb_commit_transaction (ebsdb, error);
4120         else
4121                 /* The GError is already set. */
4122                 book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
4123
4124         UNLOCK_MUTEX (&ebsdb->priv->lock);
4125
4126         return success;
4127 }
4128
4129 /**
4130  * e_book_backend_sqlitedb_get_has_partial_content 
4131  * @ebsdb: 
4132  * @folderid: 
4133  * @error: 
4134  * 
4135  * 
4136  * Returns: TRUE if the vcards stored in the db were downloaded partially. It is to indicate
4137  * the stored vcards does not contain the full data.
4138  *
4139  * Since: 3.2
4140  **/
4141 gboolean
4142 e_book_backend_sqlitedb_get_has_partial_content (EBookBackendSqliteDB *ebsdb,
4143                                                  const gchar *folderid,
4144                                                  GError **error)
4145 {
4146         gchar *stmt;
4147         gboolean ret = FALSE;
4148
4149         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
4150         g_return_val_if_fail (folderid != NULL, FALSE);
4151
4152         LOCK_MUTEX (&ebsdb->priv->lock);
4153
4154         stmt = sqlite3_mprintf (
4155                 "SELECT partial_content FROM folders "
4156                 "WHERE folder_id = %Q", folderid);
4157         book_backend_sql_exec (
4158                 ebsdb->priv->db, stmt, get_bool_cb , &ret, error);
4159         sqlite3_free (stmt);
4160
4161         UNLOCK_MUTEX (&ebsdb->priv->lock);
4162
4163         return ret;
4164 }
4165
4166 /**
4167  * e_book_backend_sqlitedb_set_has_partial_content:
4168  *
4169  * FIXME: Document me.
4170  *
4171  * Since: 3.2
4172  **/
4173 gboolean
4174 e_book_backend_sqlitedb_set_has_partial_content (EBookBackendSqliteDB *ebsdb,
4175                                                  const gchar *folderid,
4176                                                  gboolean partial_content,
4177                                                  GError **error)
4178 {
4179         gchar *stmt = NULL;
4180         gboolean success;
4181
4182         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
4183         g_return_val_if_fail (folderid != NULL, FALSE);
4184
4185         LOCK_MUTEX (&ebsdb->priv->lock);
4186
4187         if (!book_backend_sqlitedb_start_transaction (ebsdb, error)) {
4188                 UNLOCK_MUTEX (&ebsdb->priv->lock);
4189                 return FALSE;
4190         }
4191
4192         stmt = sqlite3_mprintf (
4193                 "UPDATE folders SET partial_content = %d "
4194                 "WHERE folder_id = %Q", partial_content, folderid);
4195         success = book_backend_sql_exec (
4196                 ebsdb->priv->db, stmt, NULL, NULL, error);
4197         sqlite3_free (stmt);
4198
4199         if (success)
4200                 success = book_backend_sqlitedb_commit_transaction (ebsdb, error);
4201         else
4202                 /* The GError is already set. */
4203                 book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
4204
4205         UNLOCK_MUTEX (&ebsdb->priv->lock);
4206
4207         return success;
4208 }
4209
4210 /**
4211  * e_book_backend_sqlitedb_get_contact_bdata:
4212  *
4213  * FIXME: Document me.
4214  *
4215  * Since: 3.2
4216  **/
4217 gchar *
4218 e_book_backend_sqlitedb_get_contact_bdata (EBookBackendSqliteDB *ebsdb,
4219                                            const gchar *folderid,
4220                                            const gchar *uid,
4221                                            GError **error)
4222 {
4223         gchar *stmt, *ret = NULL;
4224         gboolean success;
4225
4226         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
4227         g_return_val_if_fail (folderid != NULL, NULL);
4228         g_return_val_if_fail (uid != NULL, NULL);
4229
4230         LOCK_MUTEX (&ebsdb->priv->lock);
4231
4232         stmt = sqlite3_mprintf (
4233                 "SELECT bdata FROM %Q WHERE uid = %Q", folderid, uid);
4234         success = book_backend_sql_exec (
4235                 ebsdb->priv->db, stmt, get_string_cb , &ret, error);
4236         sqlite3_free (stmt);
4237
4238         UNLOCK_MUTEX (&ebsdb->priv->lock);
4239
4240         if (!success) {
4241                 g_warn_if_fail (ret == NULL);
4242                 return NULL;
4243         }
4244
4245         return ret;
4246 }
4247
4248 /**
4249  * e_book_backend_sqlitedb_set_contact_bdata:
4250  *
4251  * FIXME: Document me.
4252  *
4253  * Since: 3.2
4254  **/
4255 gboolean
4256 e_book_backend_sqlitedb_set_contact_bdata (EBookBackendSqliteDB *ebsdb,
4257                                            const gchar *folderid,
4258                                            const gchar *uid,
4259                                            const gchar *value,
4260                                            GError **error)
4261 {
4262         gchar *stmt = NULL;
4263         gboolean success;
4264
4265         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
4266         g_return_val_if_fail (folderid != NULL, FALSE);
4267         g_return_val_if_fail (uid != NULL, FALSE);
4268         g_return_val_if_fail (value != NULL, FALSE);
4269
4270         LOCK_MUTEX (&ebsdb->priv->lock);
4271
4272         if (!book_backend_sqlitedb_start_transaction (ebsdb, error)) {
4273                 UNLOCK_MUTEX (&ebsdb->priv->lock);
4274                 return FALSE;
4275         }
4276
4277         stmt = sqlite3_mprintf (
4278                 "UPDATE %Q SET bdata = %Q WHERE uid = %Q",
4279                 folderid, value, uid);
4280         success = book_backend_sql_exec (
4281                 ebsdb->priv->db, stmt, NULL, NULL, error);
4282         sqlite3_free (stmt);
4283
4284         if (success)
4285                 success = book_backend_sqlitedb_commit_transaction (ebsdb, error);
4286         else
4287                 /* The GError is already set. */
4288                 book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
4289
4290         UNLOCK_MUTEX (&ebsdb->priv->lock);
4291
4292         return success;
4293 }
4294
4295 /**
4296  * e_book_backend_sqlitedb_get_sync_data:
4297  *
4298  * FIXME: Document me.
4299  *
4300  * Since: 3.2
4301  **/
4302 gchar *
4303 e_book_backend_sqlitedb_get_sync_data (EBookBackendSqliteDB *ebsdb,
4304                                        const gchar *folderid,
4305                                        GError **error)
4306 {
4307         gchar *stmt, *ret = NULL;
4308
4309         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
4310         g_return_val_if_fail (folderid != NULL, NULL);
4311
4312         LOCK_MUTEX (&ebsdb->priv->lock);
4313
4314         stmt = sqlite3_mprintf (
4315                 "SELECT sync_data FROM folders WHERE folder_id = %Q",
4316                 folderid);
4317         book_backend_sql_exec (
4318                 ebsdb->priv->db, stmt, get_string_cb , &ret, error);
4319         sqlite3_free (stmt);
4320
4321         UNLOCK_MUTEX (&ebsdb->priv->lock);
4322
4323         return ret;
4324 }
4325
4326 /**
4327  * e_book_backend_sqlitedb_set_sync_data:
4328  *
4329  * FIXME: Document me.
4330  *
4331  * Since: 3.2
4332  **/
4333 gboolean
4334 e_book_backend_sqlitedb_set_sync_data (EBookBackendSqliteDB *ebsdb,
4335                                        const gchar *folderid,
4336                                        const gchar *sync_data,
4337                                        GError **error)
4338 {
4339         gchar *stmt = NULL;
4340         gboolean success;
4341
4342         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
4343         g_return_val_if_fail (folderid != NULL, FALSE);
4344         g_return_val_if_fail (sync_data != NULL, FALSE);
4345
4346         LOCK_MUTEX (&ebsdb->priv->lock);
4347
4348         if (!book_backend_sqlitedb_start_transaction (ebsdb, error)) {
4349                 UNLOCK_MUTEX (&ebsdb->priv->lock);
4350                 return FALSE;
4351         }
4352
4353         stmt = sqlite3_mprintf (
4354                 "UPDATE folders SET sync_data = %Q "
4355                 "WHERE folder_id = %Q", sync_data, folderid);
4356         success = book_backend_sql_exec (
4357                 ebsdb->priv->db, stmt, NULL, NULL, error);
4358         sqlite3_free (stmt);
4359
4360         if (success)
4361                 success = book_backend_sqlitedb_commit_transaction (ebsdb, error);
4362         else
4363                 /* The GError is already set. */
4364                 book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
4365
4366         UNLOCK_MUTEX (&ebsdb->priv->lock);
4367
4368         return success;
4369 }
4370
4371 /**
4372  * e_book_backend_sqlitedb_get_key_value:
4373  *
4374  * FIXME: Document me.
4375  *
4376  * Since: 3.2
4377  **/
4378 gchar *
4379 e_book_backend_sqlitedb_get_key_value (EBookBackendSqliteDB *ebsdb,
4380                                        const gchar *folderid,
4381                                        const gchar *key,
4382                                        GError **error)
4383 {
4384         gchar *stmt, *ret = NULL;
4385
4386         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
4387         g_return_val_if_fail (folderid != NULL, NULL);
4388         g_return_val_if_fail (key != NULL, NULL);
4389
4390         LOCK_MUTEX (&ebsdb->priv->lock);
4391
4392         stmt = sqlite3_mprintf (
4393                 "SELECT value FROM keys WHERE folder_id = %Q AND key = %Q",
4394                 folderid, key);
4395         book_backend_sql_exec (
4396                 ebsdb->priv->db, stmt, get_string_cb , &ret, error);
4397         sqlite3_free (stmt);
4398
4399         UNLOCK_MUTEX (&ebsdb->priv->lock);
4400
4401         return ret;
4402 }
4403
4404 /**
4405  * e_book_backend_sqlitedb_set_key_value:
4406  *
4407  * FIXME: Document me.
4408  *
4409  * Since: 3.2
4410  **/
4411 gboolean
4412 e_book_backend_sqlitedb_set_key_value (EBookBackendSqliteDB *ebsdb,
4413                                        const gchar *folderid,
4414                                        const gchar *key,
4415                                        const gchar *value,
4416                                        GError **error)
4417 {
4418         gchar *stmt = NULL;
4419         gboolean success;
4420
4421         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
4422         g_return_val_if_fail (folderid != NULL, FALSE);
4423         g_return_val_if_fail (key != NULL, FALSE);
4424         g_return_val_if_fail (value != NULL, FALSE);
4425
4426         LOCK_MUTEX (&ebsdb->priv->lock);
4427
4428         if (!book_backend_sqlitedb_start_transaction (ebsdb, error)) {
4429                 UNLOCK_MUTEX (&ebsdb->priv->lock);
4430                 return FALSE;
4431         }
4432
4433         stmt = sqlite3_mprintf (
4434                 "INSERT or REPLACE INTO keys (key, value, folder_id) "
4435                 "values (%Q, %Q, %Q)", key, value, folderid);
4436         success = book_backend_sql_exec (
4437                 ebsdb->priv->db, stmt, NULL, NULL, error);
4438         sqlite3_free (stmt);
4439
4440         if (success)
4441                 success = book_backend_sqlitedb_commit_transaction (ebsdb, error);
4442         else
4443                 /* The GError is already set. */
4444                 book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
4445
4446         UNLOCK_MUTEX (&ebsdb->priv->lock);
4447
4448         return success;
4449 }
4450
4451 /**
4452  * e_book_backend_sqlitedb_get_partially_cached_ids:
4453  *
4454  * FIXME: Document me.
4455  *
4456  * Since: 3.2
4457  **/
4458 GSList *
4459 e_book_backend_sqlitedb_get_partially_cached_ids (EBookBackendSqliteDB *ebsdb,
4460                                                   const gchar *folderid,
4461                                                   GError **error)
4462 {
4463         gchar *stmt;
4464         GSList *uids = NULL;
4465
4466         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
4467         g_return_val_if_fail (folderid != NULL, NULL);
4468
4469         LOCK_MUTEX (&ebsdb->priv->lock);
4470
4471         stmt = sqlite3_mprintf (
4472                 "SELECT uid FROM %Q WHERE partial_content = 1",
4473                 folderid);
4474         book_backend_sql_exec (
4475                 ebsdb->priv->db, stmt, addto_slist_cb, &uids, error);
4476         sqlite3_free (stmt);
4477
4478         UNLOCK_MUTEX (&ebsdb->priv->lock);
4479
4480         return uids;
4481 }
4482
4483 /**
4484  * e_book_backend_sqlitedb_delete_addressbook:
4485  *
4486  * FIXME: Document me.
4487  *
4488  * Since: 3.2
4489  **/
4490 gboolean
4491 e_book_backend_sqlitedb_delete_addressbook (EBookBackendSqliteDB *ebsdb,
4492                                             const gchar *folderid,
4493                                             GError **error)
4494 {
4495         gchar *stmt;
4496         gboolean success;
4497
4498         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
4499         g_return_val_if_fail (folderid != NULL, FALSE);
4500
4501         LOCK_MUTEX (&ebsdb->priv->lock);
4502
4503         if (!book_backend_sqlitedb_start_transaction (ebsdb, error)) {
4504                 UNLOCK_MUTEX (&ebsdb->priv->lock);
4505                 return FALSE;
4506         }
4507
4508         /* delete the contacts table */
4509         stmt = sqlite3_mprintf ("DROP TABLE %Q ", folderid);
4510         success = book_backend_sql_exec (
4511                 ebsdb->priv->db, stmt, NULL, NULL, error);
4512         sqlite3_free (stmt);
4513
4514         if (!success)
4515                 goto rollback;
4516
4517         /* delete the key/value pairs corresponding to this table */
4518         stmt = sqlite3_mprintf (
4519                 "DELETE FROM keys WHERE folder_id = %Q", folderid);
4520         success = book_backend_sql_exec (
4521                 ebsdb->priv->db, stmt, NULL, NULL, error);
4522         sqlite3_free (stmt);
4523
4524         if (!success)
4525                 goto rollback;
4526
4527         /* delete the folder from the folders table */
4528         stmt = sqlite3_mprintf (
4529                 "DELETE FROM folders WHERE folder_id = %Q", folderid);
4530         success = book_backend_sql_exec (
4531                 ebsdb->priv->db, stmt, NULL, NULL, error);
4532         sqlite3_free (stmt);
4533
4534         if (!success)
4535                 goto rollback;
4536
4537         success = book_backend_sqlitedb_commit_transaction (ebsdb, error);
4538         UNLOCK_MUTEX (&ebsdb->priv->lock);
4539
4540         return success;
4541
4542 rollback:
4543         /* The GError is already set. */
4544         book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
4545
4546         UNLOCK_MUTEX (&ebsdb->priv->lock);
4547
4548         return FALSE;
4549 }
4550
4551 /**
4552  * e_book_backend_sqlitedb_search_data_free:
4553  *
4554  * FIXME: Document me.
4555  *
4556  * Since: 3.2
4557  **/
4558 void
4559 e_book_backend_sqlitedb_search_data_free (EbSdbSearchData *s_data)
4560 {
4561         if (s_data) {
4562                 g_free (s_data->uid);
4563                 g_free (s_data->vcard);
4564                 g_free (s_data->bdata);
4565                 g_slice_free (EbSdbSearchData, s_data);
4566         }
4567 }
4568
4569 /**
4570  * e_book_backend_sqlitedb_remove:
4571  *
4572  * FIXME: Document me.
4573  *
4574  * Since: 3.2
4575  **/
4576 gboolean
4577 e_book_backend_sqlitedb_remove (EBookBackendSqliteDB *ebsdb,
4578                                 GError **error)
4579 {
4580         gchar *filename;
4581         gint ret;
4582
4583         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
4584
4585         LOCK_MUTEX (&ebsdb->priv->lock);
4586
4587         sqlite3_close (ebsdb->priv->db);
4588
4589         filename = g_build_filename (ebsdb->priv->path, DB_FILENAME, NULL);
4590         ret = g_unlink (filename);
4591         g_free (filename);
4592
4593         UNLOCK_MUTEX (&ebsdb->priv->lock);
4594
4595         if (ret == -1) {
4596                 g_set_error (
4597                         error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
4598                         _("Unable to remove the db file: errno %d"), errno);
4599                 return FALSE;
4600         }
4601
4602         return TRUE;
4603 }
4604
4605 static void
4606 destroy_search_data (gpointer data)
4607 {
4608         e_book_backend_sqlitedb_search_data_free (data);
4609 }
4610
4611 static gboolean
4612 upgrade_contacts_table (EBookBackendSqliteDB *ebsdb,
4613                         const gchar *folderid,
4614                         GError **error)
4615 {
4616         gchar *stmt;
4617         gboolean success = FALSE;
4618         GSList *vcard_data = NULL;
4619         GSList *l;
4620         gchar *default_region = NULL;
4621
4622         stmt = sqlite3_mprintf ("SELECT uid, vcard, NULL FROM %Q", folderid);
4623         success = book_backend_sql_exec (
4624                 ebsdb->priv->db, stmt, addto_vcard_list_cb, &vcard_data, error);
4625         sqlite3_free (stmt);
4626
4627         if (vcard_data == NULL)
4628                 return TRUE;
4629
4630         if (e_phone_number_is_supported ()) {
4631                 default_region = e_phone_number_get_default_region (error);
4632
4633                 if (default_region == NULL)
4634                         success = FALSE;
4635         }
4636
4637         success = book_backend_sqlitedb_start_transaction (ebsdb, error);
4638
4639         if (success) {
4640
4641                 for (l = vcard_data; success && l; l = l->next) {
4642                         EbSdbSearchData *const s_data = l->data;
4643                         EContact *contact = e_contact_new_from_vcard_with_uid (s_data->vcard, s_data->uid);
4644
4645                         if (contact == NULL)
4646                                 continue;
4647
4648                         success = insert_contact (ebsdb, contact, folderid, TRUE, default_region, error);
4649
4650                         g_object_unref (contact);
4651                 }
4652
4653                 if (success)
4654                         success = book_backend_sqlitedb_commit_transaction (ebsdb, error);
4655                 else
4656                         /* The GError is already set. */
4657                         book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
4658         }
4659
4660         g_slist_free_full (vcard_data, destroy_search_data);
4661         g_free (default_region);
4662
4663         return success;
4664 }