Make use of G_DEFINE_QUARK()
[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 <string.h>
23 #include <ctype.h>
24 #include <stdlib.h>
25 #include <errno.h>
26
27 #include <glib/gi18n.h>
28 #include <glib/gstdio.h>
29
30 #include <sqlite3.h>
31 #include <libebackend/libebackend.h>
32
33 #include "e-book-backend-sexp.h"
34 #include "e-book-backend-sqlitedb.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 #define DB_FILENAME "contacts.db"
43 #define FOLDER_VERSION 3
44
45 #define READER_LOCK(ebsdb) g_rw_lock_reader_lock (&ebsdb->priv->rwlock)
46 #define READER_UNLOCK(ebsdb) g_rw_lock_reader_unlock (&ebsdb->priv->rwlock)
47 #define WRITER_LOCK(ebssdb) g_rw_lock_writer_lock (&ebsdb->priv->rwlock)
48 #define WRITER_UNLOCK(ebssdb) g_rw_lock_writer_unlock (&ebsdb->priv->rwlock)
49
50 typedef enum {
51         INDEX_PREFIX = (1 << 0),
52         INDEX_SUFFIX = (1 << 1)
53 } IndexFlags;
54
55 typedef struct {
56         EContactField field;   /* The EContact field */
57         GType         type;    /* The GType (only support string or gboolean) */
58         const gchar  *dbname;  /* The key for this field in the sqlite3 table */
59         IndexFlags    index;   /* Whether this summary field should have an index in the SQLite DB */
60 } SummaryField;
61
62 struct _EBookBackendSqliteDBPrivate {
63         sqlite3 *db;
64         gchar *path;
65         gchar *hash_key;
66
67         gboolean store_vcard;
68         GRWLock rwlock;
69
70         GMutex in_transaction_lock;
71         guint32 in_transaction;
72
73         SummaryField   *summary_fields;
74         gint            n_summary_fields;
75         guint           have_attr_list : 1;
76         guint           have_attr_list_prefix : 1;
77         guint           have_attr_list_suffix : 1;
78 };
79
80 G_DEFINE_TYPE (EBookBackendSqliteDB, e_book_backend_sqlitedb, G_TYPE_OBJECT)
81
82
83 static GHashTable *db_connections = NULL;
84 static GMutex dbcon_lock;
85
86 static EContactField default_summary_fields[] = {
87         E_CONTACT_UID,
88         E_CONTACT_REV,
89         E_CONTACT_FILE_AS,
90         E_CONTACT_NICKNAME,
91         E_CONTACT_FULL_NAME,
92         E_CONTACT_GIVEN_NAME,
93         E_CONTACT_FAMILY_NAME,
94         E_CONTACT_EMAIL,
95         E_CONTACT_IS_LIST,
96         E_CONTACT_LIST_SHOW_ADDRESSES,
97         E_CONTACT_WANTS_HTML
98 };
99
100 /* Create indexes on full_name and email fields as autocompletion queries would mainly
101  * rely on this.
102  */
103 static EContactField default_indexed_fields[] = {
104         E_CONTACT_FULL_NAME,
105         E_CONTACT_EMAIL
106 };
107
108 static EBookIndexType default_index_types[] = {
109         E_BOOK_INDEX_PREFIX,
110         E_BOOK_INDEX_PREFIX
111 };
112
113 static gboolean append_summary_field (GArray         *array,
114                                       EContactField   field,
115                                       gboolean       *have_attr_list,
116                                       GError        **error);
117
118 static const gchar *
119 summary_dbname_from_field (EBookBackendSqliteDB *ebsdb,
120                            EContactField field)
121 {
122         gint i;
123
124         for (i = 0; i < ebsdb->priv->n_summary_fields; i++) {
125                 if (ebsdb->priv->summary_fields[i].field == field)
126                         return ebsdb->priv->summary_fields[i].dbname;
127         }
128
129         return NULL;
130 }
131
132 static gint
133 summary_index_from_field_name (EBookBackendSqliteDB *ebsdb,
134                                const gchar *field_name)
135 {
136         gint i;
137         EContactField field;
138
139         field = e_contact_field_id (field_name);
140
141         for (i = 0; i < ebsdb->priv->n_summary_fields; i++) {
142                 if (ebsdb->priv->summary_fields[i].field == field)
143                         return i;
144         }
145
146         return -1;
147 }
148
149 typedef struct {
150         EBookBackendSqliteDB *ebsdb;
151         GSList *list;
152 } StoreVCardData;
153
154 G_DEFINE_QUARK (
155         e-book-backend-sqlitedb-error-quark,
156         e_book_backend_sqlitedb_error)
157
158 static void
159 e_book_backend_sqlitedb_dispose (GObject *object)
160 {
161         EBookBackendSqliteDBPrivate *priv;
162
163         priv = E_BOOK_BACKEND_SQLITEDB_GET_PRIVATE (object);
164
165         g_mutex_lock (&dbcon_lock);
166         if (db_connections != NULL) {
167                 if (priv->hash_key != NULL) {
168                         g_hash_table_remove (db_connections, priv->hash_key);
169
170                         if (g_hash_table_size (db_connections) == 0) {
171                                 g_hash_table_destroy (db_connections);
172                                 db_connections = NULL;
173                         }
174
175                         g_free (priv->hash_key);
176                         priv->hash_key = NULL;
177                 }
178         }
179         g_mutex_unlock (&dbcon_lock);
180
181         /* Chain up to parent's dispose() method. */
182         G_OBJECT_CLASS (e_book_backend_sqlitedb_parent_class)->dispose (object);
183 }
184
185 static void
186 e_book_backend_sqlitedb_finalize (GObject *object)
187 {
188         EBookBackendSqliteDBPrivate *priv;
189
190         priv = E_BOOK_BACKEND_SQLITEDB_GET_PRIVATE (object);
191
192         g_rw_lock_clear (&priv->rwlock);
193
194         sqlite3_close (priv->db);
195
196         g_free (priv->path);
197         g_free (priv->summary_fields);
198
199         g_mutex_clear (&priv->in_transaction_lock);
200
201         /* Chain up to parent's finalize() method. */
202         G_OBJECT_CLASS (e_book_backend_sqlitedb_parent_class)->finalize (object);
203 }
204
205 static void
206 e_book_backend_sqlitedb_class_init (EBookBackendSqliteDBClass *class)
207 {
208         GObjectClass *object_class;
209
210         g_type_class_add_private (class, sizeof (EBookBackendSqliteDBPrivate));
211
212         object_class = G_OBJECT_CLASS (class);
213         object_class->dispose = e_book_backend_sqlitedb_dispose;
214         object_class->finalize = e_book_backend_sqlitedb_finalize;
215 }
216
217 static void
218 e_book_backend_sqlitedb_init (EBookBackendSqliteDB *ebsdb)
219 {
220         ebsdb->priv = E_BOOK_BACKEND_SQLITEDB_GET_PRIVATE (ebsdb);
221
222         ebsdb->priv->store_vcard = TRUE;
223         g_rw_lock_init (&ebsdb->priv->rwlock);
224
225         ebsdb->priv->in_transaction = 0;
226         g_mutex_init (&ebsdb->priv->in_transaction_lock);
227 }
228
229 static gint
230 get_string_cb (gpointer ref,
231                gint col,
232                gchar **cols,
233                gchar **name)
234 {
235         gchar **ret = ref;
236
237         *ret = g_strdup (cols [0]);
238
239         return 0;
240 }
241
242 static gint
243 get_bool_cb (gpointer ref,
244              gint col,
245              gchar **cols,
246              gchar **name)
247 {
248         gboolean *ret = ref;
249
250         *ret = cols [0] ? strtoul (cols [0], NULL, 10) : 0;
251
252         return 0;
253 }
254
255 /**
256  * e_book_sql_exec
257  * @db:
258  * @stmt:
259  * @callback:
260  * @data:
261  * @error:
262  *
263  * Callers should hold the rw lock depending on read or write operation
264  * Returns:
265  **/
266 static gboolean
267 book_backend_sql_exec_real (sqlite3 *db,
268                             const gchar *stmt,
269                             gint (*callback)(gpointer ,gint,gchar **,gchar **),
270                             gpointer data,
271                             GError **error)
272 {
273         gchar *errmsg = NULL;
274         gint ret = -1;
275
276         ret = sqlite3_exec (db, stmt, callback, data, &errmsg);
277         while (ret == SQLITE_BUSY || ret == SQLITE_LOCKED || ret == -1) {
278                 if (errmsg) {
279                         sqlite3_free (errmsg);
280                         errmsg = NULL;
281                 }
282                 g_thread_yield ();
283                 ret = sqlite3_exec (db, stmt, callback, data, &errmsg);
284         }
285
286         if (ret != SQLITE_OK) {
287                 d (g_print ("Error in SQL EXEC statement: %s [%s].\n", stmt, errmsg));
288                 g_set_error_literal (
289                         error, E_BOOK_SDB_ERROR,
290                         ret == SQLITE_CONSTRAINT ?
291                         E_BOOK_SDB_ERROR_CONSTRAINT : E_BOOK_SDB_ERROR_OTHER,
292                         errmsg);
293                 sqlite3_free (errmsg);
294                 errmsg = NULL;
295                 return FALSE;
296         }
297
298         if (errmsg) {
299                 sqlite3_free (errmsg);
300                 errmsg = NULL;
301         }
302
303         return TRUE;
304 }
305
306 static gint
307 print_debug_cb (gpointer ref,
308                 gint col,
309                 gchar **cols,
310                 gchar **name)
311 {
312         gint i;
313
314         g_print ("  DEBUG BEGIN: %d results\n", col);
315
316         for (i = 0; i < col; i++)
317                 g_print ("    NAME: '%s' COL: %s\n", name[i], cols[i]);
318
319         g_print ("  DEBUG END\n");
320
321         return 0;
322 }
323
324 static void
325 book_backend_sql_debug (sqlite3 *db,
326                         const gchar *stmt,
327                         gint (*callback)(gpointer ,gint,gchar **,gchar **),
328                         gpointer data,
329                         GError **error)
330 {
331         gchar *debug;
332         GError *local_error = NULL;
333         debug = g_strconcat ("EXPLAIN QUERY PLAN ", stmt, NULL);
334
335         g_print ("DEBUG STATEMENT: %s\n", stmt);
336         book_backend_sql_exec_real (db, debug, print_debug_cb, NULL, &local_error);
337         g_print ("DEBUG STATEMENT END: %s%s\n", local_error ? "Error: " : "", local_error ? local_error->message : "Success");
338         g_free (debug);
339
340         g_clear_error (&local_error);
341 }
342
343 static gboolean
344 book_backend_sql_exec (sqlite3 *db,
345                        const gchar *stmt,
346                        gint (*callback)(gpointer ,gint,gchar **,gchar **),
347                        gpointer data,
348                        GError **error)
349 {
350         static gint booksql_debug = -1;
351
352         if (booksql_debug == -1) {
353                 booksql_debug = g_getenv ("BOOKSQL_DEBUG") != NULL ? 1 : 0;
354         }
355
356         if (booksql_debug)
357                 book_backend_sql_debug (db, stmt, callback, data, error);
358
359         return book_backend_sql_exec_real (db, stmt, callback, data, error);
360 }
361
362 /* the first caller holds the writer lock too */
363 static gboolean
364 book_backend_sqlitedb_start_transaction (EBookBackendSqliteDB *ebsdb,
365                                          GError **error)
366 {
367         gboolean success = TRUE;
368
369         g_return_val_if_fail (ebsdb != NULL, FALSE);
370         g_return_val_if_fail (ebsdb->priv != NULL, FALSE);
371         g_return_val_if_fail (ebsdb->priv->db != NULL, FALSE);
372
373         g_mutex_lock (&ebsdb->priv->in_transaction_lock);
374
375         ebsdb->priv->in_transaction++;
376         if (ebsdb->priv->in_transaction == 0) {
377                 g_mutex_unlock (&ebsdb->priv->in_transaction_lock);
378
379                 g_return_val_if_fail (ebsdb->priv->in_transaction != 0, FALSE);
380                 return FALSE;
381         }
382
383         if (ebsdb->priv->in_transaction == 1) {
384                 WRITER_LOCK (ebsdb);
385
386                 success = book_backend_sql_exec (
387                         ebsdb->priv->db, "BEGIN", NULL, NULL, error);
388         }
389
390         g_mutex_unlock (&ebsdb->priv->in_transaction_lock);
391
392         return success;
393 }
394
395 /* the last caller releases the writer lock too */
396 static gboolean
397 book_backend_sqlitedb_commit_transaction (EBookBackendSqliteDB *ebsdb,
398                                           GError **error)
399 {
400         gboolean success = TRUE;
401
402         g_return_val_if_fail (ebsdb != NULL, FALSE);
403         g_return_val_if_fail (ebsdb->priv != NULL, FALSE);
404         g_return_val_if_fail (ebsdb->priv->db != NULL, FALSE);
405
406         g_mutex_lock (&ebsdb->priv->in_transaction_lock);
407
408         if (ebsdb->priv->in_transaction == 0) {
409                 g_mutex_unlock (&ebsdb->priv->in_transaction_lock);
410
411                 g_return_val_if_fail (ebsdb->priv->in_transaction > 0, FALSE);
412                 return FALSE;
413         }
414
415         ebsdb->priv->in_transaction--;
416
417         if (ebsdb->priv->in_transaction == 0) {
418                 success = book_backend_sql_exec (
419                         ebsdb->priv->db, "COMMIT", NULL, NULL, error);
420
421                 WRITER_UNLOCK (ebsdb);
422         }
423
424         g_mutex_unlock (&ebsdb->priv->in_transaction_lock);
425
426         return success;
427 }
428
429 /* the last caller releases the writer lock too */
430 static gboolean
431 book_backend_sqlitedb_rollback_transaction (EBookBackendSqliteDB *ebsdb,
432                                             GError **error)
433 {
434         gboolean success = TRUE;
435
436         g_return_val_if_fail (ebsdb != NULL, FALSE);
437         g_return_val_if_fail (ebsdb->priv != NULL, FALSE);
438         g_return_val_if_fail (ebsdb->priv->db != NULL, FALSE);
439
440         g_mutex_lock (&ebsdb->priv->in_transaction_lock);
441
442         if (ebsdb->priv->in_transaction == 0) {
443                 g_mutex_unlock (&ebsdb->priv->in_transaction_lock);
444
445                 g_return_val_if_fail (ebsdb->priv->in_transaction > 0, FALSE);
446                 return FALSE;
447         }
448
449         ebsdb->priv->in_transaction--;
450
451         if (ebsdb->priv->in_transaction == 0) {
452                 success = book_backend_sql_exec (
453                         ebsdb->priv->db, "ROLLBACK", NULL, NULL, error);
454
455                 WRITER_UNLOCK (ebsdb);
456         }
457
458         g_mutex_unlock (&ebsdb->priv->in_transaction_lock);
459
460         return success;
461 }
462
463 static gint
464 collect_versions_cb (gpointer ref,
465                      gint col,
466                      gchar **cols,
467                      gchar **name)
468 {
469         gint *ret = ref;
470
471         /* Just collect the first result, all folders
472          * should always have the same DB version. */
473         *ret = cols [0] ? strtoul (cols [0], NULL, 10) : 0;
474
475         return 0;
476 }
477
478 static gboolean
479 create_folders_table (EBookBackendSqliteDB *ebsdb,
480                       GError **error)
481 {
482         gboolean success;
483         gint version = 0;
484
485         /* sync_data points to syncronization data, it could be last_modified
486          * time or a sequence number or some text depending on the backend.
487          *
488          * partial_content says whether the contents are partially downloaded
489          * for auto-completion or if it has the complete content.
490          *
491          * Have not included a bdata here since the keys table should suffice
492          * any additional need that arises.
493          */
494         const gchar *stmt =
495                 "CREATE TABLE IF NOT EXISTS folders"
496                 "( folder_id  TEXT PRIMARY KEY,"
497                 " folder_name TEXT,"
498                 "  sync_data TEXT,"
499                 " is_populated INTEGER,"
500                 "  partial_content INTEGER,"
501                 " version INTEGER,"
502                 "  revision TEXT,"
503                 " multivalues TEXT,"
504                 "  reverse_multivalues INTEGER )";
505
506         if (!book_backend_sqlitedb_start_transaction (ebsdb, error))
507                 return FALSE;
508
509         if (!book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error))
510                 goto rollback;
511
512         /* Create a child table to store key/value pairs for a folder. */
513         stmt =  "CREATE TABLE IF NOT EXISTS keys"
514                 "( key TEXT PRIMARY KEY, value TEXT,"
515                 " folder_id TEXT REFERENCES folders)";
516         if (!book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error))
517                 goto rollback;
518
519         stmt = "CREATE INDEX IF NOT EXISTS keysindex ON keys(folder_id)";
520         if (!book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error))
521                 goto rollback;
522
523         /* Fetch the version, it should be the
524          * same for all folders (hence the LIMIT). */
525         stmt = "SELECT version FROM folders LIMIT 1";
526         success = book_backend_sql_exec (
527                 ebsdb->priv->db, stmt, collect_versions_cb, &version, error);
528
529         if (!success)
530                 goto rollback;
531
532         /* Upgrade DB to version 2, add revision column
533          *
534          * (version = 0 indicates that it did not exist and we just
535          * created the table)
536          */
537         if (version >= 1 && version < 2) {
538                 stmt = "ALTER TABLE folders ADD COLUMN revision TEXT";
539                 success = book_backend_sql_exec (
540                         ebsdb->priv->db, stmt, NULL, NULL, error);
541
542                 if (!success)
543                         goto rollback;
544         }
545
546         /* Upgrade DB to version 3, add multivalues introspection columns
547          */
548         if (version >= 1 && version < 3) {
549
550                 stmt = "ALTER TABLE folders ADD COLUMN multivalues TEXT";
551                 success = book_backend_sql_exec (
552                         ebsdb->priv->db, stmt, NULL, NULL, error);
553
554                 if (!success)
555                         goto rollback;
556
557                 stmt = "ALTER TABLE folders ADD COLUMN reverse_multivalues INTEGER";
558                 success = book_backend_sql_exec (
559                         ebsdb->priv->db, stmt, NULL, NULL, error);
560
561                 if (!success)
562                         goto rollback;
563         }
564
565         if (version >= 1 && version < FOLDER_VERSION) {
566                 gchar *version_update_stmt =
567                         sqlite3_mprintf ("UPDATE folders SET version = %d", FOLDER_VERSION);
568
569                 success = book_backend_sql_exec (
570                         ebsdb->priv->db, version_update_stmt, NULL, NULL, error);
571
572                 sqlite3_free (version_update_stmt);
573         }
574
575         if (!success)
576                 goto rollback;
577
578         return book_backend_sqlitedb_commit_transaction (ebsdb, error);
579
580 rollback:
581         /* The GError is already set. */
582         book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
583
584         return FALSE;
585 }
586
587 static gchar *
588 format_multivalues (EBookBackendSqliteDB *ebsdb,
589                     gboolean *reverse_multivalues)
590 {
591         gint i;
592         GString *string;
593         gboolean first = TRUE;
594         gboolean has_reverse = FALSE;
595
596         string = g_string_new (NULL);
597
598         for (i = 0; i < ebsdb->priv->n_summary_fields; i++) {
599                 if (ebsdb->priv->summary_fields[i].type == E_TYPE_CONTACT_ATTR_LIST) {
600                         if (first)
601                                 first = FALSE;
602                         else
603                                 g_string_append_c (string, ':');
604
605                         g_string_append (string, ebsdb->priv->summary_fields[i].dbname);
606
607                         if ((ebsdb->priv->summary_fields[i].index & INDEX_SUFFIX) != 0)
608                                 has_reverse = TRUE;
609                 }
610         }
611
612         if (reverse_multivalues)
613                 *reverse_multivalues = has_reverse;
614
615         return g_string_free (string, FALSE);
616 }
617
618 static gboolean
619 add_folder_into_db (EBookBackendSqliteDB *ebsdb,
620                     const gchar *folderid,
621                     const gchar *folder_name,
622                     GError **error)
623 {
624         gchar *stmt;
625         gboolean success;
626         gboolean has_reverse = FALSE;
627         gchar *multivalues;
628
629         if (!book_backend_sqlitedb_start_transaction (ebsdb, error))
630                 return FALSE;
631
632         multivalues = format_multivalues (ebsdb, &has_reverse);
633
634         stmt = sqlite3_mprintf (
635                 "INSERT OR IGNORE INTO folders VALUES "
636                 "( %Q, %Q, %Q, %d, %d, %d, %Q, %Q, %d ) ",
637                 folderid, folder_name, NULL, 0, 0, FOLDER_VERSION,
638                 NULL, multivalues, has_reverse);
639         success = book_backend_sql_exec (
640                 ebsdb->priv->db, stmt, NULL, NULL, error);
641         sqlite3_free (stmt);
642         g_free (multivalues);
643
644         if (!success)
645                 goto rollback;
646
647         return book_backend_sqlitedb_commit_transaction (ebsdb, error);
648
649 rollback:
650         book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
651
652         return FALSE;
653 }
654
655 static gint
656 collect_columns_cb (gpointer ref,
657                     gint col,
658                     gchar **cols,
659                     gchar **name)
660 {
661         GList **columns = (GList **) ref;
662         gint i;
663
664         for (i = 0; i < col; i++) {
665
666                 if (strcmp (name[i], "name") == 0) {
667
668                         if (strcmp (cols[i], "vcard") != 0 &&
669                             strcmp (cols[i], "bdata") != 0) {
670
671                                 gchar *column = g_strdup (cols[i]);
672
673                                 *columns = g_list_prepend (*columns, column);
674                         }
675
676                         break;
677                 }
678         }
679
680         return 0;
681 }
682
683 static gboolean
684 introspect_summary (EBookBackendSqliteDB *ebsdb,
685                     const gchar *folderid,
686                     GError **error)
687 {
688         gboolean success;
689         gchar *stmt;
690         GList *summary_columns = NULL, *l;
691         GArray *summary_fields = NULL;
692         gchar *multivalues = NULL;
693         gboolean reverse_multivalues = FALSE;
694         gchar **split;
695         gint i;
696
697         stmt = sqlite3_mprintf ("PRAGMA table_info (%Q);", folderid);
698         success = book_backend_sql_exec (
699                 ebsdb->priv->db, stmt, collect_columns_cb, &summary_columns, error);
700         sqlite3_free (stmt);
701
702         if (!success)
703                 goto introspect_summary_finish;
704
705         summary_columns = g_list_reverse (summary_columns);
706         summary_fields = g_array_new (FALSE, FALSE, sizeof (SummaryField));
707
708         /* Introspect the normal summary fields */
709         for (l = summary_columns; l; l = l->next) {
710                 EContactField field;
711                 gchar *col = l->data;
712                 gchar *p;
713                 gboolean reverse = FALSE;
714
715                 /* Check if we're parsing a reverse field */
716                 p = strstr (col, "_reverse");
717                 if (p) {
718                         *p = '\0';
719                         reverse = TRUE;
720                 }
721
722                 /* First check exception fields */
723                 if (g_ascii_strcasecmp (col, "uid") == 0)
724                         field = E_CONTACT_UID;
725                 else if (g_ascii_strcasecmp (col, "is_list") == 0)
726                         field = E_CONTACT_IS_LIST;
727                 else
728                         field = e_contact_field_id (col);
729
730                 /* Check for parse error */
731                 if (field == 0) {
732                         g_set_error (
733                                 error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
734                                 _("Error introspecting unknown summary field '%s'"), col);
735                         success = FALSE;
736                         break;
737                 }
738
739                 /* Reverse columns are always declared after the normal columns,
740                  * if a reverse field is encountered we need to set the suffix
741                  * index on the coresponding summary field
742                  */
743                 if (reverse) {
744                         for (i = 0; i < summary_fields->len; i++) {
745                                 SummaryField *iter = &g_array_index (summary_fields, SummaryField, i);
746
747                                 if (iter->field == field) {
748                                         iter->index |= INDEX_SUFFIX;
749                                         break;
750                                 }
751                         }
752                 } else {
753                         append_summary_field (summary_fields, field, NULL, NULL);
754                 }
755         }
756
757         if (!success)
758                 goto introspect_summary_finish;
759
760         /* Introspect the multivalied summary fields */
761         stmt = sqlite3_mprintf (
762                 "SELECT multivalues FROM folders WHERE folder_id = %Q", folderid);
763         success = book_backend_sql_exec (
764                 ebsdb->priv->db, stmt, get_string_cb, &multivalues, error);
765         sqlite3_free (stmt);
766
767         if (!success)
768                 goto introspect_summary_finish;
769
770         stmt = sqlite3_mprintf (
771                 "SELECT reverse_multivalues FROM folders WHERE folder_id = %Q", folderid);
772         success = book_backend_sql_exec (
773                 ebsdb->priv->db, stmt, get_bool_cb, &reverse_multivalues, error);
774         sqlite3_free (stmt);
775
776         if (!success)
777                 goto introspect_summary_finish;
778
779         if (multivalues) {
780                 split = g_strsplit (multivalues, ":", 0);
781
782                 for (i = 0; split[i] != NULL; i++) {
783                         EContactField field;
784
785                         field = e_contact_field_id (split[i]);
786                         append_summary_field (summary_fields, field, NULL, NULL);
787                 }
788                 g_strfreev (split);
789         }
790
791         /* If there is a reverse multivalue column, enable lookups for every multivalue field in reverse */
792         if (reverse_multivalues) {
793
794                 for (i = 0; i < summary_fields->len; i++) {
795                         SummaryField *iter = &g_array_index (summary_fields, SummaryField, i);
796
797                         if (iter->type == E_TYPE_CONTACT_ATTR_LIST)
798                                 iter->index |= INDEX_SUFFIX;
799                 }
800         }
801
802  introspect_summary_finish:
803
804         g_list_free_full (summary_columns, (GDestroyNotify) g_free);
805         g_free (multivalues);
806
807         /* Apply the introspected summary fields */
808         if (success) {
809                 g_free (ebsdb->priv->summary_fields);
810                 ebsdb->priv->n_summary_fields = summary_fields->len;
811                 ebsdb->priv->summary_fields = (SummaryField *) g_array_free (summary_fields, FALSE);
812         } else if (summary_fields) {
813                 g_array_free (summary_fields, TRUE);
814         }
815
816         return success;
817 }
818
819 /* The column names match the fields used in book-backend-sexp */
820 static gboolean
821 create_contacts_table (EBookBackendSqliteDB *ebsdb,
822                        const gchar *folderid,
823                        GError **error)
824 {
825         gint i;
826         gboolean success;
827         gchar *stmt, *tmp;
828         GString *string;
829
830         /* Construct the create statement from the summary fields table */
831         string = g_string_new (
832                 "CREATE TABLE IF NOT EXISTS %Q ( uid TEXT PRIMARY KEY, ");
833
834         for (i = 1; i < ebsdb->priv->n_summary_fields; i++) {
835                 if (ebsdb->priv->summary_fields[i].type == G_TYPE_STRING) {
836                         g_string_append (string, ebsdb->priv->summary_fields[i].dbname);
837                         g_string_append (string, " TEXT, ");
838                 } else if (ebsdb->priv->summary_fields[i].type == G_TYPE_BOOLEAN) {
839                         g_string_append (string, ebsdb->priv->summary_fields[i].dbname);
840                         g_string_append (string, " INTEGER, ");
841                 } else if (ebsdb->priv->summary_fields[i].type != E_TYPE_CONTACT_ATTR_LIST)
842                         g_warn_if_reached ();
843
844                 /* Additional columns holding normalized reverse values for suffix matching */
845                 if (ebsdb->priv->summary_fields[i].type == G_TYPE_STRING &&
846                     (ebsdb->priv->summary_fields[i].index & INDEX_SUFFIX) != 0) {
847                         g_string_append  (string, ebsdb->priv->summary_fields[i].dbname);
848                         g_string_append  (string, "_reverse TEXT, ");
849                 }
850         }
851         g_string_append (string, "vcard TEXT, bdata TEXT)");
852
853         stmt = sqlite3_mprintf (string->str, folderid);
854         g_string_free (string, TRUE);
855
856         WRITER_LOCK (ebsdb);
857
858         success = book_backend_sql_exec (
859                 ebsdb->priv->db, stmt, NULL, NULL , error);
860
861         sqlite3_free (stmt);
862
863         /* Create indexes on the summary fields configured for indexing */
864         for (i = 0; success && i < ebsdb->priv->n_summary_fields; i++) {
865                 if ((ebsdb->priv->summary_fields[i].index & INDEX_PREFIX) != 0 &&
866                     ebsdb->priv->summary_fields[i].type != E_TYPE_CONTACT_ATTR_LIST) {
867                         /* Derive index name from field & folder */
868                         tmp = g_strdup_printf (
869                                 "INDEX_%s_%s",
870                                 summary_dbname_from_field (ebsdb, ebsdb->priv->summary_fields[i].field),
871                                 folderid);
872                         stmt = sqlite3_mprintf (
873                                 "CREATE INDEX IF NOT EXISTS %Q ON %Q (%s)", tmp, folderid,
874                                                 summary_dbname_from_field (ebsdb, ebsdb->priv->summary_fields[i].field));
875                         success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
876                         sqlite3_free (stmt);
877                         g_free (tmp);
878                 }
879
880                 if (success &&
881                     (ebsdb->priv->summary_fields[i].index & INDEX_SUFFIX) != 0 &&
882                     ebsdb->priv->summary_fields[i].type != E_TYPE_CONTACT_ATTR_LIST) {
883                         /* Derive index name from field & folder */
884                         tmp = g_strdup_printf (
885                                 "RINDEX_%s_%s",
886                                 summary_dbname_from_field (ebsdb, ebsdb->priv->summary_fields[i].field),
887                                 folderid);
888                         stmt = sqlite3_mprintf (
889                                 "CREATE INDEX IF NOT EXISTS %Q ON %Q (%s_reverse)", tmp, folderid,
890                                                 summary_dbname_from_field (ebsdb, ebsdb->priv->summary_fields[i].field));
891                         success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
892                         sqlite3_free (stmt);
893                         g_free (tmp);
894                 }
895         }
896
897         /* Construct the create statement from the attribute list summary table */
898         if (success && ebsdb->priv->have_attr_list) {
899                 string = g_string_new ("CREATE TABLE IF NOT EXISTS %Q ( uid TEXT NOT NULL REFERENCES %Q(uid), "
900                         "field TEXT, value TEXT");
901
902                 if (ebsdb->priv->have_attr_list_suffix)
903                         g_string_append (string, ", value_reverse TEXT");
904
905                 g_string_append_c (string, ')');
906
907                 tmp = g_strdup_printf ("%s_lists", folderid);
908                 stmt = sqlite3_mprintf (string->str, tmp, folderid);
909                 g_string_free (string, TRUE);
910
911                 success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
912                 sqlite3_free (stmt);
913
914                 /* Give the UID an index in this table, always */
915                 stmt = sqlite3_mprintf ("CREATE INDEX IF NOT EXISTS LISTINDEX ON %Q (uid)", tmp);
916                 success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
917                 sqlite3_free (stmt);
918
919                 /* Create indexes if specified */
920                 if (success && ebsdb->priv->have_attr_list_prefix) {
921                         stmt = sqlite3_mprintf ("CREATE INDEX IF NOT EXISTS VALINDEX ON %Q (value)", tmp);
922                         success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
923                         sqlite3_free (stmt);
924                 }
925
926                 if (success && ebsdb->priv->have_attr_list_suffix) {
927                         stmt = sqlite3_mprintf ("CREATE INDEX IF NOT EXISTS RVALINDEX ON %Q (value_reverse)", tmp);
928                         success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
929                         sqlite3_free (stmt);
930                 }
931
932                 g_free (tmp);
933
934         }
935
936         WRITER_UNLOCK (ebsdb);
937
938         if (success)
939                 success = introspect_summary (ebsdb, folderid, error);
940
941         return success;
942 }
943
944 static gboolean
945 book_backend_sqlitedb_load (EBookBackendSqliteDB *ebsdb,
946                             const gchar *filename,
947                             GError **error)
948 {
949         gint ret;
950
951         e_sqlite3_vfs_init ();
952
953         ret = sqlite3_open (filename, &ebsdb->priv->db);
954         if (ret) {
955                 if (!ebsdb->priv->db) {
956                         g_set_error (
957                                 error, E_BOOK_SDB_ERROR,
958                                 E_BOOK_SDB_ERROR_OTHER,
959                                 _("Insufficient memory"));
960                 } else {
961                         const gchar *errmsg;
962                         errmsg = sqlite3_errmsg (ebsdb->priv->db);
963                         d (g_print ("Can't open database %s: %s\n", path, errmsg));
964                         g_set_error_literal (
965                                 error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER, errmsg);
966                         sqlite3_close (ebsdb->priv->db);
967                 }
968                 return FALSE;
969         }
970
971         WRITER_LOCK (ebsdb);
972
973         book_backend_sql_exec (
974                 ebsdb->priv->db,
975                 "ATTACH DATABASE ':memory:' AS mem",
976                 NULL, NULL, NULL);
977         book_backend_sql_exec (
978                 ebsdb->priv->db,
979                 "PRAGMA foreign_keys = ON",
980                 NULL, NULL, NULL);
981         book_backend_sql_exec (
982                 ebsdb->priv->db,
983                 "PRAGMA case_sensitive_like = ON",
984                 NULL, NULL, NULL);
985
986         WRITER_UNLOCK (ebsdb);
987
988         return create_folders_table (ebsdb, error);
989 }
990
991 static EBookBackendSqliteDB *
992 e_book_backend_sqlitedb_new_internal (const gchar *path,
993                                       const gchar *emailid,
994                                       const gchar *folderid,
995                                       const gchar *folder_name,
996                                       gboolean store_vcard,
997                                       SummaryField *fields,
998                                       gint n_fields,
999                                       gboolean have_attr_list,
1000                                       gboolean have_attr_list_prefix,
1001                                       gboolean have_attr_list_suffix,
1002                                       GError **error)
1003 {
1004         EBookBackendSqliteDB *ebsdb;
1005         gchar *hash_key, *filename;
1006
1007         g_return_val_if_fail (path != NULL, NULL);
1008         g_return_val_if_fail (emailid != NULL, NULL);
1009         g_return_val_if_fail (folderid != NULL, NULL);
1010         g_return_val_if_fail (folder_name != NULL, NULL);
1011
1012         g_mutex_lock (&dbcon_lock);
1013
1014         hash_key = g_strdup_printf ("%s@%s", emailid, path);
1015         if (db_connections != NULL) {
1016                 ebsdb = g_hash_table_lookup (db_connections, hash_key);
1017
1018                 if (ebsdb) {
1019                         g_object_ref (ebsdb);
1020                         g_mutex_unlock (&dbcon_lock);
1021                         g_free (hash_key);
1022                         goto exit;
1023                 }
1024         }
1025
1026         ebsdb = g_object_new (E_TYPE_BOOK_BACKEND_SQLITEDB, NULL);
1027         ebsdb->priv->path = g_strdup (path);
1028         ebsdb->priv->summary_fields = fields;
1029         ebsdb->priv->n_summary_fields = n_fields;
1030         ebsdb->priv->have_attr_list = have_attr_list;
1031         ebsdb->priv->have_attr_list_prefix = have_attr_list_prefix;
1032         ebsdb->priv->have_attr_list_suffix = have_attr_list_suffix;
1033         ebsdb->priv->store_vcard = store_vcard;
1034         if (g_mkdir_with_parents (path, 0777) < 0) {
1035                 g_mutex_unlock (&dbcon_lock);
1036                 g_set_error (
1037                         error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
1038                         "Can not make parent directory: errno %d", errno);
1039                 return NULL;
1040         }
1041         filename = g_build_filename (path, DB_FILENAME, NULL);
1042
1043         if (!book_backend_sqlitedb_load (ebsdb, filename, error)) {
1044                 g_mutex_unlock (&dbcon_lock);
1045                 g_object_unref (ebsdb);
1046                 g_free (filename);
1047                 return NULL;
1048         }
1049         g_free (filename);
1050
1051         if (db_connections == NULL)
1052                 db_connections = g_hash_table_new_full (
1053                         (GHashFunc) g_str_hash,
1054                         (GEqualFunc) g_str_equal,
1055                         (GDestroyNotify) g_free,
1056                         (GDestroyNotify) NULL);
1057         g_hash_table_insert (db_connections, hash_key, ebsdb);
1058         ebsdb->priv->hash_key = g_strdup (hash_key);
1059
1060         g_mutex_unlock (&dbcon_lock);
1061
1062 exit:
1063         if (!add_folder_into_db (ebsdb, folderid, folder_name, error)) {
1064                 g_object_unref (ebsdb);
1065                 return NULL;
1066         }
1067
1068         if (!create_contacts_table (ebsdb, folderid, error)) {
1069                 g_object_unref (ebsdb);
1070                 return NULL;
1071         }
1072
1073         return ebsdb;
1074 }
1075
1076 static gboolean
1077 append_summary_field (GArray *array,
1078                       EContactField field,
1079                       gboolean *have_attr_list,
1080                       GError **error)
1081 {
1082         const gchar *dbname = NULL;
1083         GType        type = G_TYPE_INVALID;
1084         gint         i;
1085         SummaryField new_field = { 0, };
1086
1087         if (field < 1 || field >= E_CONTACT_FIELD_LAST) {
1088                 g_set_error (
1089                         error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
1090                         _("Invalid contact field '%d' specified in summary"), field);
1091                 return FALSE;
1092         }
1093
1094         /* Avoid including the same field twice in the summary */
1095         for (i = 0; i < array->len; i++) {
1096                 SummaryField *iter = &g_array_index (array, SummaryField, i);
1097                 if (field == iter->field)
1098                         return TRUE;
1099         }
1100
1101         /* Resolve some exceptions, we store these
1102          * specific contact fields with different names
1103          * than those found in the EContactField table
1104          */
1105         switch (field) {
1106         case E_CONTACT_UID:
1107                 dbname = "uid";
1108                 break;
1109         case E_CONTACT_IS_LIST:
1110                 dbname = "is_list";
1111                 break;
1112         default:
1113                 dbname = e_contact_field_name (field);
1114                 break;
1115         }
1116
1117         type = e_contact_field_type (field);
1118
1119         if (type != G_TYPE_STRING &&
1120             type != G_TYPE_BOOLEAN &&
1121             type != E_TYPE_CONTACT_ATTR_LIST) {
1122                 g_set_error (
1123                         error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
1124                         _("Contact field '%s' of type '%s' specified in summary, "
1125                         "but only boolean, string and string list field types are supported"),
1126                         e_contact_pretty_name (field), g_type_name (type));
1127                 return FALSE;
1128         }
1129
1130         if (type == E_TYPE_CONTACT_ATTR_LIST && have_attr_list)
1131                 *have_attr_list = TRUE;
1132
1133         new_field.field  = field;
1134         new_field.dbname = dbname;
1135         new_field.type   = type;
1136         g_array_append_val (array, new_field);
1137
1138         return TRUE;
1139 }
1140
1141 static void
1142 summary_fields_add_indexes (GArray *array,
1143                             EContactField *indexes,
1144                             EBookIndexType *index_types,
1145                             gint n_indexes,
1146                             gboolean *have_attr_list_prefix,
1147                             gboolean *have_attr_list_suffix)
1148 {
1149         gint i, j;
1150
1151         for (i = 0; i < array->len; i++) {
1152                 SummaryField *sfield = &g_array_index (array, SummaryField, i);
1153
1154                 for (j = 0; j < n_indexes; j++) {
1155                         if (sfield->field == indexes[j]) {
1156                                 switch (index_types[j]) {
1157                                 case E_BOOK_INDEX_PREFIX:
1158                                         sfield->index |= INDEX_PREFIX;
1159
1160                                         if (sfield->type == E_TYPE_CONTACT_ATTR_LIST)
1161                                                 *have_attr_list_prefix = TRUE;
1162                                         break;
1163                                 case E_BOOK_INDEX_SUFFIX:
1164                                         sfield->index |= INDEX_SUFFIX;
1165
1166                                         if (sfield->type == E_TYPE_CONTACT_ATTR_LIST)
1167                                                 *have_attr_list_suffix = TRUE;
1168                                         break;
1169                                 default:
1170                                         g_warn_if_reached ();
1171                                         break;
1172                                 }
1173                         }
1174                 }
1175         }
1176 }
1177
1178 /**
1179  * e_book_backend_sqlitedb_new_full:
1180  * @path: location where the db would be created
1181  * @emailid: email id of the user
1182  * @folderid: folder id of the address-book
1183  * @folder_name: name of the address-book
1184  * @store_vcard: True if the vcard should be stored inside db, if FALSE only the summary fields would be stored inside db.
1185  * @setup: an #ESourceBackendSummarySetup describing how the summary should be setup
1186  * @error: A location to store any error that may have occurred
1187  *
1188  * Like e_book_backend_sqlitedb_new(), but allows configuration of which contact fields
1189  * will be stored for quick reference in the summary. The configuration indicated by
1190  * @setup will only be taken into account when initially creating the underlying table,
1191  * further configurations will be ignored.
1192  *
1193  * The fields %E_CONTACT_UID and %E_CONTACT_REV are not optional,
1194  * they will be stored in the summary regardless of this function's parameters
1195  *
1196  * <note><para>Only #EContactFields with the type #G_TYPE_STRING, #G_TYPE_BOOLEAN or
1197  * #E_TYPE_CONTACT_ATTR_LIST are currently supported.</para></note>
1198  *
1199  * Returns: (transfer full): The newly created #EBookBackendSqliteDB
1200  *
1201  * Since: 3.8
1202  **/
1203 EBookBackendSqliteDB *
1204 e_book_backend_sqlitedb_new_full (const gchar *path,
1205                                   const gchar *emailid,
1206                                   const gchar *folderid,
1207                                   const gchar *folder_name,
1208                                   gboolean store_vcard,
1209                                   ESourceBackendSummarySetup *setup,
1210                                   GError **error)
1211 {
1212         EBookBackendSqliteDB *ebsdb = NULL;
1213         EContactField *fields;
1214         EContactField *indexed_fields;
1215         EBookIndexType *index_types = NULL;
1216         gboolean have_attr_list = FALSE;
1217         gboolean have_attr_list_prefix = FALSE;
1218         gboolean have_attr_list_suffix = FALSE;
1219         gboolean had_error = FALSE;
1220         GArray *summary_fields;
1221         gint n_fields = 0, n_indexed_fields = 0, i;
1222
1223         fields         = e_source_backend_summary_setup_get_summary_fields (setup, &n_fields);
1224         indexed_fields = e_source_backend_summary_setup_get_indexed_fields (setup, &index_types, &n_indexed_fields);
1225
1226         /* No specified summary fields indicates the default summary configuration should be used */
1227         if (n_fields <= 0) {
1228                 ebsdb = e_book_backend_sqlitedb_new (path, emailid, folderid, folder_name, store_vcard, error);
1229                 g_free (fields);
1230                 g_free (index_types);
1231                 g_free (indexed_fields);
1232
1233                 return ebsdb;
1234         }
1235
1236         summary_fields = g_array_new (FALSE, FALSE, sizeof (SummaryField));
1237
1238         /* Ensure the non-optional fields first */
1239         append_summary_field (summary_fields, E_CONTACT_UID, &have_attr_list, error);
1240         append_summary_field (summary_fields, E_CONTACT_REV, &have_attr_list, error);
1241
1242         for (i = 0; i < n_fields; i++) {
1243                 if (!append_summary_field (summary_fields, fields[i], &have_attr_list, error)) {
1244                         had_error = TRUE;
1245                         break;
1246                 }
1247         }
1248
1249         if (had_error) {
1250                 g_array_free (summary_fields, TRUE);
1251                 g_free (fields);
1252                 g_free (index_types);
1253                 g_free (indexed_fields);
1254                 return NULL;
1255         }
1256
1257         /* Add the 'indexed' flag to the SummaryField structs */
1258         summary_fields_add_indexes (
1259                 summary_fields, indexed_fields, index_types, n_indexed_fields,
1260                 &have_attr_list_prefix, &have_attr_list_suffix);
1261
1262         ebsdb = e_book_backend_sqlitedb_new_internal (
1263                 path, emailid, folderid, folder_name,
1264                 store_vcard,
1265                 (SummaryField *) summary_fields->data,
1266                 summary_fields->len,
1267                 have_attr_list,
1268                 have_attr_list_prefix,
1269                 have_attr_list_suffix,
1270                 error);
1271
1272         g_free (fields);
1273         g_free (index_types);
1274         g_free (indexed_fields);
1275         g_array_free (summary_fields, FALSE);
1276
1277         return ebsdb;
1278 }
1279
1280 /**
1281  * e_book_backend_sqlitedb_new
1282  * @path: location where the db would be created
1283  * @emailid: email id of the user
1284  * @folderid: folder id of the address-book
1285  * @folder_name: name of the address-book
1286  * @store_vcard: True if the vcard should be stored inside db, if FALSE only the summary fields would be stored inside db.
1287  * @error:
1288  *
1289  * If the path for multiple addressbooks are same, the contacts from all addressbooks
1290  * would be stored in same db in different tables.
1291  *
1292  * Returns:
1293  *
1294  * Since: 3.2
1295  **/
1296 EBookBackendSqliteDB *
1297 e_book_backend_sqlitedb_new (const gchar *path,
1298                              const gchar *emailid,
1299                              const gchar *folderid,
1300                              const gchar *folder_name,
1301                              gboolean store_vcard,
1302                              GError **error)
1303 {
1304         EBookBackendSqliteDB *ebsdb;
1305         GArray *summary_fields;
1306         gboolean have_attr_list = FALSE;
1307         gboolean have_attr_list_prefix = FALSE;
1308         gboolean have_attr_list_suffix = FALSE;
1309         gint i;
1310
1311         /* Create the default summary structs */
1312         summary_fields = g_array_new (FALSE, FALSE, sizeof (SummaryField));
1313         for (i = 0; i < G_N_ELEMENTS (default_summary_fields); i++)
1314                 append_summary_field (summary_fields, default_summary_fields[i], &have_attr_list, NULL);
1315
1316         /* Add the default index flags */
1317         summary_fields_add_indexes (
1318                 summary_fields,
1319                 default_indexed_fields,
1320                 default_index_types,
1321                 G_N_ELEMENTS (default_indexed_fields),
1322                 &have_attr_list_prefix, &have_attr_list_suffix);
1323
1324         ebsdb = e_book_backend_sqlitedb_new_internal (
1325                 path, emailid, folderid, folder_name,
1326                 store_vcard,
1327                 (SummaryField *) summary_fields->data,
1328                 summary_fields->len,
1329                 have_attr_list,
1330                 have_attr_list_prefix,
1331                 have_attr_list_suffix,
1332                 error);
1333         g_array_free (summary_fields, FALSE);
1334
1335         return ebsdb;
1336 }
1337
1338 gboolean
1339 e_book_backend_sqlitedb_lock_updates (EBookBackendSqliteDB *ebsdb,
1340                                       GError **error)
1341 {
1342         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
1343
1344         return book_backend_sqlitedb_start_transaction (ebsdb, error);
1345 }
1346
1347 gboolean
1348 e_book_backend_sqlitedb_unlock_updates (EBookBackendSqliteDB *ebsdb,
1349                                         gboolean do_commit,
1350                                         GError **error)
1351 {
1352         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
1353
1354         return do_commit ?
1355                 book_backend_sqlitedb_commit_transaction (ebsdb, error) :
1356                 book_backend_sqlitedb_rollback_transaction (ebsdb, error);
1357 }
1358
1359 /* Add Contact (free the result with g_free() ) */
1360 static gchar *
1361 insert_stmt_from_contact (EBookBackendSqliteDB *ebsdb,
1362                           EContact *contact,
1363                           const gchar *folderid,
1364                           gboolean store_vcard,
1365                           gboolean replace_existing)
1366 {
1367         GString *string;
1368         gchar *str, *vcard_str;
1369         gint i;
1370
1371         str = sqlite3_mprintf ("INSERT or %s INTO %Q VALUES (",
1372                                replace_existing ? "REPLACE" : "FAIL", folderid);
1373         string = g_string_new (str);
1374         sqlite3_free (str);
1375
1376         for (i = 0; i < ebsdb->priv->n_summary_fields; i++) {
1377
1378                 if (ebsdb->priv->summary_fields[i].type == G_TYPE_STRING) {
1379                         gchar *val;
1380                         gchar *normal;
1381
1382                         if (i > 0)
1383                                 g_string_append (string, ", ");
1384
1385                         val = e_contact_get (contact, ebsdb->priv->summary_fields[i].field);
1386
1387                         /* Special exception, never normalize the UID or REV string */
1388                         if (ebsdb->priv->summary_fields[i].field != E_CONTACT_UID &&
1389                             ebsdb->priv->summary_fields[i].field != E_CONTACT_REV)
1390                                 normal = e_util_utf8_normalize (val);
1391                         else
1392                                 normal = g_strdup (val);
1393
1394                         str = sqlite3_mprintf ("%Q", normal);
1395                         g_string_append (string, str);
1396                         sqlite3_free (str);
1397
1398                         if ((ebsdb->priv->summary_fields[i].index & INDEX_SUFFIX) != 0) {
1399                                 gchar *reverse = normal ? g_utf8_strreverse (normal, -1) : NULL;
1400
1401                                 str = sqlite3_mprintf ("%Q", reverse);
1402                                 g_string_append (string, ", ");
1403                                 g_string_append (string, str);
1404                                 sqlite3_free (str);
1405                                 g_free (reverse);
1406                         }
1407
1408                         g_free (normal);
1409                         g_free (val);
1410
1411                 } else if (ebsdb->priv->summary_fields[i].type == G_TYPE_BOOLEAN) {
1412                         gboolean val;
1413
1414                         if (i > 0)
1415                                 g_string_append (string, ", ");
1416
1417                         val = e_contact_get (contact, ebsdb->priv->summary_fields[i].field) ? TRUE : FALSE;
1418                         g_string_append_printf (string, "%d", val ? 1 : 0);
1419
1420                 } else if (ebsdb->priv->summary_fields[i].type != E_TYPE_CONTACT_ATTR_LIST)
1421                         g_warn_if_reached ();
1422         }
1423
1424         vcard_str = store_vcard ? e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30) : NULL;
1425         str = sqlite3_mprintf (", %Q, %Q)", vcard_str, NULL);
1426
1427         g_string_append (string, str);
1428
1429         sqlite3_free (str);
1430         g_free (vcard_str);
1431
1432         return g_string_free (string, FALSE);
1433 }
1434
1435 static gboolean
1436 insert_contact (EBookBackendSqliteDB *ebsdb,
1437                 EContact *contact,
1438                 const gchar *folderid,
1439                 gboolean replace_existing,
1440                 GError **error)
1441 {
1442         EBookBackendSqliteDBPrivate *priv;
1443         gboolean success;
1444         gchar *stmt;
1445
1446         priv = ebsdb->priv;
1447
1448         /* Update main summary table */
1449         stmt = insert_stmt_from_contact (ebsdb, contact, folderid, priv->store_vcard, replace_existing);
1450         success = book_backend_sql_exec (priv->db, stmt, NULL, NULL, error);
1451         g_free (stmt);
1452
1453         /* Update attribute list table */
1454         if (success && priv->have_attr_list) {
1455                 gchar *list_folder = g_strdup_printf ("%s_lists", folderid);
1456                 gchar *uid;
1457                 gint   i;
1458                 GList *values, *l;
1459
1460                 /* First remove all entries for this UID */
1461                 uid = e_contact_get (contact, E_CONTACT_UID);
1462                 stmt = sqlite3_mprintf ("DELETE FROM %Q WHERE uid = %Q", list_folder, uid);
1463                 success = book_backend_sql_exec (priv->db, stmt, NULL, NULL, error);
1464                 sqlite3_free (stmt);
1465
1466                 for (i = 0; success && i < priv->n_summary_fields; i++) {
1467
1468                         if (priv->summary_fields[i].type != E_TYPE_CONTACT_ATTR_LIST)
1469                                 continue;
1470
1471                         values = e_contact_get (contact, priv->summary_fields[i].field);
1472
1473                         for (l = values; success && l != NULL; l = l->next) {
1474                                 gchar *value = (gchar *) l->data;
1475                                 gchar *normal = e_util_utf8_normalize (value);
1476
1477                                 if (priv->have_attr_list_suffix) {
1478                                         gchar *reverse = normal ? g_utf8_strreverse (normal, -1) : NULL;
1479
1480                                         stmt = sqlite3_mprintf ("INSERT INTO %Q (uid, field, value, value_reverse) "
1481                                                                 "VALUES (%Q, %Q, %Q, %Q)",
1482                                                                 list_folder, uid,
1483                                                                 priv->summary_fields[i].dbname,
1484                                                                 normal, reverse);
1485
1486                                         g_free (reverse);
1487                                 } else {
1488                                         stmt = sqlite3_mprintf ("INSERT INTO %Q (uid, field, value) "
1489                                                                 "VALUES (%Q, %Q, %Q)",
1490                                                                 list_folder, uid,
1491                                                                 priv->summary_fields[i].dbname,
1492                                                                 normal);
1493                                 }
1494
1495                                 success = book_backend_sql_exec (priv->db, stmt, NULL, NULL, error);
1496                                 sqlite3_free (stmt);
1497                                 g_free (normal);
1498                         }
1499
1500                         /* Free the list of allocated strings */
1501                         e_contact_attr_list_free (values);
1502                 }
1503
1504                 g_free (list_folder);
1505                 g_free (uid);
1506         }
1507
1508         return success;
1509 }
1510
1511 /**
1512  * e_book_backend_sqlitedb_new_contact
1513  * @ebsdb: An #EBookBackendSqliteDB
1514  * @folderid: folder id
1515  * @contact: EContact to be added
1516  * @replace_existing: Whether this contact should replace another contact with the same UID.
1517  * @error: A location to store any error that may have occurred.
1518  *
1519  * This is a convenience wrapper for e_book_backend_sqlitedb_new_contacts,
1520  * which is the preferred means to add or modify multiple contacts when possible.
1521  *
1522  * Returns: TRUE on success.
1523  *
1524  * Since: 3.8
1525  **/
1526 gboolean
1527 e_book_backend_sqlitedb_new_contact (EBookBackendSqliteDB *ebsdb,
1528                                      const gchar *folderid,
1529                                      EContact *contact,
1530                                      gboolean replace_existing,
1531                                      GError **error)
1532 {
1533         GSList l;
1534
1535         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
1536         g_return_val_if_fail (folderid != NULL, FALSE);
1537         g_return_val_if_fail (E_IS_CONTACT (contact), FALSE);
1538
1539         l.data = contact;
1540         l.next = NULL;
1541
1542         return e_book_backend_sqlitedb_new_contacts (
1543                 ebsdb, folderid, &l,
1544                 replace_existing, error);
1545 }
1546
1547 /**
1548  * e_book_backend_sqlitedb_new_contacts
1549  * @ebsdb: An #EBookBackendSqliteDB
1550  * @folderid: folder id
1551  * @contacts: list of EContacts
1552  * @replace_existing: Whether this contact should replace another contact with the same UID.
1553  * @error: A location to store any error that may have occurred.
1554  *
1555  * Adds or replaces contacts in @ebsdb. If @replace_existing is specified then existing
1556  * contacts with the same UID will be replaced, otherwise adding an existing contact
1557  * will return an error.
1558  *
1559  * Returns: TRUE on success.
1560  *
1561  * Since: 3.8
1562  **/
1563 gboolean
1564 e_book_backend_sqlitedb_new_contacts (EBookBackendSqliteDB *ebsdb,
1565                                       const gchar *folderid,
1566                                       GSList *contacts,
1567                                       gboolean replace_existing,
1568                                       GError **error)
1569 {
1570         GSList *l;
1571         gboolean success;
1572
1573         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
1574         g_return_val_if_fail (folderid != NULL, FALSE);
1575         g_return_val_if_fail (contacts != NULL, FALSE);
1576
1577         success = book_backend_sqlitedb_start_transaction (ebsdb, error);
1578
1579         for (l = contacts; success && l != NULL; l = g_slist_next (l)) {
1580                 EContact *contact = (EContact *) l->data;
1581
1582                 success = insert_contact (ebsdb, contact, folderid, replace_existing, error);
1583         }
1584
1585         if (success)
1586                 return book_backend_sqlitedb_commit_transaction (ebsdb, error);
1587
1588         /* The GError is already set. */
1589         book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
1590
1591         return FALSE;
1592 }
1593
1594 /**
1595  * e_book_backend_sqlitedb_add_contact
1596  * @ebsdb:
1597  * @folderid: folder id
1598  * @contact: EContact to be added
1599  * @partial_content: contact does not contain full information. Used when
1600  * the backend cache's partial information for auto-completion.
1601  * @error:
1602  *
1603  * This is a convenience wrapper for e_book_backend_sqlitedb_add_contacts,
1604  * which is the preferred means to add multiple contacts when possible.
1605  *
1606  * Returns: TRUE on success.
1607  *
1608  * Since: 3.2
1609  *
1610  * Deprecated: 3.8: Use e_book_backend_sqlitedb_new_contact() instead.
1611  **/
1612 gboolean
1613 e_book_backend_sqlitedb_add_contact (EBookBackendSqliteDB *ebsdb,
1614                                      const gchar *folderid,
1615                                      EContact *contact,
1616                                      gboolean partial_content,
1617                                      GError **error)
1618 {
1619         return e_book_backend_sqlitedb_new_contact (ebsdb, folderid, contact, TRUE, error);
1620 }
1621
1622 /**
1623  * e_book_backend_sqlitedb_add_contacts
1624  * @ebsdb:
1625  * @folderid: folder id
1626  * @contacts: list of EContacts
1627  * @partial_content: contact does not contain full information. Used when
1628  * the backend cache's partial information for auto-completion.
1629  * @error:
1630  *
1631  *
1632  * Returns: TRUE on success.
1633  *
1634  * Since: 3.2
1635  *
1636  * Deprecated: 3.8: Use e_book_backend_sqlitedb_new_contacts() instead.
1637  **/
1638 gboolean
1639 e_book_backend_sqlitedb_add_contacts (EBookBackendSqliteDB *ebsdb,
1640                                       const gchar *folderid,
1641                                       GSList *contacts,
1642                                       gboolean partial_content,
1643                                       GError **error)
1644 {
1645         return e_book_backend_sqlitedb_new_contacts (ebsdb, folderid, contacts, TRUE, error);
1646 }
1647
1648 /**
1649  * e_book_backend_sqlitedb_remove_contact:
1650  *
1651  * FIXME: Document me.
1652  *
1653  * Since: 3.2
1654  **/
1655 gboolean
1656 e_book_backend_sqlitedb_remove_contact (EBookBackendSqliteDB *ebsdb,
1657                                         const gchar *folderid,
1658                                         const gchar *uid,
1659                                         GError **error)
1660 {
1661         GSList l;
1662
1663         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
1664         g_return_val_if_fail (folderid != NULL, FALSE);
1665         g_return_val_if_fail (uid != NULL, FALSE);
1666
1667         l.data = (gchar *) uid; /* Won't modify it, I promise :) */
1668         l.next = NULL;
1669
1670         return e_book_backend_sqlitedb_remove_contacts (
1671                 ebsdb, folderid, &l, error);
1672 }
1673
1674 static gchar *
1675 generate_uid_list_for_stmt (GSList *uids)
1676 {
1677         GString *str = g_string_new (NULL);
1678         GSList  *l;
1679         gboolean first = TRUE;
1680
1681         for (l = uids; l; l = l->next) {
1682                 gchar *uid = (gchar *) l->data;
1683                 gchar *tmp;
1684
1685                 /* First uid with no comma */
1686                 if (!first)
1687                         g_string_append_printf (str, ", ");
1688                 else
1689                         first = FALSE;
1690
1691                 tmp = sqlite3_mprintf ("%Q", uid);
1692                 g_string_append (str, tmp);
1693                 sqlite3_free (tmp);
1694         }
1695
1696         return g_string_free (str, FALSE);
1697 }
1698
1699 static gchar *
1700 generate_delete_stmt (const gchar *table,
1701                       GSList *uids)
1702 {
1703         GString *str = g_string_new (NULL);
1704         gchar *tmp;
1705
1706         tmp = sqlite3_mprintf ("DELETE FROM %Q WHERE uid IN (", table);
1707         g_string_append (str, tmp);
1708         sqlite3_free (tmp);
1709
1710         tmp = generate_uid_list_for_stmt (uids);
1711         g_string_append (str, tmp);
1712         g_free (tmp);
1713         g_string_append_c (str, ')');
1714
1715         return g_string_free (str, FALSE);
1716 }
1717
1718 /**
1719  * e_book_backend_sqlitedb_remove_contacts:
1720  *
1721  * FIXME: Document me.
1722  *
1723  * Since: 3.2
1724  **/
1725 gboolean
1726 e_book_backend_sqlitedb_remove_contacts (EBookBackendSqliteDB *ebsdb,
1727                                          const gchar *folderid,
1728                                          GSList *uids,
1729                                          GError **error)
1730 {
1731         gboolean success;
1732         gchar *stmt;
1733
1734         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
1735         g_return_val_if_fail (folderid != NULL, FALSE);
1736         g_return_val_if_fail (uids != NULL, FALSE);
1737
1738         success = book_backend_sqlitedb_start_transaction (ebsdb, error);
1739
1740         /* Delete the auxillary contact infos first */
1741         if (success && ebsdb->priv->have_attr_list) {
1742                 gchar *lists_folder = g_strdup_printf ("%s_lists", folderid);
1743
1744                 stmt = generate_delete_stmt (lists_folder, uids);
1745                 g_free (lists_folder);
1746
1747                 success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
1748                 g_free (stmt);
1749         }
1750
1751         if (success) {
1752                 stmt = generate_delete_stmt (folderid, uids);
1753                 success = book_backend_sql_exec (ebsdb->priv->db, stmt, NULL, NULL, error);
1754                 g_free (stmt);
1755         }
1756
1757         if (success)
1758                 return book_backend_sqlitedb_commit_transaction (ebsdb, error);
1759
1760         /* The GError is already set. */
1761         book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
1762
1763         return FALSE;
1764 }
1765
1766 struct _contact_info {
1767         gboolean exists;
1768         gboolean partial_content;
1769 };
1770
1771 static gint
1772 contact_found_cb (gpointer ref,
1773                   gint col,
1774                   gchar **cols,
1775                   gchar **name)
1776 {
1777         struct _contact_info *cinfo = ref;
1778
1779         cinfo->exists = TRUE;
1780         cinfo->partial_content = cols[0] ? strtoul (cols[0], NULL, 10) : 0;
1781
1782         return 0;
1783 }
1784
1785 /**
1786  * e_book_backend_sqlitedb_has_contact:
1787  *
1788  * FIXME: Document me.
1789  *
1790  * Since: 3.2
1791  **/
1792 gboolean
1793 e_book_backend_sqlitedb_has_contact (EBookBackendSqliteDB *ebsdb,
1794                                      const gchar *folderid,
1795                                      const gchar *uid,
1796                                      gboolean *partial_content,
1797                                      GError **error)
1798 {
1799         struct _contact_info cinfo;
1800         gboolean success;
1801         gchar *stmt;
1802
1803         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
1804         g_return_val_if_fail (folderid != NULL, FALSE);
1805         g_return_val_if_fail (uid != NULL, FALSE);
1806
1807         cinfo.exists = FALSE;
1808         cinfo.partial_content = FALSE;
1809
1810         READER_LOCK (ebsdb);
1811
1812         stmt = sqlite3_mprintf (
1813                 "SELECT partial_content FROM %Q WHERE uid = %Q",
1814                 folderid, uid);
1815         success = book_backend_sql_exec (
1816                 ebsdb->priv->db, stmt, contact_found_cb , &cinfo, error);
1817         sqlite3_free (stmt);
1818
1819         if (success)
1820                 *partial_content = cinfo.partial_content;
1821
1822         READER_UNLOCK (ebsdb);
1823
1824         /* FIXME Returning FALSE can mean either "contact not found" or
1825          *       "error occurred".  Add a boolean (out) "exists" parameter. */
1826         return success && cinfo.exists;
1827 }
1828
1829 static gint
1830 get_vcard_cb (gpointer ref,
1831               gint col,
1832               gchar **cols,
1833               gchar **name)
1834 {
1835         gchar **vcard_str = ref;
1836
1837         if (cols[0])
1838                 *vcard_str = g_strdup (cols [0]);
1839
1840         return 0;
1841 }
1842
1843 /**
1844  * e_book_backend_sqlitedb_get_contact:
1845  *
1846  * FIXME: Document me.
1847  *
1848  * Since: 3.2
1849  **/
1850 EContact *
1851 e_book_backend_sqlitedb_get_contact (EBookBackendSqliteDB *ebsdb,
1852                                      const gchar *folderid,
1853                                      const gchar *uid,
1854                                      GHashTable *fields_of_interest,
1855                                      gboolean *with_all_required_fields,
1856                                      GError **error)
1857 {
1858         EContact *contact = NULL;
1859         gchar *vcard;
1860
1861         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
1862         g_return_val_if_fail (folderid != NULL, NULL);
1863         g_return_val_if_fail (uid != NULL, NULL);
1864
1865         vcard = e_book_backend_sqlitedb_get_vcard_string (
1866                 ebsdb, folderid, uid,
1867                 fields_of_interest, with_all_required_fields, error);
1868
1869         if (vcard != NULL) {
1870                 contact = e_contact_new_from_vcard_with_uid (vcard, uid);
1871                 g_free (vcard);
1872         }
1873
1874         return contact;
1875 }
1876
1877 static gboolean
1878 uid_rev_fields (GHashTable *fields_of_interest)
1879 {
1880         GHashTableIter iter;
1881         gpointer key, value;
1882
1883         if (!fields_of_interest || g_hash_table_size (fields_of_interest) > 2)
1884                 return FALSE;
1885
1886         g_hash_table_iter_init (&iter, fields_of_interest);
1887         while (g_hash_table_iter_next (&iter, &key, &value)) {
1888                 const gchar *field_name = key;
1889                 EContactField field = e_contact_field_id (field_name);
1890
1891                 if (field != E_CONTACT_UID &&
1892                     field != E_CONTACT_REV)
1893                         return FALSE;
1894         }
1895
1896         return TRUE;
1897 }
1898
1899 /**
1900  * e_book_backend_sqlitedb_is_summary_fields:
1901  * @fields_of_interest: A hash table containing the fields of interest
1902  * 
1903  * This only checks if all the fields are part of the default summary fields,
1904  * not part of the configured summary fields.
1905  *
1906  * Since: 3.2
1907  *
1908  * Deprecated: 3.8: Use e_book_backend_sqlitedb_check_summary_fields() instead.
1909  **/
1910 gboolean
1911 e_book_backend_sqlitedb_is_summary_fields (GHashTable *fields_of_interest)
1912 {
1913         gboolean summary_fields = TRUE;
1914         GHashTableIter iter;
1915         gpointer key, value;
1916         gint     i;
1917
1918         if (!fields_of_interest)
1919                 return FALSE;
1920
1921         g_hash_table_iter_init (&iter, fields_of_interest);
1922         while (g_hash_table_iter_next (&iter, &key, &value)) {
1923                 const gchar  *field_name = key;
1924                 EContactField field      = e_contact_field_id (field_name);
1925                 gboolean      found      = FALSE;
1926
1927                 for (i = 0; i < G_N_ELEMENTS (default_summary_fields); i++) {
1928                         if (field == default_summary_fields[i]) {
1929                                 found = TRUE;
1930                                 break;
1931                         }
1932                 }
1933
1934                 if (!found) {
1935                         summary_fields = FALSE;
1936                         break;
1937                 }
1938         }
1939
1940         return summary_fields;
1941 }
1942
1943 /**
1944  * e_book_backend_sqlitedb_check_summary_fields:
1945  * @ebsdb: An #EBookBackendSqliteDB
1946  * @fields_of_interest: A hash table containing the fields of interest
1947  * 
1948  * Checks if all the specified fields are part of the configured summary
1949  * fields for @ebsdb
1950  *
1951  * Since: 3.8
1952  **/
1953 gboolean
1954 e_book_backend_sqlitedb_check_summary_fields (EBookBackendSqliteDB *ebsdb,
1955                                               GHashTable *fields_of_interest)
1956 {
1957         gboolean summary_fields = TRUE;
1958         GHashTableIter iter;
1959         gpointer key, value;
1960
1961         if (!fields_of_interest)
1962                 return FALSE;
1963
1964         g_hash_table_iter_init (&iter, fields_of_interest);
1965         while (g_hash_table_iter_next (&iter, &key, &value)) {
1966                 const gchar  *field_name = key;
1967                 EContactField field      = e_contact_field_id (field_name);
1968
1969                 if (summary_dbname_from_field (ebsdb, field) == NULL) {
1970                         summary_fields = FALSE;
1971                         break;
1972                 }
1973         }
1974
1975         return summary_fields;
1976 }
1977
1978 /* free return value with g_free */
1979 static gchar *
1980 summary_select_stmt (GHashTable *fields_of_interest,
1981                      gboolean distinct)
1982 {
1983         GString *string;
1984
1985         if (distinct)
1986                 string = g_string_new ("SELECT DISTINCT summary.uid");
1987         else
1988                 string = g_string_new ("SELECT summary.uid");
1989
1990         /* Add the E_CONTACT_REV field if they are both requested */
1991         if (g_hash_table_size (fields_of_interest) == 2)
1992                 g_string_append (string, ", Rev");
1993
1994         return g_string_free (string, FALSE);
1995 }
1996
1997 static gint
1998 store_data_to_vcard (gpointer ref,
1999                      gint ncol,
2000                      gchar **cols,
2001                      gchar **name)
2002 {
2003         GSList **vcard_data = ref;
2004         EbSdbSearchData *search_data = g_slice_new0 (EbSdbSearchData);
2005         EContact *contact = e_contact_new ();
2006         gchar *vcard;
2007         gint i;
2008
2009         /* parse through cols, this will be useful if the api starts supporting field restrictions */
2010         for (i = 0; i < ncol; i++)
2011         {
2012                 if (!name[i] || !cols[i])
2013                         continue;
2014
2015                 /* Only UID & REV can be used to create contacts from the summary columns */
2016                 if (!g_ascii_strcasecmp (name[i], "uid")) {
2017                         e_contact_set (contact, E_CONTACT_UID, cols[i]);
2018
2019                         search_data->uid = g_strdup (cols[i]);
2020                 } else if (!g_ascii_strcasecmp (name[i], "Rev")) {
2021                         e_contact_set (contact, E_CONTACT_REV, cols[i]);
2022                 } else if (!g_ascii_strcasecmp (name[i], "bdata"))
2023                         search_data->bdata = g_strdup (cols[i]);
2024         }
2025
2026         vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
2027         search_data->vcard = vcard;
2028         *vcard_data = g_slist_prepend (*vcard_data, search_data);
2029
2030         g_object_unref (contact);
2031         return 0;
2032 }
2033
2034 /**
2035  * e_book_backend_sqlitedb_get_vcard_string:
2036  * @ebsdb: An #EBookBackendSqliteDB
2037  * @folderid: The folder id
2038  * @uid: The uid to fetch a vcard for
2039  * @fields_of_interest: The required fields for this vcard, or %NULL to require all fields.
2040  * @with_all_required_fields: (allow none) (out): Whether all the required fields are present in the returned vcard.
2041  * @error: A location to store any error that may have occurred.
2042  *
2043  * Searches @ebsdb in the context of @folderid for @uid.
2044  *
2045  * If @ebsdb is configured to store the whole vcards, the whole vcard will be returned.
2046  * Otherwise the summary cache will be searched and the virtual vcard will be built
2047  * from the summary cache.
2048  *
2049  * In either case, @with_all_required_fields if specified, will be updated to reflect whether
2050  * the returned vcard string satisfies the passed 'fields_of_interest' parameter.
2051  * 
2052  * Returns: (transfer full): The vcard string for @uid or %NULL if @uid was not found.
2053  *
2054  * Since: 3.2
2055  */
2056 gchar *
2057 e_book_backend_sqlitedb_get_vcard_string (EBookBackendSqliteDB *ebsdb,
2058                                           const gchar *folderid,
2059                                           const gchar *uid,
2060                                           GHashTable *fields_of_interest,
2061                                           gboolean *with_all_required_fields,
2062                                           GError **error)
2063 {
2064         gchar *stmt;
2065         gchar *vcard_str = NULL;
2066         gboolean local_with_all_required_fields = FALSE;
2067
2068         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
2069         g_return_val_if_fail (folderid != NULL, NULL);
2070         g_return_val_if_fail (uid != NULL, NULL);
2071
2072         READER_LOCK (ebsdb);
2073
2074         /* Try constructing contacts from only UID/REV first if that's requested */
2075         if (uid_rev_fields (fields_of_interest)) {
2076                 GSList *vcards = NULL;
2077                 gchar *select_portion;
2078
2079                 select_portion = summary_select_stmt (fields_of_interest, FALSE);
2080
2081                 stmt = sqlite3_mprintf (
2082                         "%s FROM %Q AS summary WHERE summary.uid = %Q",
2083                         select_portion, folderid, uid);
2084                 book_backend_sql_exec (ebsdb->priv->db, stmt, store_data_to_vcard, &vcards, error);
2085                 sqlite3_free (stmt);
2086                 g_free (select_portion);
2087
2088                 if (vcards) {
2089                         EbSdbSearchData *s_data = (EbSdbSearchData *) vcards->data;
2090
2091                         vcard_str = s_data->vcard;
2092                         s_data->vcard = NULL;
2093
2094                         e_book_backend_sqlitedb_search_data_free (s_data);
2095
2096                         g_slist_free (vcards);
2097                         vcards = NULL;
2098                 }
2099
2100                 local_with_all_required_fields = TRUE;
2101
2102         } else if (ebsdb->priv->store_vcard) {
2103
2104                 stmt = sqlite3_mprintf (
2105                         "SELECT vcard FROM %Q WHERE uid = %Q", folderid, uid);
2106                 book_backend_sql_exec (
2107                         ebsdb->priv->db, stmt,
2108                         get_vcard_cb , &vcard_str, error);
2109                 sqlite3_free (stmt);
2110
2111                 local_with_all_required_fields = TRUE;
2112         } else {
2113                 g_set_error (
2114                         error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
2115                         _("Full search_contacts are not stored in cache. vcards cannot be returned."));
2116
2117         }
2118
2119         READER_UNLOCK (ebsdb);
2120
2121         if (with_all_required_fields)
2122                 *with_all_required_fields = local_with_all_required_fields;
2123
2124         if (!vcard_str && error && !*error)
2125                 g_set_error (
2126                         error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_CONTACT_NOT_FOUND,
2127                         _("Contact '%s' not found"), uid ? uid : "NULL");
2128
2129         return vcard_str;
2130 }
2131
2132 enum {
2133         CHECK_IS_SUMMARY   = (1 << 0),
2134         CHECK_IS_LIST_ATTR = (1 << 1),
2135 };
2136
2137 static ESExpResult *
2138 func_check_subset (ESExp *f,
2139                    gint argc,
2140                    struct _ESExpTerm **argv,
2141                    gpointer data)
2142 {
2143         ESExpResult *r, *r1;
2144         gboolean one_non_summary_query = FALSE;
2145         gint result = 0;
2146         gint i;
2147
2148         for (i = 0; i < argc; i++) {
2149                 r1 = e_sexp_term_eval (f, argv[i]);
2150
2151                 if (r1->type != ESEXP_RES_INT) {
2152                         e_sexp_result_free (f, r1);
2153                         continue;
2154                 }
2155
2156                 result |= r1->value.number;
2157
2158                 if ((r1->value.number & CHECK_IS_SUMMARY) == 0)
2159                         one_non_summary_query = TRUE;
2160
2161                 e_sexp_result_free (f, r1);
2162         }
2163
2164         /* If at least one subset is not a summary query,
2165          * then the whole query is not a summary query and
2166          * thus cannot be done with an SQL statement
2167          */
2168         if (one_non_summary_query)
2169                 result = 0;
2170
2171         r = e_sexp_result_new (f, ESEXP_RES_INT);
2172         r->value.number = result;
2173
2174         return r;
2175 }
2176
2177 static ESExpResult *
2178 func_check (struct _ESExp *f,
2179             gint argc,
2180             struct _ESExpResult **argv,
2181             gpointer data)
2182 {
2183         EBookBackendSqliteDB *ebsdb = data;
2184         ESExpResult *r;
2185         gint ret_val = 0;
2186
2187         if (argc == 2
2188             && argv[0]->type == ESEXP_RES_STRING
2189             && argv[1]->type == ESEXP_RES_STRING) {
2190                 const gchar *query_name = argv[0]->value.string;
2191                 const gchar *query_value = argv[1]->value.string;
2192                 gint i;
2193
2194                 /* Special case, when testing the special symbolic 'any field' we can
2195                  * consider it a summary query (it's similar to a 'no query'). */
2196                 if (g_strcmp0 (query_name, "x-evolution-any-field") == 0 &&
2197                     g_strcmp0 (query_value, "") == 0) {
2198                         ret_val |= CHECK_IS_SUMMARY;
2199                         goto check_finish;
2200                 }
2201
2202                 if (ebsdb) {
2203                         for (i = 0; i < ebsdb->priv->n_summary_fields; i++) {
2204                                 if (!g_ascii_strcasecmp (e_contact_field_name (ebsdb->priv->summary_fields[i].field), query_name)) {
2205                                         ret_val |= CHECK_IS_SUMMARY;
2206
2207                                         if (ebsdb->priv->summary_fields[i].type == E_TYPE_CONTACT_ATTR_LIST)
2208                                                 ret_val |= CHECK_IS_LIST_ATTR;
2209                                 }
2210                         }
2211                 } else {
2212                         for (i = 0; i < G_N_ELEMENTS (default_summary_fields); i++) {
2213
2214                                 if (!g_ascii_strcasecmp (e_contact_field_name (default_summary_fields[i]), query_name)) {
2215                                         ret_val |= CHECK_IS_SUMMARY;
2216
2217                                         if (e_contact_field_type (default_summary_fields[i]) == E_TYPE_CONTACT_ATTR_LIST)
2218                                                 ret_val |= CHECK_IS_LIST_ATTR;
2219                                 }
2220                         }
2221                 }
2222         }
2223
2224  check_finish:
2225
2226         r = e_sexp_result_new (f, ESEXP_RES_INT);
2227         r->value.number = ret_val;
2228
2229         return r;
2230 }
2231
2232 /* 'builtin' functions */
2233 static const struct {
2234         const gchar *name;
2235         ESExpFunc *func;
2236         gint type;              /* set to 1 if a function can perform shortcut evaluation, or
2237                                    doesn't execute everything, 0 otherwise */
2238 } check_symbols[] = {
2239         { "and", (ESExpFunc *) func_check_subset, 1},
2240         { "or", (ESExpFunc *) func_check_subset, 1},
2241
2242         { "contains", func_check, 0 },
2243         { "is", func_check, 0 },
2244         { "beginswith", func_check, 0 },
2245         { "endswith", func_check, 0 },
2246         { "exists", func_check, 0 }
2247 };
2248
2249 /**
2250  * e_book_backend_sqlitedb_check_summary_query:
2251  * @ebsdb: an #EBookBackendSqliteDB
2252  * @query: the query to check
2253  * @with_list_attrs: Return location to store whether the query touches upon list attributes
2254  *
2255  * Checks whether @query contains only checks for the summary fields
2256  * configured in @ebsdb
2257  *
2258  * Since: 3.8
2259  **/
2260 gboolean
2261 e_book_backend_sqlitedb_check_summary_query (EBookBackendSqliteDB *ebsdb,
2262                                              const gchar *query,
2263                                              gboolean *with_list_attrs)
2264 {
2265         ESExp *sexp;
2266         ESExpResult *r;
2267         gboolean retval = FALSE;
2268         gint i;
2269         gint esexp_error;
2270
2271         g_return_val_if_fail (query != NULL, FALSE);
2272         g_return_val_if_fail (*query != '\0', FALSE);
2273
2274         sexp = e_sexp_new ();
2275
2276         for (i = 0; i < G_N_ELEMENTS (check_symbols); i++) {
2277                 if (check_symbols[i].type == 1) {
2278                         e_sexp_add_ifunction (
2279                                 sexp, 0, check_symbols[i].name,
2280                                 (ESExpIFunc *) check_symbols[i].func, ebsdb);
2281                 } else {
2282                         e_sexp_add_function (
2283                                 sexp, 0, check_symbols[i].name,
2284                                 check_symbols[i].func, ebsdb);
2285                 }
2286         }
2287
2288         e_sexp_input_text (sexp, query, strlen (query));
2289         esexp_error = e_sexp_parse (sexp);
2290
2291         if (esexp_error == -1) {
2292                 return FALSE;
2293         }
2294
2295         r = e_sexp_eval (sexp);
2296         if (r && r->type == ESEXP_RES_INT) {
2297                 retval = (r->value.number & CHECK_IS_SUMMARY) != 0;
2298
2299                 if ((r->value.number & CHECK_IS_LIST_ATTR) != 0 && with_list_attrs)
2300                         *with_list_attrs = TRUE;
2301         }
2302
2303         e_sexp_result_free (sexp, r);
2304         e_sexp_unref (sexp);
2305
2306         return retval;
2307 }
2308
2309 /**
2310  * e_book_backend_sqlitedb_is_summary_query:
2311  *
2312  * Checks whether the query contains only checks for the default summary fields
2313  *
2314  * Since: 3.2
2315  *
2316  * Deprecated: 3.8: Use e_book_backend_sqlitedb_check_summary_query() instead
2317  **/
2318 gboolean
2319 e_book_backend_sqlitedb_is_summary_query (const gchar *query)
2320 {
2321         return e_book_backend_sqlitedb_check_summary_query (NULL, query, NULL);
2322 }
2323
2324 static ESExpResult *
2325 func_and (ESExp *f,
2326           gint argc,
2327           struct _ESExpTerm **argv,
2328           gpointer data)
2329 {
2330         ESExpResult *r, *r1;
2331         GString *string;
2332         gint i;
2333
2334         string = g_string_new ("( ");
2335         for (i = 0; i < argc; i++) {
2336                 r1 = e_sexp_term_eval (f, argv[i]);
2337
2338                 if (r1->type != ESEXP_RES_STRING) {
2339                         e_sexp_result_free (f, r1);
2340                         continue;
2341                 }
2342                 if (r1->value.string && *r1->value.string)
2343                         g_string_append_printf (string, "%s%s", r1->value.string, ((argc > 1) && (i != argc - 1)) ? " AND ":"");
2344                 e_sexp_result_free (f, r1);
2345         }
2346         g_string_append (string, " )");
2347         r = e_sexp_result_new (f, ESEXP_RES_STRING);
2348
2349         if (strlen (string->str) == 4) {
2350                 r->value.string = g_strdup ("");
2351                 g_string_free (string, TRUE);
2352         } else {
2353                 r->value.string = g_string_free (string, FALSE);
2354         }
2355
2356         return r;
2357 }
2358
2359 static ESExpResult *
2360 func_or (ESExp *f,
2361          gint argc,
2362          struct _ESExpTerm **argv,
2363          gpointer data)
2364 {
2365         ESExpResult *r, *r1;
2366         GString *string;
2367         gint i;
2368
2369         string = g_string_new ("( ");
2370         for (i = 0; i < argc; i++) {
2371                 r1 = e_sexp_term_eval (f, argv[i]);
2372
2373                 if (r1->type != ESEXP_RES_STRING) {
2374                         e_sexp_result_free (f, r1);
2375                         continue;
2376                 }
2377                 if (r1->value.string && *r1->value.string)
2378                         g_string_append_printf (string, "%s%s", r1->value.string, ((argc > 1) && (i != argc - 1)) ? " OR ":"");
2379                 e_sexp_result_free (f, r1);
2380         }
2381         g_string_append (string, " )");
2382
2383         r = e_sexp_result_new (f, ESEXP_RES_STRING);
2384         if (strlen (string->str) == 4) {
2385                 r->value.string = g_strdup ("");
2386                 g_string_free (string, TRUE);
2387         } else {
2388                 r->value.string = g_string_free (string, FALSE);
2389         }
2390
2391         return r;
2392 }
2393
2394 typedef enum {
2395         MATCH_CONTAINS,
2396         MATCH_IS,
2397         MATCH_BEGINS_WITH,
2398         MATCH_ENDS_WITH
2399 } match_type;
2400
2401 static gchar *
2402 convert_string_value (const gchar *value,
2403                       gboolean normalize,
2404                       gboolean reverse,
2405                       match_type match)
2406 {
2407         GString *str;
2408         size_t len;
2409         gchar c;
2410         gboolean escape_modifier_needed = FALSE;
2411         const gchar *escape_modifier = " ESCAPE '^'";
2412         gchar *reverse_val = NULL;
2413         gchar *normal;
2414         const gchar *ptr;
2415
2416         g_return_val_if_fail (value != NULL, NULL);
2417
2418         if (normalize)
2419                 normal = e_util_utf8_normalize (value);
2420         else
2421                 normal = g_strdup (value);
2422
2423         /* Just assume each character must be escaped. The result of this function
2424          * is discarded shortly after calling this function. Therefore it's
2425          * acceptable to possibly allocate twice the memory needed.
2426          */
2427         len = strlen (normal);
2428         str = g_string_sized_new (2 * len + 4 + strlen (escape_modifier) - 1);
2429         g_string_append_c (str, '\'');
2430
2431         switch (match) {
2432         case MATCH_CONTAINS:
2433         case MATCH_ENDS_WITH:
2434                 g_string_append_c (str, '%');
2435                 break;
2436
2437         case MATCH_BEGINS_WITH:
2438         case MATCH_IS:
2439                 break;
2440         }
2441
2442         if (reverse) {
2443                 reverse_val = g_utf8_strreverse (normal, -1);
2444                 ptr = reverse_val;
2445         } else {
2446                 ptr = normal;
2447         }
2448
2449         while ((c = *ptr++)) {
2450                 if (c == '\'') {
2451                         g_string_append_c (str, '\'');
2452                 } else if (c == '%' || c == '^') {
2453                         g_string_append_c (str, '^');
2454                         escape_modifier_needed = TRUE;
2455                 }
2456
2457                 g_string_append_c (str, c);
2458         }
2459
2460         switch (match) {
2461         case MATCH_CONTAINS:
2462         case MATCH_BEGINS_WITH:
2463                 g_string_append_c (str, '%');
2464                 break;
2465
2466         case MATCH_ENDS_WITH:
2467         case MATCH_IS:
2468                 break;
2469         }
2470
2471         g_string_append_c (str, '\'');
2472
2473         if (escape_modifier_needed)
2474                 g_string_append (str, escape_modifier);
2475
2476         g_free (reverse_val);
2477         g_free (normal);
2478
2479         return g_string_free (str, FALSE);
2480 }
2481
2482 static gchar *
2483 field_name_and_query_term (EBookBackendSqliteDB *ebsdb,
2484                            const gchar *folderid,
2485                            const gchar *field_name_input,
2486                            const gchar *query_term_input,
2487                            match_type match,
2488                            gboolean *is_list_attr,
2489                            gchar **query_term)
2490 {
2491         gint summary_index;
2492         gchar *field_name = NULL;
2493         gchar *value = NULL;
2494         gboolean list_attr = FALSE;
2495
2496         summary_index = summary_index_from_field_name (ebsdb, field_name_input);
2497
2498         if (summary_index < 0) {
2499                 g_critical ("Only summary field matches should be converted to sql queries");
2500                 field_name = g_strconcat (folderid, ".", field_name_input, NULL);
2501                 value = convert_string_value (query_term_input, TRUE, FALSE, match);
2502         } else {
2503                 gboolean suffix_search = FALSE;
2504
2505                 /* If its a suffix search and we have reverse data to search... */
2506                 if (match == MATCH_ENDS_WITH &&
2507                     (ebsdb->priv->summary_fields[summary_index].index & INDEX_SUFFIX) != 0)
2508                         suffix_search = TRUE;
2509
2510                 /* Or also if its an exact match, and we *only* have reverse data which is indexed,
2511                  * then prefer the indexed reverse search. */
2512                 else if (match == MATCH_IS &&
2513                          (ebsdb->priv->summary_fields[summary_index].index & INDEX_SUFFIX) != 0 &&
2514                          (ebsdb->priv->summary_fields[summary_index].index & INDEX_PREFIX) == 0)
2515                         suffix_search = TRUE;
2516
2517                 if (suffix_search) {
2518                         /* Special case for suffix matching:
2519                          *  o Reverse the string
2520                          *  o Check the reversed column instead
2521                          *  o Make it a prefix search
2522                          */
2523                         if (ebsdb->priv->summary_fields[summary_index].type == E_TYPE_CONTACT_ATTR_LIST) {
2524                                 field_name = g_strdup ("multi.value_reverse");
2525                                 list_attr = TRUE;
2526                         } else
2527                                 field_name = g_strconcat (
2528                                         "summary.",
2529                                         ebsdb->priv->summary_fields[summary_index].dbname,
2530                                         "_reverse", NULL);
2531
2532                         if (ebsdb->priv->summary_fields[summary_index].field == E_CONTACT_UID ||
2533                             ebsdb->priv->summary_fields[summary_index].field == E_CONTACT_REV)
2534                                 value = convert_string_value (
2535                                         query_term_input, FALSE, TRUE,
2536                                         (match == MATCH_ENDS_WITH) ? MATCH_BEGINS_WITH : MATCH_IS);
2537                         else
2538                                 value = convert_string_value (
2539                                         query_term_input, TRUE, TRUE,
2540                                         (match == MATCH_ENDS_WITH) ? MATCH_BEGINS_WITH : MATCH_IS);
2541                 } else {
2542
2543                         if (ebsdb->priv->summary_fields[summary_index].type == E_TYPE_CONTACT_ATTR_LIST) {
2544                                 field_name = g_strdup ("multi.value");
2545                                 list_attr = TRUE;
2546                         } else
2547                                 field_name = g_strconcat (
2548                                         "summary.",
2549                                         ebsdb->priv->summary_fields[summary_index].dbname, NULL);
2550
2551                         if (ebsdb->priv->summary_fields[summary_index].field == E_CONTACT_UID ||
2552                             ebsdb->priv->summary_fields[summary_index].field == E_CONTACT_REV)
2553                                 value = convert_string_value (query_term_input, FALSE, FALSE, match);
2554                         else
2555                                 value = convert_string_value (query_term_input, TRUE, FALSE, match);
2556                 }
2557         }
2558
2559         if (is_list_attr)
2560                 *is_list_attr = list_attr;
2561
2562         *query_term = value;
2563
2564         return field_name;
2565 }
2566
2567 typedef struct {
2568         EBookBackendSqliteDB *ebsdb;
2569         const gchar          *folderid;
2570 } BuildQueryData;
2571
2572 static ESExpResult *
2573 convert_match_exp (struct _ESExp *f,
2574                    gint argc,
2575                    struct _ESExpResult **argv,
2576                    gpointer data,
2577                    match_type match)
2578 {
2579         BuildQueryData *qdata = (BuildQueryData *) data;
2580         EBookBackendSqliteDB *ebsdb = qdata->ebsdb;
2581         ESExpResult *r;
2582         gchar *str = NULL;
2583
2584         /* are we inside a match-all? */
2585         if (argc > 1 && argv[0]->type == ESEXP_RES_STRING) {
2586                 const gchar *field;
2587
2588                 /* only a subset of headers are supported .. */
2589                 field = argv[0]->value.string;
2590
2591                 if (argv[1]->type == ESEXP_RES_STRING && argv[1]->value.string[0] != 0) {
2592                         const gchar *oper = "LIKE";
2593                         gchar *field_name, *query_term;
2594
2595                         if (match == MATCH_IS)
2596                                 oper = "=";
2597
2598                         if (!g_ascii_strcasecmp (field, "full_name")) {
2599                                 GString *names = g_string_new (NULL);
2600
2601                                 field_name = field_name_and_query_term (
2602                                         ebsdb, qdata->folderid, "full_name",
2603                                         argv[1]->value.string,
2604                                         match, NULL, &query_term);
2605                                 g_string_append_printf (
2606                                         names, "(%s IS NOT NULL AND %s %s %s)",
2607                                         field_name, field_name, oper, query_term);
2608                                 g_free (field_name);
2609                                 g_free (query_term);
2610
2611                                 if (summary_dbname_from_field (ebsdb, E_CONTACT_FAMILY_NAME)) {
2612
2613                                         field_name = field_name_and_query_term (
2614                                                 ebsdb, qdata->folderid, "family_name",
2615                                                 argv[1]->value.string,
2616                                                 match, NULL, &query_term);
2617                                         g_string_append_printf (
2618                                                 names, " OR (%s IS NOT NULL AND %s %s %s)",
2619                                                 field_name, field_name, oper, query_term);
2620                                         g_free (field_name);
2621                                         g_free (query_term);
2622                                 }
2623
2624                                 if (summary_dbname_from_field (ebsdb, E_CONTACT_GIVEN_NAME)) {
2625
2626                                         field_name = field_name_and_query_term (
2627                                                 ebsdb, qdata->folderid, "given_name",
2628                                                 argv[1]->value.string,
2629                                                 match, NULL, &query_term);
2630                                         g_string_append_printf (
2631                                                 names, " OR (%s IS NOT NULL AND %s %s %s)",
2632                                                 field_name, field_name, oper, query_term);
2633                                         g_free (field_name);
2634                                         g_free (query_term);
2635                                 }
2636
2637                                 if (summary_dbname_from_field (ebsdb, E_CONTACT_NICKNAME)) {
2638
2639                                         field_name = field_name_and_query_term (
2640                                                 ebsdb, qdata->folderid, "nickname",
2641                                                 argv[1]->value.string,
2642                                                 match, NULL, &query_term);
2643                                         g_string_append_printf (
2644                                                 names, " OR (%s IS NOT NULL AND %s %s %s)",
2645                                                 field_name, field_name, oper, query_term);
2646                                         g_free (field_name);
2647                                         g_free (query_term);
2648                                 }
2649
2650                                 str = names->str;
2651                                 g_string_free (names, FALSE);
2652
2653                         } else {
2654                                 gboolean is_list = FALSE;
2655
2656                                 /* This should ideally be the only valid case from all the above special casing, but oh well... */
2657                                 field_name = field_name_and_query_term (
2658                                         ebsdb, qdata->folderid, field,
2659                                         argv[1]->value.string,
2660                                         match, &is_list, &query_term);
2661
2662                                 if (is_list) {
2663                                         gchar *tmp;
2664
2665                                         tmp = sqlite3_mprintf ("summary.uid = multi.uid AND multi.field = %Q", field);
2666                                         str = g_strdup_printf (
2667                                                 "(%s AND %s %s %s)",
2668                                                 tmp, field_name, oper, query_term);
2669                                         sqlite3_free (tmp);
2670                                 } else
2671                                         str = g_strdup_printf (
2672                                                 "(%s IS NOT NULL AND %s %s %s)",
2673                                                 field_name, field_name, oper, query_term);
2674
2675                                 g_free (field_name);
2676                                 g_free (query_term);
2677                         }
2678                 }
2679         }
2680
2681         r = e_sexp_result_new (f, ESEXP_RES_STRING);
2682         r->value.string = str;
2683
2684         return r;
2685 }
2686
2687 static ESExpResult *
2688 func_contains (struct _ESExp *f,
2689                gint argc,
2690                struct _ESExpResult **argv,
2691                gpointer data)
2692 {
2693         return convert_match_exp (f, argc, argv, data, MATCH_CONTAINS);
2694 }
2695
2696 static ESExpResult *
2697 func_is (struct _ESExp *f,
2698          gint argc,
2699          struct _ESExpResult **argv,
2700          gpointer data)
2701 {
2702         return convert_match_exp (f, argc, argv, data, MATCH_IS);
2703 }
2704
2705 static ESExpResult *
2706 func_beginswith (struct _ESExp *f,
2707                  gint argc,
2708                  struct _ESExpResult **argv,
2709                  gpointer data)
2710 {
2711         return convert_match_exp (f, argc, argv, data, MATCH_BEGINS_WITH);
2712 }
2713
2714 static ESExpResult *
2715 func_endswith (struct _ESExp *f,
2716                gint argc,
2717                struct _ESExpResult **argv,
2718                gpointer data)
2719 {
2720         return convert_match_exp (f, argc, argv, data, MATCH_ENDS_WITH);
2721 }
2722
2723 /* 'builtin' functions */
2724 static struct {
2725         const gchar *name;
2726         ESExpFunc *func;
2727         guint immediate :1;
2728 } symbols[] = {
2729         { "and", (ESExpFunc *) func_and, 1},
2730         { "or", (ESExpFunc *) func_or, 1},
2731
2732         { "contains", func_contains, 0 },
2733         { "is", func_is, 0 },
2734         { "beginswith", func_beginswith, 0 },
2735         { "endswith", func_endswith, 0 },
2736 };
2737
2738 static gchar *
2739 sexp_to_sql_query (EBookBackendSqliteDB *ebsdb,
2740                    const gchar *folderid,
2741                    const gchar *query)
2742 {
2743         BuildQueryData data = { ebsdb, folderid };
2744         ESExp *sexp;
2745         ESExpResult *r;
2746         gint i;
2747         gchar *res;
2748
2749         sexp = e_sexp_new ();
2750
2751         for (i = 0; i < G_N_ELEMENTS (symbols); i++) {
2752                 if (symbols[i].immediate)
2753                         e_sexp_add_ifunction (
2754                                 sexp, 0, symbols[i].name,
2755                                 (ESExpIFunc *) symbols[i].func, &data);
2756                 else
2757                         e_sexp_add_function (
2758                                 sexp, 0, symbols[i].name,
2759                                 symbols[i].func, &data);
2760         }
2761
2762         e_sexp_input_text (sexp, query, strlen (query));
2763         e_sexp_parse (sexp);
2764
2765         r = e_sexp_eval (sexp);
2766         if (!r)
2767                 return NULL;
2768         if (r->type == ESEXP_RES_STRING) {
2769                 if (r->value.string && *r->value.string)
2770                         res = g_strdup (r->value.string);
2771                 else
2772                         res = NULL;
2773         } else {
2774                 g_warn_if_reached ();
2775                 res = NULL;
2776         }
2777
2778         e_sexp_result_free (sexp, r);
2779         e_sexp_unref (sexp);
2780
2781         return res;
2782 }
2783
2784 static gint
2785 addto_vcard_list_cb (gpointer ref,
2786                      gint col,
2787                      gchar **cols,
2788                      gchar **name)
2789 {
2790         GSList **vcard_data = ref;
2791         EbSdbSearchData *s_data = g_slice_new0 (EbSdbSearchData);
2792
2793         if (cols[0])
2794                 s_data->uid = g_strdup (cols[0]);
2795
2796         if (cols[1])
2797                 s_data->vcard = g_strdup (cols[1]);
2798
2799         if (cols[2])
2800                 s_data->bdata = g_strdup (cols[2]);
2801
2802         *vcard_data = g_slist_prepend (*vcard_data, s_data);
2803
2804         return 0;
2805 }
2806
2807 static gint
2808 addto_slist_cb (gpointer ref,
2809                 gint col,
2810                 gchar **cols,
2811                 gchar **name)
2812 {
2813         GSList **uids = ref;
2814
2815         if (cols[0])
2816                 *uids = g_slist_prepend (*uids, g_strdup (cols [0]));
2817
2818         return 0;
2819 }
2820
2821 static GSList *
2822 book_backend_sqlitedb_search_query (EBookBackendSqliteDB *ebsdb,
2823                                     const gchar *sql,
2824                                     const gchar *folderid,
2825                                     GHashTable *fields_of_interest,
2826                                     gboolean *with_all_required_fields,
2827                                     gboolean query_with_list_attrs,
2828                                     GError **error)
2829 {
2830         GSList *vcard_data = NULL;
2831         gchar  *stmt;
2832         gboolean local_with_all_required_fields = FALSE;
2833         gboolean success = TRUE;
2834
2835         READER_LOCK (ebsdb);
2836
2837         /* Try constructing contacts from only UID/REV first if that's requested */
2838         if (uid_rev_fields (fields_of_interest)) {
2839                 gchar *select_portion;
2840
2841                 select_portion = summary_select_stmt (
2842                         fields_of_interest, query_with_list_attrs);
2843
2844                 if (sql && sql[0]) {
2845
2846                         if (query_with_list_attrs) {
2847                                 gchar *list_table = g_strconcat (folderid, "_lists", NULL);
2848
2849                                 stmt = sqlite3_mprintf (
2850                                         "%s FROM %Q AS summary, %Q AS multi WHERE %s",
2851                                         select_portion, folderid, list_table, sql);
2852                                 g_free (list_table);
2853                         } else {
2854                                 stmt = sqlite3_mprintf (
2855                                         "%s FROM %Q AS summary WHERE %s",
2856                                         select_portion, folderid, sql);
2857                         }
2858
2859                         success = book_backend_sql_exec (
2860                                 ebsdb->priv->db, stmt,
2861                                 store_data_to_vcard, &vcard_data, error);
2862
2863                         sqlite3_free (stmt);
2864                 } else {
2865                         stmt = sqlite3_mprintf ("%s FROM %Q AS summary", select_portion, folderid);
2866                         success = book_backend_sql_exec (
2867                                 ebsdb->priv->db, stmt,
2868                                 store_data_to_vcard, &vcard_data, error);
2869                         sqlite3_free (stmt);
2870                 }
2871
2872                 local_with_all_required_fields = TRUE;
2873                 g_free (select_portion);
2874
2875         } else if (ebsdb->priv->store_vcard) {
2876
2877                 if (sql && sql[0]) {
2878
2879                         if (query_with_list_attrs) {
2880                                 gchar *list_table = g_strconcat (folderid, "_lists", NULL);
2881
2882                                 stmt = sqlite3_mprintf (
2883                                         "SELECT DISTINCT summary.uid, vcard, bdata "
2884                                         "FROM %Q AS summary, %Q AS multi WHERE %s",
2885                                         folderid, list_table, sql);
2886                                 g_free (list_table);
2887                         } else {
2888                                 stmt = sqlite3_mprintf (
2889                                         "SELECT uid, vcard, bdata FROM %Q as summary WHERE %s", folderid, sql);
2890                         }
2891
2892                         success = book_backend_sql_exec (
2893                                 ebsdb->priv->db, stmt,
2894                                 addto_vcard_list_cb , &vcard_data, error);
2895
2896                         sqlite3_free (stmt);
2897                 } else {
2898                         stmt = sqlite3_mprintf (
2899                                 "SELECT uid, vcard, bdata FROM %Q", folderid);
2900                         success = book_backend_sql_exec (
2901                                 ebsdb->priv->db, stmt,
2902                                 addto_vcard_list_cb , &vcard_data, error);
2903                         sqlite3_free (stmt);
2904                 }
2905
2906                 local_with_all_required_fields = TRUE;
2907         } else {
2908                 g_set_error (
2909                         error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
2910                         _("Full search_contacts are not stored in cache. vcards cannot be returned."));
2911         }
2912
2913         READER_UNLOCK (ebsdb);
2914
2915         if (!success) {
2916                 g_warn_if_fail (vcard_data == NULL);
2917                 return NULL;
2918         }
2919
2920         if (with_all_required_fields)
2921                 *with_all_required_fields = local_with_all_required_fields;
2922
2923         return g_slist_reverse (vcard_data);
2924 }
2925
2926 static GSList *
2927 book_backend_sqlitedb_search_full (EBookBackendSqliteDB *ebsdb,
2928                                    const gchar *sexp,
2929                                    const gchar *folderid,
2930                                    gboolean return_uids,
2931                                    GError **error)
2932 {
2933         GSList *r_list = NULL, *all = NULL, *l;
2934         EBookBackendSExp *bsexp = NULL;
2935         gboolean success;
2936         gchar *stmt;
2937
2938         READER_LOCK (ebsdb);
2939
2940         stmt = sqlite3_mprintf ("SELECT uid, vcard, bdata FROM %Q", folderid);
2941         success = book_backend_sql_exec (
2942                 ebsdb->priv->db, stmt, addto_vcard_list_cb , &all, error);
2943         sqlite3_free (stmt);
2944
2945         READER_UNLOCK (ebsdb);
2946
2947         if (!success) {
2948                 g_warn_if_fail (all == NULL);
2949                 return NULL;
2950         }
2951
2952         bsexp = e_book_backend_sexp_new (sexp);
2953
2954         for (l = all; l != NULL; l = g_slist_next (l)) {
2955                 EbSdbSearchData *s_data = (EbSdbSearchData *) l->data;
2956
2957                 if (e_book_backend_sexp_match_vcard (bsexp, s_data->vcard)) {
2958                         if (!return_uids)
2959                                 r_list = g_slist_prepend (r_list, s_data);
2960                         else {
2961                                 r_list = g_slist_prepend (r_list, g_strdup (s_data->uid));
2962                                 e_book_backend_sqlitedb_search_data_free (s_data);
2963                         }
2964                 } else
2965                         e_book_backend_sqlitedb_search_data_free (s_data);
2966         }
2967
2968         g_object_unref (bsexp);
2969
2970         g_slist_free (all);
2971
2972         return r_list;
2973 }
2974
2975 /**
2976  * e_book_backend_sqlitedb_search 
2977  * @ebsdb: 
2978  * @folderid: 
2979  * @sexp: search expression; use NULL or an empty string to get all stored
2980  * contacts.
2981  * @fields_of_interest: a #GHashTable containing the names of fields to return,
2982  * or NULL for all.  At the moment if this is non-null, the vcard will be
2983  * populated with summary fields, else it would return the whole vcard if
2984  * its stored in the db. [not implemented fully]
2985  * @searched: (allow none) (out): Whether @ebsdb was capable of searching
2986  * for the provided query @sexp.
2987  * @with_all_required_fields: (allow none) (out): Whether all the required
2988  * fields are present in the returned vcards.
2989  * @error: 
2990  *
2991  * Searching with summary fields is always supported. Search expressions
2992  * containing any other field is supported only if backend chooses to store
2993  * the vcard inside the db.
2994  *
2995  * Summary fields - uid, rev, nickname, given_name, family_name, file_as
2996  * email_1, email_2, email_3, email_4, is_list, list_show_addresses, wants_html
2997  *
2998  * If @ebsdb was incapable of returning vcards with results that satisfy
2999  * @fields_of_interest, then @with_all_required_fields will be updated to
3000  * @FALSE and only uid fields will be present in the returned vcards. This
3001  * can be useful when a summary query succeeds and the returned list can be
3002  * used to iterate and fetch for full required data from another persistance.
3003  *
3004  * Returns: List of EbSdbSearchData.
3005  *
3006  * Since: 3.2
3007  **/
3008 GSList *
3009 e_book_backend_sqlitedb_search (EBookBackendSqliteDB *ebsdb,
3010                                 const gchar *folderid,
3011                                 const gchar *sexp,
3012                                 GHashTable *fields_of_interest,
3013                                 gboolean *searched,
3014                                 gboolean *with_all_required_fields,
3015                                 GError **error)
3016 {
3017         GSList *search_contacts = NULL;
3018         gboolean local_searched = FALSE;
3019         gboolean local_with_all_required_fields = FALSE;
3020         gboolean query_with_list_attrs = FALSE;
3021
3022         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
3023         g_return_val_if_fail (folderid != NULL, NULL);
3024
3025         if (sexp && !*sexp)
3026                 sexp = NULL;
3027
3028         if (!sexp || e_book_backend_sqlitedb_check_summary_query (ebsdb, sexp,
3029                                                                   &query_with_list_attrs)) {
3030                 gchar *sql_query;
3031
3032                 sql_query = sexp ? sexp_to_sql_query (ebsdb, folderid, sexp) : NULL;
3033                 search_contacts = book_backend_sqlitedb_search_query (
3034                         ebsdb, sql_query, folderid,
3035                         fields_of_interest,
3036                         &local_with_all_required_fields,
3037                         query_with_list_attrs, error);
3038                 g_free (sql_query);
3039
3040                 local_searched = TRUE;
3041
3042         } else if (ebsdb->priv->store_vcard) {
3043                 search_contacts = book_backend_sqlitedb_search_full (
3044                         ebsdb, sexp, folderid, FALSE, error);
3045
3046                 local_searched = TRUE;
3047                 local_with_all_required_fields = TRUE;
3048
3049         } else {
3050                 g_set_error (
3051                         error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
3052                         _("Full search_contacts are not stored in cache. "
3053                         "Hence only summary query is supported."));
3054         }
3055
3056         if (searched)
3057                 *searched = local_searched;
3058         if (with_all_required_fields)
3059                 *with_all_required_fields = local_with_all_required_fields;
3060
3061         return search_contacts;
3062 }
3063
3064 /**
3065  * e_book_backend_sqlitedb_search_uids:
3066  *
3067  * FIXME: Document me.
3068  *
3069  * Since: 3.2
3070  **/
3071 GSList *
3072 e_book_backend_sqlitedb_search_uids (EBookBackendSqliteDB *ebsdb,
3073                                      const gchar *folderid,
3074                                      const gchar *sexp,
3075                                      gboolean *searched,
3076                                      GError **error)
3077 {
3078         GSList *uids = NULL;
3079         gboolean local_searched = FALSE;
3080         gboolean query_with_list_attrs = FALSE;
3081
3082         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
3083         g_return_val_if_fail (folderid != NULL, NULL);
3084
3085         if (sexp && !*sexp)
3086                 sexp = NULL;
3087
3088         if (!sexp || e_book_backend_sqlitedb_check_summary_query (ebsdb, sexp, &query_with_list_attrs)) {
3089                 gchar *stmt;
3090                 gchar *sql_query = sexp ? sexp_to_sql_query (ebsdb, folderid, sexp) : NULL;
3091
3092                 READER_LOCK (ebsdb);
3093
3094                 if (sql_query && sql_query[0]) {
3095
3096                         if (query_with_list_attrs) {
3097                                 gchar *list_table = g_strconcat (folderid, "_lists", NULL);
3098
3099                                 stmt = sqlite3_mprintf (
3100                                         "SELECT DISTINCT summary.uid FROM %Q AS summary, %Q AS multi WHERE %s",
3101                                         folderid, list_table, sql_query);
3102
3103                                 g_free (list_table);
3104                         } else
3105                                 stmt = sqlite3_mprintf (
3106                                         "SELECT summary.uid FROM %Q AS summary WHERE %s",
3107                                         folderid, sql_query);
3108
3109                         book_backend_sql_exec (ebsdb->priv->db, stmt, addto_slist_cb, &uids, error);
3110                         sqlite3_free (stmt);
3111
3112                 } else {
3113                         stmt = sqlite3_mprintf ("SELECT uid FROM %Q", folderid);
3114                         book_backend_sql_exec (ebsdb->priv->db, stmt, addto_slist_cb, &uids, error);
3115                         sqlite3_free (stmt);
3116                 }
3117
3118                 READER_UNLOCK (ebsdb);
3119
3120                 local_searched = TRUE;
3121
3122                 g_free (sql_query);
3123
3124         } else if (ebsdb->priv->store_vcard) {
3125                 uids = book_backend_sqlitedb_search_full (
3126                         ebsdb, sexp, folderid, TRUE, error);
3127
3128                 local_searched = TRUE;
3129
3130         } else {
3131                 g_set_error (
3132                         error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
3133                         _("Full vcards are not stored in cache. "
3134                         "Hence only summary query is supported."));
3135         }
3136
3137         if (searched)
3138                 *searched = local_searched;
3139
3140         return uids;
3141 }
3142
3143 static gint
3144 get_uids_and_rev_cb (gpointer user_data,
3145                      gint col,
3146                      gchar **cols,
3147                      gchar **name)
3148 {
3149         GHashTable *uids_and_rev = user_data;
3150
3151         if (col == 2 && cols[0])
3152                 g_hash_table_insert (uids_and_rev, g_strdup (cols[0]), g_strdup (cols[1] ? cols[1] : ""));
3153
3154         return 0;
3155 }
3156
3157 /**
3158  * e_book_backend_sqlitedb_get_uids_and_rev:
3159  *
3160  * Gets hash table of all uids (key) and rev (value) pairs stored
3161  * for each contact in the cache. The hash table should be freed
3162  * with g_hash_table_destroy(), if not needed anymore. Each key
3163  * and value is a newly allocated string.
3164  *
3165  * Since: 3.4
3166  **/
3167 GHashTable *
3168 e_book_backend_sqlitedb_get_uids_and_rev (EBookBackendSqliteDB *ebsdb,
3169                                           const gchar *folderid,
3170                                           GError **error)
3171 {
3172         GHashTable *uids_and_rev;
3173         gchar *stmt;
3174
3175         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
3176         g_return_val_if_fail (folderid != NULL, NULL);
3177
3178         uids_and_rev = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
3179
3180         READER_LOCK (ebsdb);
3181
3182         stmt = sqlite3_mprintf ("SELECT uid,rev FROM %Q", folderid);
3183         book_backend_sql_exec (
3184                 ebsdb->priv->db, stmt,
3185                 get_uids_and_rev_cb, uids_and_rev, error);
3186         sqlite3_free (stmt);
3187
3188         READER_UNLOCK (ebsdb);
3189
3190         return uids_and_rev;
3191 }
3192
3193 /**
3194  * e_book_backend_sqlitedb_get_is_populated:
3195  *
3196  * FIXME: Document me.
3197  *
3198  * Since: 3.2
3199  **/
3200 gboolean
3201 e_book_backend_sqlitedb_get_is_populated (EBookBackendSqliteDB *ebsdb,
3202                                           const gchar *folderid,
3203                                           GError **error)
3204 {
3205         gchar *stmt;
3206         gboolean ret = FALSE;
3207
3208         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
3209         g_return_val_if_fail (folderid != NULL, FALSE);
3210
3211         READER_LOCK (ebsdb);
3212
3213         stmt = sqlite3_mprintf (
3214                 "SELECT is_populated FROM folders WHERE folder_id = %Q",
3215                 folderid);
3216         book_backend_sql_exec (
3217                 ebsdb->priv->db, stmt, get_bool_cb , &ret, error);
3218         sqlite3_free (stmt);
3219
3220         READER_UNLOCK (ebsdb);
3221
3222         return ret;
3223
3224 }
3225
3226 /**
3227  * e_book_backend_sqlitedb_set_is_populated:
3228  *
3229  * FIXME: Document me.
3230  *
3231  * Since: 3.2
3232  **/
3233 gboolean
3234 e_book_backend_sqlitedb_set_is_populated (EBookBackendSqliteDB *ebsdb,
3235                                           const gchar *folderid,
3236                                           gboolean populated,
3237                                           GError **error)
3238 {
3239         gchar *stmt = NULL;
3240         gboolean success;
3241
3242         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
3243         g_return_val_if_fail (folderid != NULL, FALSE);
3244
3245         if (!book_backend_sqlitedb_start_transaction (ebsdb, error))
3246                 return FALSE;
3247
3248         stmt = sqlite3_mprintf (
3249                 "UPDATE folders SET is_populated = %d "
3250                 "WHERE folder_id = %Q", populated, folderid);
3251         success =book_backend_sql_exec (
3252                 ebsdb->priv->db, stmt, NULL, NULL, error);
3253         sqlite3_free (stmt);
3254
3255         if (!success)
3256                 goto rollback;
3257
3258         return book_backend_sqlitedb_commit_transaction (ebsdb, error);
3259
3260 rollback:
3261         /* The GError is already set. */
3262         book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
3263
3264         return FALSE;
3265 }
3266
3267 /**
3268  * e_book_backend_sqlitedb_get_revision:
3269  * @ebsdb: An #EBookBackendSqliteDB
3270  * @folderid: folder id of the address-book
3271  * @revision_out: (out) (transfer full): The location to return the current
3272  * revision
3273  * @error: A location to store any error that may have occurred
3274  *
3275  * Fetches the current revision for the address-book indicated by @folderid.
3276  *
3277  * Upon success, @revision_out will hold the returned revision, otherwise
3278  * %FALSE will be returned and @error will be updated accordingly.
3279  *
3280  * Returns: Whether the revision was successfully fetched.
3281  *
3282  * Since: 3.8
3283  */
3284 gboolean
3285 e_book_backend_sqlitedb_get_revision (EBookBackendSqliteDB *ebsdb,
3286                                       const gchar *folderid,
3287                                       gchar **revision_out,
3288                                       GError **error)
3289 {
3290         gchar *stmt;
3291         gboolean success;
3292
3293         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
3294         g_return_val_if_fail (folderid && folderid[0], FALSE);
3295         g_return_val_if_fail (revision_out != NULL && *revision_out == NULL, FALSE);
3296
3297         READER_LOCK (ebsdb);
3298
3299         stmt = sqlite3_mprintf (
3300                 "SELECT revision FROM folders WHERE folder_id = %Q", folderid);
3301         success = book_backend_sql_exec (
3302                 ebsdb->priv->db, stmt, get_string_cb, &revision_out, error);
3303         sqlite3_free (stmt);
3304
3305         READER_UNLOCK (ebsdb);
3306
3307         return success;
3308 }
3309
3310 /**
3311  * e_book_backend_sqlitedb_set_revision:
3312  * @ebsdb: An #EBookBackendSqliteDB
3313  * @folderid: folder id of the address-book
3314  * @revision: The new revision
3315  * @error: A location to store any error that may have occurred
3316  *
3317  * Sets the current revision for the address-book indicated by @folderid to be @revision.
3318  *
3319  * Returns: Whether the revision was successfully set.
3320  *
3321  * Since: 3.8
3322  */
3323 gboolean
3324 e_book_backend_sqlitedb_set_revision (EBookBackendSqliteDB *ebsdb,
3325                                       const gchar *folderid,
3326                                       const gchar *revision,
3327                                       GError **error)
3328 {
3329         gchar *stmt = NULL;
3330         gboolean success;
3331
3332         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
3333         g_return_val_if_fail (folderid && folderid[0], FALSE);
3334
3335         if (!book_backend_sqlitedb_start_transaction (ebsdb, error))
3336                 return FALSE;
3337
3338         stmt = sqlite3_mprintf (
3339                 "UPDATE folders SET revision = %Q "
3340                 "WHERE folder_id = %Q", revision, folderid);
3341         success = book_backend_sql_exec (
3342                 ebsdb->priv->db, stmt, NULL, NULL, error);
3343         sqlite3_free (stmt);
3344
3345         if (!success)
3346                 goto rollback;
3347
3348         return book_backend_sqlitedb_commit_transaction (ebsdb, error);
3349
3350 rollback:
3351         /* The GError is already set. */
3352         book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
3353
3354         return FALSE;
3355 }
3356
3357 /**
3358  * e_book_backend_sqlitedb_get_has_partial_content 
3359  * @ebsdb: 
3360  * @folderid: 
3361  * @error: 
3362  * 
3363  * 
3364  * Returns: TRUE if the vcards stored in the db were downloaded partially. It is to indicate
3365  * the stored vcards does not contain the full data.
3366  *
3367  * Since: 3.2
3368  **/
3369 gboolean
3370 e_book_backend_sqlitedb_get_has_partial_content (EBookBackendSqliteDB *ebsdb,
3371                                                  const gchar *folderid,
3372                                                  GError **error)
3373 {
3374         gchar *stmt;
3375         gboolean ret = FALSE;
3376
3377         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
3378         g_return_val_if_fail (folderid != NULL, FALSE);
3379
3380         READER_LOCK (ebsdb);
3381
3382         stmt = sqlite3_mprintf (
3383                 "SELECT partial_content FROM folders "
3384                 "WHERE folder_id = %Q", folderid);
3385         book_backend_sql_exec (
3386                 ebsdb->priv->db, stmt, get_bool_cb , &ret, error);
3387         sqlite3_free (stmt);
3388
3389         READER_UNLOCK (ebsdb);
3390
3391         return ret;
3392 }
3393
3394 /**
3395  * e_book_backend_sqlitedb_set_has_partial_content:
3396  *
3397  * FIXME: Document me.
3398  *
3399  * Since: 3.2
3400  **/
3401 gboolean
3402 e_book_backend_sqlitedb_set_has_partial_content (EBookBackendSqliteDB *ebsdb,
3403                                                  const gchar *folderid,
3404                                                  gboolean partial_content,
3405                                                  GError **error)
3406 {
3407         gchar *stmt = NULL;
3408         gboolean success;
3409
3410         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
3411         g_return_val_if_fail (folderid != NULL, FALSE);
3412
3413         if (!book_backend_sqlitedb_start_transaction (ebsdb, error))
3414                 return FALSE;
3415
3416         stmt = sqlite3_mprintf (
3417                 "UPDATE folders SET partial_content = %d "
3418                 "WHERE folder_id = %Q", partial_content, folderid);
3419         success = book_backend_sql_exec (
3420                 ebsdb->priv->db, stmt, NULL, NULL, error);
3421         sqlite3_free (stmt);
3422
3423         if (!success)
3424                 goto rollback;
3425
3426         return book_backend_sqlitedb_commit_transaction (ebsdb, error);
3427
3428 rollback:
3429         /* The GError is already set. */
3430         book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
3431
3432         return FALSE;
3433 }
3434
3435 /**
3436  * e_book_backend_sqlitedb_get_contact_bdata:
3437  *
3438  * FIXME: Document me.
3439  *
3440  * Since: 3.2
3441  **/
3442 gchar *
3443 e_book_backend_sqlitedb_get_contact_bdata (EBookBackendSqliteDB *ebsdb,
3444                                            const gchar *folderid,
3445                                            const gchar *uid,
3446                                            GError **error)
3447 {
3448         gchar *stmt, *ret = NULL;
3449         gboolean success;
3450
3451         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
3452         g_return_val_if_fail (folderid != NULL, NULL);
3453         g_return_val_if_fail (uid != NULL, NULL);
3454
3455         READER_LOCK (ebsdb);
3456
3457         stmt = sqlite3_mprintf (
3458                 "SELECT bdata FROM %Q WHERE uid = %Q", folderid, uid);
3459         success = book_backend_sql_exec (
3460                 ebsdb->priv->db, stmt, get_string_cb , &ret, error);
3461         sqlite3_free (stmt);
3462
3463         READER_UNLOCK (ebsdb);
3464
3465         if (!success) {
3466                 g_warn_if_fail (ret == NULL);
3467                 return NULL;
3468         }
3469
3470         return ret;
3471 }
3472
3473 /**
3474  * e_book_backend_sqlitedb_set_contact_bdata:
3475  *
3476  * FIXME: Document me.
3477  *
3478  * Since: 3.2
3479  **/
3480 gboolean
3481 e_book_backend_sqlitedb_set_contact_bdata (EBookBackendSqliteDB *ebsdb,
3482                                            const gchar *folderid,
3483                                            const gchar *uid,
3484                                            const gchar *value,
3485                                            GError **error)
3486 {
3487         gchar *stmt = NULL;
3488         gboolean success;
3489
3490         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
3491         g_return_val_if_fail (folderid != NULL, FALSE);
3492         g_return_val_if_fail (uid != NULL, FALSE);
3493         g_return_val_if_fail (value != NULL, FALSE);
3494
3495         if (!book_backend_sqlitedb_start_transaction (ebsdb, error))
3496                 return FALSE;
3497
3498         stmt = sqlite3_mprintf (
3499                 "UPDATE %Q SET bdata = %Q WHERE uid = %Q",
3500                 folderid, value, uid);
3501         success = book_backend_sql_exec (
3502                 ebsdb->priv->db, stmt, NULL, NULL, error);
3503         sqlite3_free (stmt);
3504
3505         if (!success)
3506                 goto rollback;
3507
3508         return book_backend_sqlitedb_commit_transaction (ebsdb, error);
3509
3510 rollback:
3511         /* The GError is already set. */
3512         book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
3513
3514         return FALSE;
3515 }
3516
3517 /**
3518  * e_book_backend_sqlitedb_get_sync_data:
3519  *
3520  * FIXME: Document me.
3521  *
3522  * Since: 3.2
3523  **/
3524 gchar *
3525 e_book_backend_sqlitedb_get_sync_data (EBookBackendSqliteDB *ebsdb,
3526                                        const gchar *folderid,
3527                                        GError **error)
3528 {
3529         gchar *stmt, *ret = NULL;
3530
3531         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
3532         g_return_val_if_fail (folderid != NULL, NULL);
3533
3534         READER_LOCK (ebsdb);
3535
3536         stmt = sqlite3_mprintf (
3537                 "SELECT sync_data FROM folders WHERE folder_id = %Q",
3538                 folderid);
3539         book_backend_sql_exec (
3540                 ebsdb->priv->db, stmt, get_string_cb , &ret, error);
3541         sqlite3_free (stmt);
3542
3543         READER_UNLOCK (ebsdb);
3544
3545         return ret;
3546 }
3547
3548 /**
3549  * e_book_backend_sqlitedb_set_sync_data:
3550  *
3551  * FIXME: Document me.
3552  *
3553  * Since: 3.2
3554  **/
3555 gboolean
3556 e_book_backend_sqlitedb_set_sync_data (EBookBackendSqliteDB *ebsdb,
3557                                        const gchar *folderid,
3558                                        const gchar *sync_data,
3559                                        GError **error)
3560 {
3561         gchar *stmt = NULL;
3562         gboolean success;
3563
3564         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
3565         g_return_val_if_fail (folderid != NULL, FALSE);
3566         g_return_val_if_fail (sync_data != NULL, FALSE);
3567
3568         if (!book_backend_sqlitedb_start_transaction (ebsdb, error))
3569                 return FALSE;
3570
3571         stmt = sqlite3_mprintf (
3572                 "UPDATE folders SET sync_data = %Q "
3573                 "WHERE folder_id = %Q", sync_data, folderid);
3574         success = book_backend_sql_exec (
3575                 ebsdb->priv->db, stmt, NULL, NULL, error);
3576         sqlite3_free (stmt);
3577
3578         if (!success)
3579                 goto rollback;
3580
3581         return book_backend_sqlitedb_commit_transaction (ebsdb, error);
3582
3583 rollback:
3584         /* The GError is already set. */
3585         book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
3586
3587         return FALSE;
3588 }
3589
3590 /**
3591  * e_book_backend_sqlitedb_get_key_value:
3592  *
3593  * FIXME: Document me.
3594  *
3595  * Since: 3.2
3596  **/
3597 gchar *
3598 e_book_backend_sqlitedb_get_key_value (EBookBackendSqliteDB *ebsdb,
3599                                        const gchar *folderid,
3600                                        const gchar *key,
3601                                        GError **error)
3602 {
3603         gchar *stmt, *ret = NULL;
3604
3605         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
3606         g_return_val_if_fail (folderid != NULL, NULL);
3607         g_return_val_if_fail (key != NULL, NULL);
3608
3609         READER_LOCK (ebsdb);
3610
3611         stmt = sqlite3_mprintf (
3612                 "SELECT value FROM keys WHERE folder_id = %Q AND key = %Q",
3613                 folderid, key);
3614         book_backend_sql_exec (
3615                 ebsdb->priv->db, stmt, get_string_cb , &ret, error);
3616         sqlite3_free (stmt);
3617
3618         READER_UNLOCK (ebsdb);
3619
3620         return ret;
3621 }
3622
3623 /**
3624  * e_book_backend_sqlitedb_set_key_value:
3625  *
3626  * FIXME: Document me.
3627  *
3628  * Since: 3.2
3629  **/
3630 gboolean
3631 e_book_backend_sqlitedb_set_key_value (EBookBackendSqliteDB *ebsdb,
3632                                        const gchar *folderid,
3633                                        const gchar *key,
3634                                        const gchar *value,
3635                                        GError **error)
3636 {
3637         gchar *stmt = NULL;
3638         gboolean success;
3639
3640         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
3641         g_return_val_if_fail (folderid != NULL, FALSE);
3642         g_return_val_if_fail (key != NULL, FALSE);
3643         g_return_val_if_fail (value != NULL, FALSE);
3644
3645         if (!book_backend_sqlitedb_start_transaction (ebsdb, error))
3646                 return FALSE;
3647
3648         stmt = sqlite3_mprintf (
3649                 "INSERT or REPLACE INTO keys (key, value, folder_id) "
3650                 "values (%Q, %Q, %Q)", key, value, folderid);
3651         success = book_backend_sql_exec (
3652                 ebsdb->priv->db, stmt, NULL, NULL, error);
3653         sqlite3_free (stmt);
3654
3655         if (!success)
3656                 goto rollback;
3657
3658         return book_backend_sqlitedb_commit_transaction (ebsdb, error);
3659
3660 rollback:
3661         /* The GError is already set. */
3662         book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
3663
3664         return FALSE;
3665 }
3666
3667 /**
3668  * e_book_backend_sqlitedb_get_partially_cached_ids:
3669  *
3670  * FIXME: Document me.
3671  *
3672  * Since: 3.2
3673  **/
3674 GSList *
3675 e_book_backend_sqlitedb_get_partially_cached_ids (EBookBackendSqliteDB *ebsdb,
3676                                                   const gchar *folderid,
3677                                                   GError **error)
3678 {
3679         gchar *stmt;
3680         GSList *uids = NULL;
3681
3682         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), NULL);
3683         g_return_val_if_fail (folderid != NULL, NULL);
3684
3685         READER_LOCK (ebsdb);
3686
3687         stmt = sqlite3_mprintf (
3688                 "SELECT uid FROM %Q WHERE partial_content = 1",
3689                 folderid);
3690         book_backend_sql_exec (
3691                 ebsdb->priv->db, stmt, addto_slist_cb, &uids, error);
3692         sqlite3_free (stmt);
3693
3694         READER_UNLOCK (ebsdb);
3695
3696         return uids;
3697 }
3698
3699 /**
3700  * e_book_backend_sqlitedb_delete_addressbook:
3701  *
3702  * FIXME: Document me.
3703  *
3704  * Since: 3.2
3705  **/
3706 gboolean
3707 e_book_backend_sqlitedb_delete_addressbook (EBookBackendSqliteDB *ebsdb,
3708                                             const gchar *folderid,
3709                                             GError **error)
3710 {
3711         gchar *stmt;
3712         gboolean success;
3713
3714         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
3715         g_return_val_if_fail (folderid != NULL, FALSE);
3716
3717         if (!book_backend_sqlitedb_start_transaction (ebsdb, error))
3718                 return FALSE;
3719
3720         /* delete the contacts table */
3721         stmt = sqlite3_mprintf ("DROP TABLE %Q ", folderid);
3722         success = book_backend_sql_exec (
3723                 ebsdb->priv->db, stmt, NULL, NULL, error);
3724         sqlite3_free (stmt);
3725
3726         if (!success)
3727                 goto rollback;
3728
3729         /* delete the key/value pairs corresponding to this table */
3730         stmt = sqlite3_mprintf (
3731                 "DELETE FROM keys WHERE folder_id = %Q", folderid);
3732         success = book_backend_sql_exec (
3733                 ebsdb->priv->db, stmt, NULL, NULL, error);
3734         sqlite3_free (stmt);
3735
3736         if (!success)
3737                 goto rollback;
3738
3739         /* delete the folder from the folders table */
3740         stmt = sqlite3_mprintf (
3741                 "DELETE FROM folders WHERE folder_id = %Q", folderid);
3742         success = book_backend_sql_exec (
3743                 ebsdb->priv->db, stmt, NULL, NULL, error);
3744         sqlite3_free (stmt);
3745
3746         if (!success)
3747                 goto rollback;
3748
3749         return book_backend_sqlitedb_commit_transaction (ebsdb, error);
3750
3751 rollback:
3752         /* The GError is already set. */
3753         book_backend_sqlitedb_rollback_transaction (ebsdb, NULL);
3754
3755         return FALSE;
3756 }
3757
3758 /**
3759  * e_book_backend_sqlitedb_search_data_free:
3760  *
3761  * FIXME: Document me.
3762  *
3763  * Since: 3.2
3764  **/
3765 void
3766 e_book_backend_sqlitedb_search_data_free (EbSdbSearchData *s_data)
3767 {
3768         if (s_data) {
3769                 g_free (s_data->uid);
3770                 g_free (s_data->vcard);
3771                 g_free (s_data->bdata);
3772                 g_slice_free (EbSdbSearchData, s_data);
3773         }
3774 }
3775
3776 /**
3777  * e_book_backend_sqlitedb_remove:
3778  *
3779  * FIXME: Document me.
3780  *
3781  * Since: 3.2
3782  **/
3783 gboolean
3784 e_book_backend_sqlitedb_remove (EBookBackendSqliteDB *ebsdb,
3785                                 GError **error)
3786 {
3787         gchar *filename;
3788         gint ret;
3789
3790         g_return_val_if_fail (E_IS_BOOK_BACKEND_SQLITEDB (ebsdb), FALSE);
3791
3792         WRITER_LOCK (ebsdb);
3793
3794         sqlite3_close (ebsdb->priv->db);
3795
3796         filename = g_build_filename (ebsdb->priv->path, DB_FILENAME, NULL);
3797         ret = g_unlink (filename);
3798         g_free (filename);
3799
3800         WRITER_UNLOCK (ebsdb);
3801
3802         if (ret == -1) {
3803                 g_set_error (
3804                         error, E_BOOK_SDB_ERROR, E_BOOK_SDB_ERROR_OTHER,
3805                         _("Unable to remove the db file: errno %d"), errno);
3806                 return FALSE;
3807         }
3808
3809         return TRUE;
3810 }