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