Fix FSF address (Tobias Mueller, #470445)
[platform/upstream/evolution-data-server.git] / addressbook / libedata-book / e-book-backend-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: Sivaiah Nallagatla <snallagatla@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-cache.h"
28 #include "e-book-backend-sexp.h"
29
30 struct _EBookBackendCachePrivate {
31         char *uri;
32 };
33
34 /* Property IDs */
35 enum {
36         PROP_0,
37         PROP_URI
38 };
39
40 static GObjectClass *parent_class = NULL;
41
42 static char *
43 get_filename_from_uri (const char *uri)
44 {
45         char *mangled_uri, *filename;
46         int i;
47
48         /* mangle the URI to not contain invalid characters */
49         mangled_uri = g_strdup (uri);
50         for (i = 0; i < strlen (mangled_uri); i++) {
51                 switch (mangled_uri[i]) {
52                 case ':' :
53                 case '/' :
54                         mangled_uri[i] = '_';
55                 }
56         }
57
58         /* generate the file name */
59         filename = g_build_filename (g_get_home_dir (), ".evolution/cache/addressbook",
60                                      mangled_uri, "cache.xml", NULL);
61
62         /* free memory */
63         g_free (mangled_uri);
64
65         return filename;
66 }
67
68 static void
69 e_book_backend_cache_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
70 {
71         EBookBackendCache *cache;
72         EBookBackendCachePrivate *priv;
73         char *cache_file;
74
75         cache = E_BOOK_BACKEND_CACHE (object);
76         priv = cache->priv;
77
78         switch (property_id) {
79         case PROP_URI :
80                 cache_file = get_filename_from_uri (g_value_get_string (value));
81                 if (!cache_file)
82                         break;
83
84                 g_object_set (G_OBJECT (cache), "filename", cache_file, NULL);
85                 g_free (cache_file);
86
87                 if (priv->uri)
88                         g_free (priv->uri);
89                 priv->uri = g_value_dup_string (value);
90                 break;
91         default :
92                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
93         }
94 }
95
96 static void
97 e_book_backend_cache_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
98 {
99         EBookBackendCache *cache;
100         EBookBackendCachePrivate *priv;
101
102         cache = E_BOOK_BACKEND_CACHE (object);
103         priv = cache->priv;
104
105         switch (property_id) {
106         case PROP_URI :
107                 g_value_set_string (value, priv->uri);
108                 break;
109         default :
110                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
111         }
112 }
113
114
115 static void
116 e_book_backend_cache_finalize (GObject *object)
117 {
118         EBookBackendCache *cache;
119         EBookBackendCachePrivate *priv;
120
121         cache = E_BOOK_BACKEND_CACHE (object);
122         priv = cache->priv;
123
124         if (priv) {
125                 if (priv->uri) {
126                         g_free (priv->uri);
127                         priv->uri = NULL;
128                 }
129         
130
131                 g_free (priv);
132                 cache->priv = NULL;
133         }
134
135         parent_class->finalize (object);
136 }
137
138 static GObject *
139 e_book_backend_cache_constructor (GType type,
140                                  guint n_construct_properties,
141                                  GObjectConstructParam *construct_properties)
142 {
143         GObject *obj;
144         const char *uri;
145         char *cache_file;
146
147         /* Invoke parent constructor. */
148         obj = parent_class->constructor (type,
149                                          n_construct_properties,
150                                          construct_properties);
151   
152         /* extract uid */
153         if (!g_ascii_strcasecmp ( g_param_spec_get_name (construct_properties->pspec), "uri")) {
154                 uri = g_value_get_string (construct_properties->value);
155                 cache_file = get_filename_from_uri (uri);
156                 if (cache_file)
157                         g_object_set (obj, "filename", cache_file, NULL);
158                 g_free (cache_file);
159         }
160
161         return obj;
162 }
163
164 static void
165 e_book_backend_cache_class_init (EBookBackendCacheClass *klass)
166 {
167         GObjectClass *object_class;
168
169         parent_class = g_type_class_peek_parent (klass);
170
171         object_class = G_OBJECT_CLASS (klass);
172         object_class->finalize = e_book_backend_cache_finalize;
173         object_class->set_property = e_book_backend_cache_set_property;
174         object_class->get_property = e_book_backend_cache_get_property;
175
176         object_class->constructor = e_book_backend_cache_constructor;
177         g_object_class_install_property (object_class, PROP_URI,
178                                          g_param_spec_string ("uri", NULL, NULL, "",
179                                                               G_PARAM_READABLE | G_PARAM_WRITABLE
180                                                               | G_PARAM_CONSTRUCT_ONLY));
181 }
182
183 static void
184 e_book_backend_cache_init (EBookBackendCache *cache)
185 {
186         EBookBackendCachePrivate *priv;
187
188         priv = g_new0 (EBookBackendCachePrivate, 1);
189
190         cache->priv = priv;
191
192 }
193
194
195 GType
196 e_book_backend_cache_get_type (void)
197 {
198         static GType type = 0;
199
200         if (!type) {
201                 static GTypeInfo info = {
202                         sizeof (EBookBackendCacheClass),
203                         (GBaseInitFunc) NULL,
204                         (GBaseFinalizeFunc) NULL,
205                         (GClassInitFunc) e_book_backend_cache_class_init,
206                         NULL, NULL,
207                         sizeof (EBookBackendCache),
208                         0,
209                         (GInstanceInitFunc) e_book_backend_cache_init,
210                 };
211                 type = g_type_register_static (E_TYPE_FILE_CACHE, "EBookBackendCache", &info, 0);
212         }
213
214         return type;
215 }
216
217 /**
218  * e_book_backend_cache_new
219  * @uri: URI of the backend to be cached.
220  *
221  * Creates a new #EBookBackendCache object, which implements a local
222  * cache of #EContact objects, useful for remote backends.
223  *
224  * Return value: A new #EBookBackendCache.
225  */
226 EBookBackendCache *
227 e_book_backend_cache_new (const char *uri)
228 {
229         EBookBackendCache *cache;
230         
231         cache = g_object_new (E_TYPE_BOOK_BACKEND_CACHE, "uri", uri, NULL);
232
233         return cache;
234 }
235
236 /**
237  * e_book_backend_cache_get_contact:
238  * @cache: an #EBookBackendCache
239  * @uid: a unique contact ID
240  *
241  * Get a cached contact. Note that the returned #EContact will be
242  * newly created, and must be unreffed by the caller when no longer
243  * needed.
244  *
245  * Return value: A cached #EContact, or %NULL if @uid is not cached.
246  **/
247 EContact *
248 e_book_backend_cache_get_contact (EBookBackendCache *cache, const char *uid)
249 {
250         const char *vcard_str;
251         EContact *contact = NULL;
252
253         g_return_val_if_fail (E_IS_BOOK_BACKEND_CACHE (cache), NULL);
254         g_return_val_if_fail (uid != NULL, NULL);
255
256         vcard_str = e_file_cache_get_object (E_FILE_CACHE (cache), uid);
257         if (vcard_str) {
258                 contact = e_contact_new_from_vcard (vcard_str);
259                 
260         }
261
262
263         return contact;
264 }
265
266 /**
267  * e_book_backend_cache_add_contact:
268  * @cache: an #EBookBackendCache
269  * @contact: an #EContact
270  *
271  * Adds @contact to @cache.
272  *
273  * Return value: %TRUE if the contact was cached successfully, %FALSE otherwise.
274  **/
275 gboolean
276 e_book_backend_cache_add_contact (EBookBackendCache *cache,
277                                    EContact *contact)
278 {
279         char *vcard_str;
280         const char *uid;
281         gboolean retval;
282         EBookBackendCachePrivate *priv;
283
284         g_return_val_if_fail (E_IS_BOOK_BACKEND_CACHE (cache), FALSE);
285
286
287         priv = cache->priv;
288
289         uid = e_contact_get_const (contact, E_CONTACT_UID);
290         vcard_str = e_vcard_to_string (E_VCARD(contact), EVC_FORMAT_VCARD_30);
291
292         if (e_file_cache_get_object (E_FILE_CACHE (cache), uid))
293                 retval = e_file_cache_replace_object (E_FILE_CACHE (cache), uid, vcard_str);
294         else
295                 retval = e_file_cache_add_object (E_FILE_CACHE (cache), uid, vcard_str);
296
297         g_free (vcard_str);
298
299         return retval;
300 }
301
302 /**
303  * e_book_backend_cache_remove_contact:
304  * @cache: an #EBookBackendCache
305  * @uid: a unique contact ID
306  *
307  * Removes the contact identified by @uid from @cache.
308  *
309  * Return value: %TRUE if the contact was found and removed, %FALSE otherwise.
310  **/
311 gboolean
312 e_book_backend_cache_remove_contact (EBookBackendCache *cache,
313                                     const char *uid)
314                                       
315 {
316         gboolean retval;
317         EBookBackendCachePrivate *priv;
318
319         g_return_val_if_fail (E_IS_BOOK_BACKEND_CACHE (cache), FALSE);
320         g_return_val_if_fail (uid != NULL, FALSE);
321
322         priv = cache->priv;
323
324
325         if (!e_file_cache_get_object (E_FILE_CACHE (cache), uid)) {
326                 return FALSE;
327         }
328
329         retval = e_file_cache_remove_object (E_FILE_CACHE (cache), uid);
330
331
332         return retval;
333 }
334
335 /**
336  * e_book_backend_cache_check_contact:
337  * @cache: an #EBookBackendCache
338  * @uid: a unique contact ID
339  *
340  * Checks if the contact identified by @uid exists in @cache.
341  *
342  * Return value: %TRUE if the cache contains the contact, %FALSE otherwise.
343  **/
344 gboolean 
345 e_book_backend_cache_check_contact (EBookBackendCache *cache, const char *uid)
346 {
347
348         gboolean retval;
349         EBookBackendCachePrivate *priv;
350
351         g_return_val_if_fail (E_IS_BOOK_BACKEND_CACHE (cache), FALSE);
352         g_return_val_if_fail (uid != NULL, FALSE);
353
354         priv = cache->priv;
355
356         retval = FALSE;
357         if (e_file_cache_get_object (E_FILE_CACHE (cache), uid)) 
358                 retval = TRUE;
359         return retval;
360 }
361
362 /**
363  * e_book_backend_cache_get_contacts:
364  * @cache: an #EBookBackendCache
365  * @query: an s-expression
366  *
367  * Returns a list of #EContact elements from @cache matching @query.
368  * When done with the list, the caller must unref the contacts and
369  * free the list.
370  *
371  * Return value: A #GList of pointers to #EContact.
372  **/
373 GList *
374 e_book_backend_cache_get_contacts (EBookBackendCache *cache, const char *query)
375 {
376         char *vcard_str;
377         GSList *l, *lcache;
378         GList *list = NULL;
379         EContact *contact;
380         EBookBackendSExp *sexp = NULL;
381         const char *uid;
382
383         g_return_val_if_fail (E_IS_BOOK_BACKEND_CACHE (cache), NULL);
384         if (query) {
385                 sexp = e_book_backend_sexp_new (query);
386                 if (!sexp)
387                         return NULL;
388         }
389        
390
391         lcache = l = e_file_cache_get_objects (E_FILE_CACHE (cache));
392
393         for ( ; l != NULL; l = g_slist_next (l)) {
394                 vcard_str = l->data;
395                 if (vcard_str && !strncmp (vcard_str, "BEGIN:VCARD", 11)) {
396                         contact = e_contact_new_from_vcard (vcard_str);
397                         uid = e_contact_get_const (contact, E_CONTACT_UID);
398                         if (contact && uid && *uid &&(query && e_book_backend_sexp_match_contact(sexp, contact)))
399                                 list = g_list_prepend (list, contact);
400                         else
401                                 g_object_unref (contact);
402                 }
403                 
404         }
405         if (lcache)
406                 g_slist_free (lcache);
407         if (sexp)
408                 g_object_unref (sexp);
409
410         return g_list_reverse (list);
411 }
412
413 /**
414  * e_book_backend_cache_search:
415  * @cache: an #EBookBackendCache
416  * @query: an s-expression
417  *
418  * Returns an array of pointers to unique contact ID strings for contacts
419  * in @cache matching @query. When done with the array, the caller must
420  * free the ID strings and the array.
421  *
422  * Return value: A #GPtrArray of pointers to contact ID strings.
423  **/
424 GPtrArray *
425 e_book_backend_cache_search (EBookBackendCache *cache, const char *query)
426 {
427         GList *matching_contacts, *temp;
428         GPtrArray *ptr_array;
429         
430         matching_contacts = e_book_backend_cache_get_contacts (cache, query);
431         ptr_array = g_ptr_array_new ();
432         
433         temp = matching_contacts;
434         for (; matching_contacts != NULL; matching_contacts = g_list_next (matching_contacts)) {
435                 g_ptr_array_add (ptr_array, e_contact_get (matching_contacts->data, E_CONTACT_UID));
436                 g_object_unref (matching_contacts->data);
437         }
438         g_list_free (temp);
439         
440         return ptr_array;
441 }
442
443 /**
444  * e_book_backend_cache_exists:
445  * @uri: URI for the cache
446  *
447  * Checks if an #EBookBackendCache exists at @uri.
448  *
449  * Return value: %TRUE if cache exists, %FALSE if not.
450  **/
451 gboolean 
452 e_book_backend_cache_exists (const char *uri)
453 {
454         char *file_name;
455         gboolean exists = FALSE;
456         file_name = get_filename_from_uri (uri);
457         
458         if (file_name && g_file_test (file_name, G_FILE_TEST_EXISTS)) {
459                 exists = TRUE;
460                 g_free (file_name);
461         }
462         
463         return exists;
464 }
465
466 /**
467  * e_book_backend_cache_set_populated:
468  * @cache: an #EBookBackendCache
469  *
470  * Flags @cache as being populated - that is, it is up-to-date on the 
471  * contents of the book it's caching.
472  **/
473 void
474 e_book_backend_cache_set_populated (EBookBackendCache *cache)
475 {
476         g_return_if_fail (E_IS_BOOK_BACKEND_CACHE (cache));
477         e_file_cache_add_object (E_FILE_CACHE (cache), "populated", "TRUE");
478         
479 }
480
481 /**
482  * e_book_backend_cache_is_populated:
483  * @cache: an #EBookBackendCache
484  *
485  * Checks if @cache is populated.
486  *
487  * Return value: %TRUE if @cache is populated, %FALSE otherwise.
488  **/
489 gboolean
490 e_book_backend_cache_is_populated (EBookBackendCache *cache)
491 {
492         g_return_val_if_fail (E_IS_BOOK_BACKEND_CACHE (cache), FALSE);
493         if (e_file_cache_get_object (E_FILE_CACHE (cache), "populated"))
494                 return TRUE;
495         return FALSE;   
496 }
497
498 void
499 e_book_backend_cache_set_time (EBookBackendCache *cache, const char *t)
500 {
501         g_return_if_fail (E_IS_BOOK_BACKEND_CACHE (cache));
502         e_file_cache_add_object (E_FILE_CACHE (cache), "last_update_time", t);
503 }
504
505 char *
506 e_book_backend_cache_get_time (EBookBackendCache *cache)
507 {
508         g_return_val_if_fail (E_IS_BOOK_BACKEND_CACHE (cache), NULL);
509         return g_strdup (e_file_cache_get_object (E_FILE_CACHE (cache), "last_update_time"));
510 }
511