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