Fix FSF address (Tobias Mueller, #470445)
[platform/upstream/evolution-data-server.git] / calendar / libedata-cal / e-cal-backend-cache.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* Evolution calendar - generic backend class
3  *
4  * Copyright (C) 2003 Novell, Inc.
5  *
6  * Authors: Rodrigo Moya <rodrigo@ximian.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 <libecal/e-cal-util.h>
28 #include "e-cal-backend-cache.h"
29
30 struct _ECalBackendCachePrivate {
31         char *uri;
32         ECalSourceType source_type;
33         GHashTable *timezones;
34 };
35
36 /* Property IDs */
37 enum {
38         PROP_0,
39         PROP_SOURCE_TYPE,
40         PROP_URI
41 };
42
43 static GObjectClass *parent_class = NULL;
44
45 static char *
46 get_filename_from_uri (const char *uri, ECalSourceType source_type)
47 {
48         char *mangled_uri, *filename;
49         char *source = NULL;
50         int i;
51
52         switch (source_type) {
53                 case E_CAL_SOURCE_TYPE_EVENT :
54                         source = "calendar";
55                         break;
56                 case E_CAL_SOURCE_TYPE_TODO :
57                         source = "tasks";
58                         break;
59                 case E_CAL_SOURCE_TYPE_JOURNAL :
60                         source = "journal";
61                         break;
62                 case E_CAL_SOURCE_TYPE_LAST :
63                 default :
64                         break;
65         }       
66
67         /* mangle the URI to not contain invalid characters */
68         mangled_uri = g_strdup (uri);
69         for (i = 0; i < strlen (mangled_uri); i++) {
70                 switch (mangled_uri[i]) {
71                 case ':' :
72                 case '/' :
73                         mangled_uri[i] = '_';
74                 }
75         }
76
77         /* generate the file name */
78         filename = g_build_filename (g_get_home_dir (), ".evolution/cache/",
79                                 source, mangled_uri, "cache.xml", NULL);
80
81         /* free memory */
82         g_free (mangled_uri);
83
84         return filename;
85 }
86
87 static void
88 e_cal_backend_cache_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
89 {
90         ECalBackendCache *cache;
91         ECalBackendCachePrivate *priv;
92         char *cache_file;
93         ECalSourceType source_type;
94
95         cache = E_CAL_BACKEND_CACHE (object);
96         priv = cache->priv;
97
98         switch (property_id) {
99         case PROP_SOURCE_TYPE :
100                 source_type = g_value_get_enum (value);
101                 priv->source_type = source_type;
102                 break;
103         case PROP_URI :
104                 /* Ensure both properties are set and then create the
105                  * cache_file property */
106                 cache_file = get_filename_from_uri (g_value_get_string (value), priv->source_type);
107                 if (!cache_file)
108                         break;
109
110                 g_object_set (G_OBJECT (cache), "filename", cache_file, NULL);
111                 g_free (cache_file);
112
113                 if (priv->uri)
114                         g_free (priv->uri);
115                 priv->uri = g_value_dup_string (value);
116                 break;
117         default :
118                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
119         }
120 }
121
122 static void
123 e_cal_backend_cache_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
124 {
125         ECalBackendCache *cache;
126         ECalBackendCachePrivate *priv;
127
128         cache = E_CAL_BACKEND_CACHE (object);
129         priv = cache->priv;
130
131         switch (property_id) {
132         case PROP_SOURCE_TYPE:
133                 g_value_set_enum (value, priv->source_type);    
134         case PROP_URI :
135                 g_value_set_string (value, priv->uri);
136                 break;
137         default :
138                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
139         }
140 }
141
142 static void
143 free_timezone_hash (gpointer key, gpointer value, gpointer user_data)
144 {
145         g_free (key);
146         icaltimezone_free (value, 1);
147 }
148
149 static void
150 e_cal_backend_cache_finalize (GObject *object)
151 {
152         ECalBackendCache *cache;
153         ECalBackendCachePrivate *priv;
154
155         cache = E_CAL_BACKEND_CACHE (object);
156         priv = cache->priv;
157
158         if (priv) {
159                 if (priv->uri) {
160                         g_free (priv->uri);
161                         priv->uri = NULL;
162                 }
163
164                 if (priv->timezones) {
165                         g_hash_table_foreach (priv->timezones, (GHFunc) free_timezone_hash, NULL);
166                         g_hash_table_destroy (priv->timezones);
167                         priv->timezones = NULL;
168                 }
169
170                 g_free (priv);
171                 cache->priv = NULL;
172         }
173
174         parent_class->finalize (object);
175 }
176
177 static GObject *
178 e_cal_backend_cache_constructor (GType type,
179                                  guint n_construct_properties,
180                                  GObjectConstructParam *construct_properties)
181 {
182         GObject *obj;
183         const char *uri;
184         ECalSourceType source_type = E_CAL_SOURCE_TYPE_EVENT;
185         ECalBackendCacheClass *klass;
186         GObjectClass *parent_class;
187
188         /* Invoke parent constructor. */
189         klass = E_CAL_BACKEND_CACHE_CLASS (g_type_class_peek (E_TYPE_CAL_BACKEND_CACHE));
190         parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
191         obj = parent_class->constructor (type,
192                                          n_construct_properties,
193                                          construct_properties);
194
195         if (!g_ascii_strcasecmp ( g_param_spec_get_name (construct_properties->pspec), "source_type")) 
196                 source_type = g_value_get_enum (construct_properties->value);
197         /* extract uid */
198         if (!g_ascii_strcasecmp ( g_param_spec_get_name (construct_properties->pspec), "uri")) {
199                 char *cache_file;
200
201                 uri = g_value_get_string (construct_properties->value);
202                 cache_file = get_filename_from_uri (uri, source_type);
203                 g_object_set (obj, "filename", cache_file, NULL);
204                 g_free (cache_file);
205         }
206
207         return obj;
208 }
209
210 static void
211 e_cal_backend_cache_class_init (ECalBackendCacheClass *klass)
212 {
213         GObjectClass *object_class;
214
215         parent_class = g_type_class_peek_parent (klass);
216
217         object_class = G_OBJECT_CLASS (klass);
218         object_class->finalize = e_cal_backend_cache_finalize;
219         object_class->set_property = e_cal_backend_cache_set_property;
220         object_class->get_property = e_cal_backend_cache_get_property;
221
222         object_class->constructor = e_cal_backend_cache_constructor;
223         g_object_class_install_property (object_class, PROP_SOURCE_TYPE,
224                                          g_param_spec_enum ("source_type", NULL, NULL, 
225                                          e_cal_source_type_enum_get_type (),
226                                          E_CAL_SOURCE_TYPE_EVENT, 
227                                          G_PARAM_READABLE | G_PARAM_WRITABLE
228                                                               | G_PARAM_CONSTRUCT_ONLY));
229
230         g_object_class_install_property (object_class, PROP_URI,
231                                          g_param_spec_string ("uri", NULL, NULL, "",
232                                                               G_PARAM_READABLE | G_PARAM_WRITABLE
233                                                               | G_PARAM_CONSTRUCT_ONLY));
234 }
235
236 static void
237 e_cal_backend_cache_init (ECalBackendCache *cache)
238 {
239         ECalBackendCachePrivate *priv;
240
241         priv = g_new0 (ECalBackendCachePrivate, 1);
242         priv->timezones = g_hash_table_new (g_str_hash, g_str_equal);
243
244         cache->priv = priv;
245
246 }
247
248 /**
249  * e_cal_backend_cache_get_type:
250  * @void:
251  *
252  * Registers the #ECalBackendCache class if necessary, and returns the type ID
253  * associated to it.
254  *
255  * Return value: The type ID of the #ECalBackendCache class.
256  **/
257 GType
258 e_cal_backend_cache_get_type (void)
259 {
260         static GType type = 0;
261         static GStaticMutex registering = G_STATIC_MUTEX_INIT;  
262
263         g_static_mutex_lock (&registering);
264         if (!type) {
265                 static GTypeInfo info = {
266                         sizeof (ECalBackendCacheClass),
267                         (GBaseInitFunc) NULL,
268                         (GBaseFinalizeFunc) NULL,
269                         (GClassInitFunc) e_cal_backend_cache_class_init,
270                         NULL, NULL,
271                         sizeof (ECalBackendCache),
272                         0,
273                         (GInstanceInitFunc) e_cal_backend_cache_init,
274                 };
275                 /* Check if the type is already registered */
276                 if (!(type = g_type_from_name ("ECalBackendCache")))
277                         type = g_type_register_static (E_TYPE_FILE_CACHE, "ECalBackendCache", &info, 0);
278         }
279         g_static_mutex_unlock (&registering);
280
281         return type;
282 }
283
284 /**
285  * e_cal_backend_cache_new
286  * @uri: URI of the backend to be cached.
287  *
288  * Creates a new #ECalBackendCache object, which implements a cache of
289  * calendar/tasks objects, very useful for remote backends.
290  *
291  * Return value: The newly created object.
292  */
293 ECalBackendCache *
294 e_cal_backend_cache_new (const char *uri, ECalSourceType source_type)
295 {
296         ECalBackendCache *cache;
297         
298         cache = g_object_new (E_TYPE_CAL_BACKEND_CACHE, "source_type", source_type, "uri", uri,  NULL);
299
300         return cache;
301 }
302
303 static char *
304 get_key (const char *uid, const char *rid)
305 {
306         GString *real_key;
307         char *retval;
308
309         real_key = g_string_new (uid);
310         if (rid && *rid) {
311                 real_key = g_string_append (real_key, "@");
312                 real_key = g_string_append (real_key, rid);
313         }
314
315         retval = real_key->str;
316         g_string_free (real_key, FALSE);
317
318         return retval;
319 }
320
321 /**
322  * e_cal_backend_cache_get_component:
323  * @cache: A %ECalBackendCache object.
324  * @uid: The UID of the component to retrieve.
325  * @rid: Recurrence ID of the specific detached recurrence to retrieve,
326  * or NULL if the whole object is to be retrieved.
327  *
328  * Gets a component from the %ECalBackendCache object.
329  *
330  * Return value: The %ECalComponent representing the component found,
331  * or %NULL if it was not found in the cache.
332  */
333 ECalComponent *
334 e_cal_backend_cache_get_component (ECalBackendCache *cache, const char *uid, const char *rid)
335 {
336         char *real_key;
337         const char *comp_str;
338         icalcomponent *icalcomp;
339         ECalComponent *comp = NULL;
340
341         g_return_val_if_fail (E_IS_CAL_BACKEND_CACHE (cache), NULL);
342         g_return_val_if_fail (uid != NULL, NULL);
343
344         real_key = get_key (uid, rid);
345
346         comp_str = e_file_cache_get_object (E_FILE_CACHE (cache), real_key);
347         if (comp_str) {
348                 icalcomp = icalparser_parse_string (comp_str);
349                 if (icalcomp) {
350                         comp = e_cal_component_new ();
351                         if (!e_cal_component_set_icalcomponent (comp, icalcomp)) {
352                                 icalcomponent_free (icalcomp);
353                                 g_object_unref (comp);
354                                 comp = NULL;
355                         }
356                 }
357         }
358
359         /* free memory */
360         g_free (real_key);
361
362         return comp;
363 }
364
365 /**
366  * e_cal_backend_cache_put_component:
367  * @cache: An #ECalBackendCache object.
368  * @comp: Component to put on the cache.
369  *
370  * Puts the given calendar component in the given cache. This will add
371  * the component if it does not exist or replace it if there was a
372  * previous version of it.
373  *
374  * Return value: TRUE if the operation was successful, FALSE otherwise.
375  */
376 gboolean
377 e_cal_backend_cache_put_component (ECalBackendCache *cache,
378                                    ECalComponent *comp)
379 {
380         char *real_key, *uid, *comp_str;
381         const char *rid;
382         gboolean retval;
383         ECalBackendCachePrivate *priv;
384
385         g_return_val_if_fail (E_IS_CAL_BACKEND_CACHE (cache), FALSE);
386         g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), FALSE);
387
388         priv = cache->priv;
389
390         e_cal_component_get_uid (comp, (const char **) &uid);
391         if (e_cal_component_is_instance (comp)) {
392                 rid = e_cal_component_get_recurid_as_string (comp);
393         } else
394                 rid = NULL;
395
396         comp_str = e_cal_component_get_as_string (comp);
397         real_key = get_key (uid, rid);
398
399         if (e_file_cache_get_object (E_FILE_CACHE (cache), real_key))
400                 retval = e_file_cache_replace_object (E_FILE_CACHE (cache), real_key, comp_str);
401         else
402                 retval = e_file_cache_add_object (E_FILE_CACHE (cache), real_key, comp_str);
403
404         g_free (real_key);
405         g_free (comp_str);
406
407         return retval;
408 }
409
410 /**
411  * e_cal_backend_cache_remove_component:
412  * @cache: An #ECalBackendCache object.
413  * @uid: UID of the component to remove.
414  * @rid: Recurrence-ID of the component to remove. This is used when removing
415  * detached instances of a recurring appointment.
416  *
417  * Removes a component from the cache.
418  *
419  * Return value: TRUE if the component was removed, FALSE otherwise.
420  */
421 gboolean
422 e_cal_backend_cache_remove_component (ECalBackendCache *cache,
423                                       const char *uid,
424                                       const char *rid)
425 {
426         char *real_key;
427         gboolean retval;
428         ECalBackendCachePrivate *priv;
429
430         g_return_val_if_fail (E_IS_CAL_BACKEND_CACHE (cache), FALSE);
431         g_return_val_if_fail (uid != NULL, FALSE);
432
433         priv = cache->priv;
434
435         real_key = get_key (uid, rid);
436         if (!e_file_cache_get_object (E_FILE_CACHE (cache), real_key)) {
437                 g_free (real_key);
438                 return FALSE;
439         }
440
441         retval = e_file_cache_remove_object (E_FILE_CACHE (cache), real_key);
442         g_free (real_key);
443
444         return retval;
445 }
446
447 /**
448  * e_cal_backend_cache_get_components:
449  * @cache: An #ECalBackendCache object.
450  *
451  * Retrieves a list of all the components stored in the cache.
452  *
453  * Return value: A list of all the components. Each item in the list is
454  * an #ECalComponent, which should be freed when no longer needed.
455  */
456 GList *
457 e_cal_backend_cache_get_components (ECalBackendCache *cache)
458 {
459         char *comp_str;
460         GSList *l;
461         GList *list = NULL;
462         icalcomponent *icalcomp;
463         ECalComponent *comp = NULL;
464         
465         /* return null if cache is not a valid Backend Cache.  */
466         g_return_val_if_fail (E_IS_CAL_BACKEND_CACHE (cache), NULL);
467         l = e_file_cache_get_objects (E_FILE_CACHE (cache));
468         if (!l)
469                 return NULL;
470         for ( ; l != NULL; l = g_slist_next (l)) {
471                 comp_str = l->data;
472                 if (comp_str) {
473                         icalcomp = icalparser_parse_string (comp_str);
474                         if (icalcomp) {
475                                 icalcomponent_kind kind;
476
477                                 kind = icalcomponent_isa (icalcomp);
478                                 if (kind == ICAL_VEVENT_COMPONENT || kind == ICAL_VTODO_COMPONENT || kind == ICAL_VJOURNAL_COMPONENT) {
479                                         comp = e_cal_component_new ();
480                                         if (e_cal_component_set_icalcomponent (comp, icalcomp))
481                                                 list = g_list_prepend (list, comp);
482                                         else {
483                                                 icalcomponent_free (icalcomp);
484                                                 g_object_unref (comp);
485                                         }
486                                 } else
487                                         icalcomponent_free (icalcomp);
488                         }
489                 }
490                 
491         }
492
493         return list;
494 }
495
496 /**
497  * e_cal_backend_cache_get_components_by_uid:
498  * @cache: An #ECalBackendCache object.
499  * @uid: ID of the component to retrieve.
500  *
501  * Retrieves a ical components from the cache.
502  *
503  * Return value: The list of calendar components if found, or NULL otherwise.
504  */
505 GSList *
506 e_cal_backend_cache_get_components_by_uid (ECalBackendCache *cache, const char *uid)
507 {
508         char *comp_str;
509         GSList *l;
510         GSList *list = NULL;
511         icalcomponent *icalcomp;
512         ECalComponent *comp = NULL;
513         
514         /* return null if cache is not a valid Backend Cache.  */
515         g_return_val_if_fail (E_IS_CAL_BACKEND_CACHE (cache), NULL);
516         l = e_file_cache_get_objects (E_FILE_CACHE (cache));
517         if (!l)
518                 return NULL;
519         for ( ; l != NULL; l = g_slist_next (l)) {
520                 comp_str = l->data;
521                 if (comp_str) {
522                         icalcomp = icalparser_parse_string (comp_str);
523                         if (icalcomp) {
524                                 icalcomponent_kind kind;
525
526                                 kind = icalcomponent_isa (icalcomp);
527                                 if (kind == ICAL_VEVENT_COMPONENT || kind == ICAL_VTODO_COMPONENT) {
528                                         comp = e_cal_component_new ();
529                                         if ((e_cal_component_set_icalcomponent (comp, icalcomp)) &&
530                                                 !strcmp (icalcomponent_get_uid (icalcomp), uid)) 
531                                                         list = g_slist_prepend (list, comp);
532                                         else {
533                                                 g_object_unref (comp);
534                                         }
535                                 } else
536                                         icalcomponent_free (icalcomp);
537                         }
538                 }
539                 
540         }
541
542         return list;
543 }
544
545 /**
546  * e_cal_backend_cache_get_timezone:
547  * @cache: An #ECalBackendCache object.
548  * @tzid: ID of the timezone to retrieve.
549  *
550  * Retrieves a timezone component from the cache.
551  *
552  * Return value: The timezone if found, or NULL otherwise.
553  */
554 const icaltimezone *
555 e_cal_backend_cache_get_timezone (ECalBackendCache *cache, const char *tzid)
556 {
557         icaltimezone *zone;
558         const char *comp_str;
559         ECalBackendCachePrivate *priv;
560
561         g_return_val_if_fail (E_IS_CAL_BACKEND_CACHE (cache), NULL);
562         g_return_val_if_fail (tzid != NULL, NULL);
563
564         priv = cache->priv;
565
566         /* we first look for the timezone in the timezones hash table */
567         zone = g_hash_table_lookup (priv->timezones, tzid);
568         if (zone)
569                 return (const icaltimezone *) zone;
570
571         /* if not found look for the timezone in the cache */
572         comp_str = e_file_cache_get_object (E_FILE_CACHE (cache), tzid);
573         if (comp_str) {
574                 icalcomponent *icalcomp;
575
576                 icalcomp = icalparser_parse_string (comp_str);
577                 if (icalcomp) {
578                         zone = icaltimezone_new ();
579                         if (icaltimezone_set_component (zone, icalcomp) == 1)
580                                 g_hash_table_insert (priv->timezones, g_strdup (tzid), zone);
581                         else {
582                                 icalcomponent_free (icalcomp);
583                                 icaltimezone_free (zone, 1);
584                         }
585                 }
586         }
587
588         return (const icaltimezone *) zone;
589 }
590
591 /**
592  * e_cal_backend_cache_put_timezone:
593  * @cache: An #ECalBackendCache object.
594  * @zone: The timezone to put on the cache.
595  *
596  * Puts the given timezone in the cache, adding it, if it did not exist, or
597  * replacing it, if there was an older version.
598  *
599  * Return value: TRUE if the timezone was put on the cache, FALSE otherwise.
600  */
601 gboolean
602 e_cal_backend_cache_put_timezone (ECalBackendCache *cache, const icaltimezone *zone)
603 {
604         ECalBackendCachePrivate *priv;
605         gpointer orig_key, orig_value;
606         icaltimezone *new_zone;
607         icalcomponent *icalcomp;
608         gboolean retval;
609
610         g_return_val_if_fail (E_IS_CAL_BACKEND_CACHE (cache), FALSE);
611         g_return_val_if_fail (zone != NULL, FALSE);
612
613         priv = cache->priv;
614
615         /* add the timezone to the cache file */
616         icalcomp = icaltimezone_get_component ((icaltimezone *)zone);
617         if (!icalcomp)
618                 return FALSE;
619
620         if (e_file_cache_get_object (E_FILE_CACHE (cache), icaltimezone_get_tzid ((icaltimezone *)zone))) {
621                 retval = e_file_cache_replace_object (E_FILE_CACHE (cache),
622                                                       icaltimezone_get_tzid ((icaltimezone *)zone),
623                                                       icalcomponent_as_ical_string (icalcomp));
624         } else {
625                 retval = e_file_cache_add_object (E_FILE_CACHE (cache),
626                                                   icaltimezone_get_tzid ((icaltimezone *)zone),
627                                                   icalcomponent_as_ical_string (icalcomp));
628         }
629
630         if (!retval)
631                 return FALSE;
632
633         /* check if the timezone already exists */
634         if (g_hash_table_lookup_extended (priv->timezones, icaltimezone_get_tzid ((icaltimezone *)zone),
635                                           &orig_key, &orig_value)) {
636                 /* remove the previous timezone */
637                 g_hash_table_remove (priv->timezones, orig_key);
638                 g_free (orig_key);
639                 icaltimezone_free (orig_value, 1);
640         }
641
642         /* add the timezone to the hash table */
643         new_zone = icaltimezone_new ();
644         icaltimezone_set_component (new_zone, icalcomponent_new_clone (icalcomp));
645         g_hash_table_insert (priv->timezones, g_strdup (icaltimezone_get_tzid (new_zone)), new_zone);
646
647         return TRUE;
648 }
649
650 /**
651  * e_cal_backend_cache_put_default_timezone:
652  * @cache: An #ECalBackendCache object.
653  * @default_zone: The default timezone.
654  *
655  * Sets the default timezone on the cache.
656  *
657  * Return value: TRUE if the operation was successful, FALSE otherwise.
658  */
659 gboolean
660 e_cal_backend_cache_put_default_timezone (ECalBackendCache *cache, icaltimezone *default_zone)
661 {
662         ECalBackendCachePrivate *priv;
663         icalcomponent *icalcomp;
664         gboolean retval;
665
666         g_return_val_if_fail (E_IS_CAL_BACKEND_CACHE (cache), FALSE);
667
668         priv = cache->priv;
669
670         /* add the timezone to the cache file */
671         icalcomp = icaltimezone_get_component (default_zone);
672         if (!icalcomp)
673                 return FALSE;
674
675         if (e_file_cache_get_object (E_FILE_CACHE (cache), "default_zone")) {
676                 retval = e_file_cache_replace_object (E_FILE_CACHE (cache), "default_zone",
677                                                       icalcomponent_as_ical_string (icalcomp));
678         } else {
679                 retval = e_file_cache_add_object (E_FILE_CACHE (cache),
680                                                  "default_zone",
681                                                   icalcomponent_as_ical_string (icalcomp));
682         }
683
684         if (!retval)
685                 return FALSE;
686
687         return TRUE;
688
689 }
690
691 /**
692  * e_cal_backend_cache_get_default_timezone:
693  * @cache: An #ECalBackendCache object.
694  *
695  * Retrieves the default timezone from the cache.
696  *
697  * Return value: The default timezone, or NULL if no default timezone
698  * has been set on the cache.
699  */
700 icaltimezone *
701 e_cal_backend_cache_get_default_timezone (ECalBackendCache *cache)
702 {
703         icaltimezone *zone;
704         const char *comp_str;
705         ECalBackendCachePrivate *priv;
706
707         g_return_val_if_fail (E_IS_CAL_BACKEND_CACHE (cache), NULL);
708
709         priv = cache->priv;
710
711         /*  look for the timezone in the cache */
712         comp_str = e_file_cache_get_object (E_FILE_CACHE (cache), "default_zone");
713         if (comp_str) {
714                 icalcomponent *icalcomp;
715
716                 icalcomp = icalparser_parse_string (comp_str);
717                 if (icalcomp) {
718                         zone = icaltimezone_new ();
719                         if (icaltimezone_set_component (zone, icalcomp) == 1) {
720                                 return zone;
721                         } else {
722                                 icalcomponent_free (icalcomp);
723                                 icaltimezone_free (zone, 1);
724                         }
725                 }
726         }
727
728         return NULL;
729 }
730
731 /**
732  * e_cal_backend_cache_remove_timezone:
733  * @cache: An #ECalBackendCache object.
734  * @tzid: ID of the timezone to remove.
735  *
736  * Removes a timezone component from the cache.
737  *
738  * Return value: TRUE if the timezone was removed, FALSE otherwise.
739  */
740 gboolean
741 e_cal_backend_cache_remove_timezone (ECalBackendCache *cache, const char *tzid)
742 {
743         gpointer orig_key, orig_value;
744         ECalBackendCachePrivate *priv;
745
746         g_return_val_if_fail (E_IS_CAL_BACKEND_CACHE (cache), FALSE);
747         g_return_val_if_fail (tzid != NULL, FALSE);
748
749         priv = cache->priv;
750
751         if (g_hash_table_lookup_extended (priv->timezones, tzid, &orig_key, &orig_value)) {
752                 g_hash_table_remove (priv->timezones, tzid);
753                 g_free (orig_key);
754                 icaltimezone_free (orig_value, 1);
755         }
756
757         return e_file_cache_remove_object (E_FILE_CACHE (cache), tzid);
758 }
759
760 /**
761  * e_cal_backend_cache_get_keys:
762  * @cache: An #ECalBackendCache object.
763  *
764  * Gets the list of unique keys in the cache file.
765  *
766  * Return value: A list of all the keys. The items in the list are pointers
767  * to internal data, so should not be freed, only the list should.
768  */
769 GSList *
770 e_cal_backend_cache_get_keys (ECalBackendCache *cache)
771 {
772         g_return_val_if_fail (E_IS_CAL_BACKEND_CACHE (cache), NULL);
773         return e_file_cache_get_keys (E_FILE_CACHE (cache));
774 }
775
776 /**
777  * e_cal_backend_cache_set_marker:
778  * @cache: An #ECalBackendCache object.
779  *
780  * Marks the cache as populated, to discriminate between an empty calendar
781  * and an unpopulated one.
782  */
783 void
784 e_cal_backend_cache_set_marker (ECalBackendCache *cache)
785 {
786         g_return_if_fail (E_IS_CAL_BACKEND_CACHE (cache));
787         e_file_cache_add_object (E_FILE_CACHE (cache), "populated", "TRUE");
788 }
789
790 /**
791  * e_cal_backend_cache_get_marker:
792  * @cache: An #ECalBackendCache object.
793  *
794  * Gets the marker of the cache. If this field is present, it means the
795  * cache has been populated.
796  *
797  * Return value: The value of the marker or NULL if the cache is still empty.
798  */
799 const char *
800 e_cal_backend_cache_get_marker (ECalBackendCache *cache)
801 {
802         g_return_val_if_fail (E_IS_CAL_BACKEND_CACHE (cache), NULL);
803         if (e_file_cache_get_object (E_FILE_CACHE (cache), "populated"))
804                 return "";
805         return NULL;
806 }
807
808 /**
809  * e_cal_backend_cache_put_server_utc_time:
810  * @cache: An #ECalBackendCache object.
811  * @utc_str: UTC string.
812  *
813  * Return value: TRUE if the operation was successful, FALSE otherwise.
814  */
815 gboolean
816 e_cal_backend_cache_put_server_utc_time (ECalBackendCache *cache, const char *utc_str)
817 {
818         gboolean ret_val = FALSE;
819         
820         g_return_val_if_fail (E_IS_CAL_BACKEND_CACHE (cache), FALSE);
821
822         if (!(ret_val = e_file_cache_add_object (E_FILE_CACHE (cache), "server_utc_time", utc_str)))
823                 ret_val = e_file_cache_replace_object (E_FILE_CACHE (cache), "server_utc_time", utc_str);
824
825         return ret_val;
826 }
827
828 /**
829  * e_cal_backend_cache_get_server_utc_time:
830  * @cache: An #ECalBackendCache object.
831  *
832  * Return value: The server's UTC string.
833  */
834 const char *
835 e_cal_backend_cache_get_server_utc_time (ECalBackendCache *cache)
836 {
837
838         g_return_val_if_fail (E_IS_CAL_BACKEND_CACHE (cache), NULL);
839         
840         return  e_file_cache_get_object (E_FILE_CACHE (cache), "server_utc_time");
841 }
842
843 /**
844  * e_cal_backend_cache_put_key_value:
845  * @cache: An #ECalBackendCache object.
846  * @keyp: The Key parameter to identify uniquely.
847  * @valuep: The value for the keyp parameter.
848  *
849  * Return value: TRUE if the operation was successful, FALSE otherwise.
850  */
851 gboolean
852 e_cal_backend_cache_put_key_value (ECalBackendCache *cache, const char *key, const char *value)
853 {
854         gboolean ret_val = FALSE;
855         
856         g_return_val_if_fail (E_IS_CAL_BACKEND_CACHE (cache), FALSE);
857
858         if (value) {
859                 e_file_cache_remove_object (E_FILE_CACHE (cache), key);
860                 return TRUE;
861         }
862         
863         if (!(ret_val = e_file_cache_add_object (E_FILE_CACHE (cache), key, value)))
864                 ret_val = e_file_cache_replace_object (E_FILE_CACHE (cache), key, value);
865
866         return ret_val;
867 }
868
869 /**
870  * e_cal_backend_cache_get_key_value:
871  * @cache: An #ECalBackendCache object.
872  *
873  * Return value: The value.
874  */
875 const char *
876 e_cal_backend_cache_get_key_value (ECalBackendCache *cache, const char *key)
877 {
878
879         g_return_val_if_fail (E_IS_CAL_BACKEND_CACHE (cache), NULL);
880         
881         return  e_file_cache_get_object (E_FILE_CACHE (cache), key);
882 }