Avoid including <db.h> in a public header file.
[platform/upstream/evolution-data-server.git] / addressbook / libedata-book / e-book-backend-db-cache.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* A class to cache address  book conents on local file system
3  *
4  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
5  *
6  * Authors: Devashish Sharma <sdevashish@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 <config.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include <db.h>
27
28 #include "e-book-backend-db-cache.h"
29 #include "e-book-backend.h"
30 #include "e-book-backend-sexp.h"
31
32 static void
33 string_to_dbt (const gchar *str,
34                DBT *dbt)
35 {
36         memset (dbt, 0, sizeof (DBT));
37         dbt->data = (gpointer) str;
38         dbt->size = strlen (str) + 1;
39         dbt->flags = DB_DBT_USERMEM;
40 }
41
42 static gchar *
43 get_filename_from_uri (const gchar *uri)
44 {
45         const gchar *user_cache_dir;
46         gchar *mangled_uri, *filename;
47
48         user_cache_dir = e_get_user_cache_dir ();
49
50         /* Mangle the URI to not contain invalid characters. */
51         mangled_uri = g_strdelimit (g_strdup (uri), ":/", '_');
52
53         filename = g_build_filename (
54                 user_cache_dir, "addressbook",
55                 mangled_uri, "cache.db", NULL);
56
57         g_free (mangled_uri);
58
59         return filename;
60 }
61
62 /**
63  * e_book_backend_db_cache_set_filename:
64  * @db:  DB Handle
65  * @filename: filename to be set
66  *
67  * Set the filename for db cacahe file.
68  **/
69
70 void
71 e_book_backend_db_cache_set_filename (DB *db,
72                                       const gchar *filename)
73 {
74         DBT uid_dbt, vcard_dbt;
75         gint db_error;
76
77         string_to_dbt ("filename", &uid_dbt);
78         string_to_dbt (filename, &vcard_dbt);
79
80         db_error = db->put (db, NULL, &uid_dbt, &vcard_dbt, 0);
81         if (db_error != 0) {
82                 g_warning ("db->put failed with %d", db_error);
83         }
84
85 }
86
87 /**
88  * e_book_backend_db_cache_get_filename:
89  * @db:  DB Handle
90  *
91  * Get the filename for db cacahe file.
92  **/
93
94 gchar *
95 e_book_backend_db_cache_get_filename (DB *db)
96 {
97         DBT  uid_dbt, vcard_dbt;
98         gint db_error;
99         gchar *filename;
100
101         string_to_dbt ("filename", &uid_dbt);
102         memset (&vcard_dbt, 0 , sizeof (vcard_dbt));
103         vcard_dbt.flags = DB_DBT_MALLOC;
104
105         db_error = db->get (db, NULL, &uid_dbt, &vcard_dbt, 0);
106         if (db_error != 0) {
107                 g_warning ("db-<get failed with %d", db_error);
108                 return NULL;
109         }
110         else {
111                 filename = g_strdup (vcard_dbt.data);
112                 g_free (vcard_dbt.data);
113                 return filename;
114         }
115 }
116
117 /**
118  * e_book_backend_db_cache_get_contact:
119  * @db: DB Handle
120  * @uid: a unique contact ID
121  *
122  * Get a cached contact. Note that the returned #EContact will be
123  * newly created, and must be unreffed by the caller when no longer
124  * needed.
125  *
126  * Returns: A cached #EContact, or %NULL if @uid is not cached.
127  **/
128 EContact *
129 e_book_backend_db_cache_get_contact (DB *db,
130                                      const gchar *uid)
131 {
132         DBT     uid_dbt, vcard_dbt;
133         gint    db_error;
134         EContact *contact = NULL;
135
136         g_return_val_if_fail (uid != NULL, NULL);
137
138         string_to_dbt (uid, &uid_dbt);
139         memset (&vcard_dbt, 0 , sizeof (vcard_dbt));
140         vcard_dbt.flags = DB_DBT_MALLOC;
141
142         db_error = db->get (db, NULL, &uid_dbt, &vcard_dbt,0);
143         if (db_error != 0) {
144                 g_warning ("db->get failed with %d", db_error);
145                 return NULL;
146         }
147
148         contact = e_contact_new_from_vcard_with_uid ((const gchar *) vcard_dbt.data, uid);
149         g_free (vcard_dbt.data);
150         return contact;
151 }
152
153 /**
154  * e_book_backend_db_cache_add_contact:
155  * @db: DB Handle
156  * @contact: an #EContact
157  *
158  * Adds @contact to @cache.
159  *
160  * Returns: %TRUE if the contact was cached successfully, %FALSE otherwise.
161  **/
162 gboolean
163 e_book_backend_db_cache_add_contact (DB *db,
164                                      EContact *contact)
165 {
166         DBT     uid_dbt, vcard_dbt;
167         gint    db_error;
168         gchar   *vcard_str;
169         const gchar *uid;
170
171         uid = e_contact_get_const (contact, E_CONTACT_UID);
172         if (!uid) {
173                 printf ("no uid\n");
174                 printf("name:%s, email:%s\n",
175                         (gchar *) e_contact_get (contact, E_CONTACT_GIVEN_NAME),
176                         (gchar *) e_contact_get (contact, E_CONTACT_EMAIL_1));
177                 return FALSE;
178         }
179         string_to_dbt (uid, &uid_dbt);
180
181         vcard_str = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
182         string_to_dbt (vcard_str, &vcard_dbt);
183
184         /* db_error = db->del (db, NULL, &uid_dbt, 0); */
185         db_error = db->put (db, NULL, &uid_dbt, &vcard_dbt, 0);
186
187         g_free (vcard_str);
188
189         if (db_error != 0) {
190                 g_warning ("db->put failed with %d", db_error);
191                 return FALSE;
192         }
193         else
194                 return TRUE;
195 }
196
197 /**
198  * e_book_backend_db_cache_remove_contact:
199  * @db: DB Handle
200  * @uid: a unique contact ID
201  *
202  * Removes the contact identified by @uid from @cache.
203  *
204  * Returns: %TRUE if the contact was found and removed, %FALSE otherwise.
205  **/
206 gboolean
207 e_book_backend_db_cache_remove_contact (DB *db,
208                                         const gchar *uid)
209
210 {
211         DBT     uid_dbt;
212         gint    db_error;
213
214         g_return_val_if_fail (uid != NULL, FALSE);
215
216         string_to_dbt (uid, &uid_dbt);
217         db_error = db->del (db, NULL, &uid_dbt, 0);
218
219         if (db_error != 0) {
220                 g_warning ("db->del failed with %d", db_error);
221                 return FALSE;
222         }
223         else
224                 return TRUE;
225
226 }
227
228 /**
229  * e_book_backend_db_cache_check_contact:
230  * @db: DB Handle
231  * @uid: a unique contact ID
232  *
233  * Checks if the contact identified by @uid exists in @cache.
234  *
235  * Returns: %TRUE if the cache contains the contact, %FALSE otherwise.
236  **/
237 gboolean
238 e_book_backend_db_cache_check_contact (DB *db,
239                                        const gchar *uid)
240 {
241         DBT     uid_dbt, vcard_dbt;
242         gint    db_error;
243
244         g_return_val_if_fail (uid != NULL, FALSE);
245
246         string_to_dbt (uid, &uid_dbt);
247         memset (&vcard_dbt, 0 , sizeof (vcard_dbt));
248         vcard_dbt.flags = DB_DBT_MALLOC;
249
250         db_error = db->get (db, NULL, &uid_dbt, &vcard_dbt,0);
251         if (db_error != 0)
252                 return FALSE;
253         else {
254                 free (vcard_dbt.data);
255                 return TRUE;
256         }
257 }
258
259 /**
260  * e_book_backend_db_cache_get_contacts:
261  * @db: DB Handle
262  * @query: an s-expression
263  *
264  * Returns a list of #EContact elements from @cache matching @query.
265  * When done with the list, the caller must unref the contacts and
266  * free the list.
267  *
268  * Returns: A #GList of pointers to #EContact.
269  **/
270 GList *
271 e_book_backend_db_cache_get_contacts (DB *db,
272                                       const gchar *query)
273 {
274         DBC     *dbc;
275         DBT     uid_dbt, vcard_dbt;
276         gint    db_error;
277         GList *list = NULL;
278         EBookBackendSExp *sexp = NULL;
279         EContact *contact;
280
281         if (query) {
282                 sexp = e_book_backend_sexp_new (query);
283                 if (!sexp)
284                         return NULL;
285         }
286
287         db_error = db->cursor (db, NULL, &dbc, 0);
288         if (db_error != 0) {
289                 g_warning ("db->cursor failed with %d", db_error);
290                 if (sexp)
291                         g_object_unref (sexp);
292                 return NULL;
293         }
294
295         memset (&vcard_dbt, 0 , sizeof (vcard_dbt));
296         memset (&uid_dbt, 0, sizeof (uid_dbt));
297         db_error = dbc->c_get (dbc, &uid_dbt, &vcard_dbt, DB_FIRST);
298
299         while (db_error == 0) {
300                 if (vcard_dbt.data && !strncmp (vcard_dbt.data, "BEGIN:VCARD", 11)) {
301                         contact = e_contact_new_from_vcard (vcard_dbt.data);
302
303                         if (!sexp || e_book_backend_sexp_match_contact (sexp, contact))
304                                 list = g_list_prepend (list, contact);
305                         else
306                                 g_object_unref (contact);
307                 }
308                 db_error = dbc->c_get (dbc, &uid_dbt, &vcard_dbt, DB_NEXT);
309         }
310
311         db_error = dbc->c_close (dbc);
312         if (db_error != 0)
313                 g_warning ("db->c_close failed with %d", db_error);
314
315         if (sexp)
316                 g_object_unref (sexp);
317
318         return g_list_reverse (list);
319 }
320
321 /**
322  * e_book_backend_db_cache_search:
323  * @db: DB handle
324  * @query: an s-expression
325  *
326  * Returns an array of pointers to unique contact ID strings for contacts
327  * in @cache matching @query. When done with the array, the caller must
328  * free the ID strings and the array.
329  *
330  * Returns: A #GPtrArray of pointers to contact ID strings.
331  **/
332 GPtrArray *
333 e_book_backend_db_cache_search (DB *db,
334                                 const gchar *query)
335 {
336         GList *matching_contacts, *temp;
337         GPtrArray *ptr_array;
338
339         matching_contacts = e_book_backend_db_cache_get_contacts (db, query);
340         ptr_array = g_ptr_array_new ();
341
342         temp = matching_contacts;
343         for (; matching_contacts != NULL; matching_contacts = g_list_next (matching_contacts)) {
344                 g_ptr_array_add (ptr_array, e_contact_get (matching_contacts->data, E_CONTACT_UID));
345                 g_object_unref (matching_contacts->data);
346         }
347         g_list_free (temp);
348
349         return ptr_array;
350 }
351
352 /**
353  * e_book_backend_db_cache_exists:
354  * @uri: URI for the cache
355  *
356  * Checks if an #EBookBackendCache exists at @uri.
357  *
358  * Returns: %TRUE if cache exists, %FALSE if not.
359  **/
360 gboolean
361 e_book_backend_db_cache_exists (const gchar *uri)
362 {
363         gchar *file_name;
364         gboolean exists = FALSE;
365         file_name = get_filename_from_uri (uri);
366
367         if (file_name && g_file_test (file_name, G_FILE_TEST_EXISTS))
368                 exists = TRUE;
369
370         g_free (file_name);
371
372         return exists;
373 }
374
375 /**
376  * e_book_backend_db_cache_set_populated:
377  * @db: DB handle
378  *
379  * Flags @cache as being populated - that is, it is up-to-date on the
380  * contents of the book it's caching.
381  **/
382 void
383 e_book_backend_db_cache_set_populated (DB *db)
384 {
385         DBT     uid_dbt, vcard_dbt;
386         gint    db_error;
387
388         string_to_dbt ("populated", &uid_dbt);
389         string_to_dbt ("TRUE", &vcard_dbt);
390         db_error = db->put (db, NULL, &uid_dbt, &vcard_dbt, 0);
391         if (db_error != 0) {
392                 g_warning ("db->put failed with %d", db_error);
393         }
394
395 }
396
397 /**
398  * e_book_backend_cache_is_populated:
399  * @db: DB Handle
400  *
401  * Checks if @cache is populated.
402  *
403  * Returns: %TRUE if @cache is populated, %FALSE otherwise.
404  **/
405 gboolean
406 e_book_backend_db_cache_is_populated (DB *db)
407 {
408         DBT     uid_dbt, vcard_dbt;
409         gint    db_error;
410
411         string_to_dbt ("populated", &uid_dbt);
412         memset (&vcard_dbt, 0, sizeof (vcard_dbt));
413         vcard_dbt.flags = DB_DBT_MALLOC;
414
415         db_error = db->get (db, NULL, &uid_dbt, &vcard_dbt, 0);
416         if (db_error != 0) {
417                 return FALSE;
418         }
419         else {
420                 free (vcard_dbt.data);
421                 return TRUE;
422         }
423 }
424
425 /**
426  * e_book_backend_db_cache_set_time:
427  *
428  * Since: 2.26
429  **/
430 void
431 e_book_backend_db_cache_set_time (DB *db,
432                                   const gchar *t)
433 {
434         DBT uid_dbt, vcard_dbt;
435         gint db_error;
436
437         string_to_dbt ("last_update_time", &uid_dbt);
438         string_to_dbt (t, &vcard_dbt);
439
440         db_error = db->put (db, NULL, &uid_dbt, &vcard_dbt, 0);
441         if (db_error != 0) {
442                 g_warning ("db->put failed with %d", db_error);
443         }
444 }
445
446 /**
447  * e_book_backend_db_cache_get_time:
448  *
449  * Since: 2.26
450  **/
451 gchar *
452 e_book_backend_db_cache_get_time (DB *db)
453 {
454         DBT uid_dbt, vcard_dbt;
455         gint db_error;
456         gchar *t = NULL;
457
458         string_to_dbt ("last_update_time", &uid_dbt);
459         memset (&vcard_dbt, 0, sizeof (vcard_dbt));
460         vcard_dbt.flags = DB_DBT_MALLOC;
461
462         db_error = db->get (db, NULL, &uid_dbt, &vcard_dbt, 0);
463         if (db_error != 0) {
464                 g_warning ("db->get failed with %d", db_error);
465         } else {
466                 t = g_strdup (vcard_dbt.data);
467                 free (vcard_dbt.data);
468         }
469
470         return t;
471 }