--- /dev/null
+/*-*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* e-cal-backend-file-store.c
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ * Authors: Chenthill Palanisamy <pchenthill@novell.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <string.h>
+#include "e-cal-backend-file-store.h"
+#include "libebackend/e-file-cache.h"
+#include <glib/gstdio.h>
+
+#define CACHE_FILE_NAME "calendar.ics"
+#define KEY_FILE_NAME "keys.xml"
+#define IDLE_SAVE_TIMEOUT 6000
+
+G_DEFINE_TYPE (ECalBackendFileStore, e_cal_backend_file_store, E_TYPE_CAL_BACKEND_STORE)
+
+#define GET_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), E_TYPE_CAL_BACKEND_FILE_STORE, ECalBackendFileStorePrivate))
+
+typedef struct _ECalBackendFileStorePrivate ECalBackendFileStorePrivate;
+
+typedef struct {
+ ECalComponent *comp;
+ GHashTable *recurrences;
+} FullCompObject;
+
+struct _ECalBackendFileStorePrivate {
+ GHashTable *timezones;
+ GHashTable *comp_uid_hash;
+ EFileCache *keys_cache;
+
+ GStaticRWLock lock;
+
+ gchar *cache_file_name;
+ gchar *key_file_name;
+
+ gboolean dirty;
+ gboolean freeze_changes;
+
+ guint save_timeout_id;
+};
+
+static void save_cache (ECalBackendFileStore *store);
+
+
+static FullCompObject *
+create_new_full_object (void)
+{
+ FullCompObject *obj;
+
+ obj = g_new0 (FullCompObject, 1);
+ obj->recurrences = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+
+ return obj;
+}
+
+static void
+destroy_full_object (FullCompObject *obj)
+{
+ if (!obj)
+ return;
+
+ if (obj->comp)
+ g_object_unref (obj->comp);
+ g_hash_table_destroy (obj->recurrences);
+
+ g_free (obj);
+ obj = NULL;
+}
+
+static gboolean
+put_component (ECalBackendFileStore *fstore, ECalComponent *comp)
+{
+ ECalBackendFileStorePrivate *priv;
+ FullCompObject *obj = NULL;
+ const gchar *uid;
+
+ g_return_val_if_fail (comp != NULL, FALSE);
+
+ priv = GET_PRIVATE (fstore);
+ e_cal_component_get_uid (comp, &uid);
+
+ if (uid == NULL) {
+ g_warning ("The component does not have a valid uid \n");
+ return FALSE;
+ }
+
+ g_static_rw_lock_writer_lock (&priv->lock);
+
+ obj = g_hash_table_lookup (priv->comp_uid_hash, uid);
+
+ if (obj == NULL) {
+ obj = create_new_full_object ();
+ }
+
+ if (!e_cal_component_is_instance (comp)) {
+ if (obj->comp != NULL)
+ g_object_unref (obj->comp);
+
+ obj->comp = comp;
+ g_hash_table_insert (priv->comp_uid_hash, g_strdup (uid), obj);
+ } else {
+ gchar *rid = e_cal_component_get_recurid_as_string (comp);
+
+ g_hash_table_insert (obj->recurrences, g_strdup (rid), comp);
+ }
+
+ g_static_rw_lock_writer_unlock (&priv->lock);
+
+ return TRUE;
+}
+
+static gboolean
+remove_component (ECalBackendFileStore *fstore, const gchar *uid, const gchar *rid)
+{
+ ECalBackendFileStorePrivate *priv;
+ FullCompObject *obj = NULL;
+ gboolean ret_val = TRUE;
+ gboolean remove_completely = FALSE;
+
+ priv = GET_PRIVATE (fstore);
+
+ g_static_rw_lock_writer_lock (&priv->lock);
+
+ obj = g_hash_table_lookup (priv->comp_uid_hash, uid);
+ if (obj == NULL) {
+ ret_val = FALSE;
+ goto end;
+ }
+
+ if (rid != NULL) {
+ ret_val = g_hash_table_remove (obj->recurrences, rid);
+
+ if (ret_val && g_hash_table_size (obj->recurrences) == 0 && !obj->comp)
+ remove_completely = TRUE;
+ } else
+ remove_completely = TRUE;
+
+ if (remove_completely)
+ destroy_full_object (obj);
+
+end:
+ g_static_rw_lock_writer_unlock (&priv->lock);
+ return ret_val;
+}
+
+static ECalComponent *
+get_component (ECalBackendFileStore *fstore, const gchar *uid, const gchar *rid)
+{
+ ECalBackendFileStorePrivate *priv;
+ FullCompObject *obj = NULL;
+ ECalComponent *comp = NULL;
+
+ priv = GET_PRIVATE(fstore);
+
+ g_static_rw_lock_reader_lock (&priv->lock);
+
+ obj = g_hash_table_lookup (priv->comp_uid_hash, uid);
+ if (obj == NULL)
+ goto end;
+
+ if (rid != NULL)
+ comp = g_hash_table_lookup (obj->recurrences, rid);
+ else
+ comp = obj->comp;
+
+ if (comp != NULL)
+ g_object_ref (comp);
+
+end:
+ g_static_rw_lock_reader_unlock (&priv->lock);
+ return comp;
+}
+
+static ECalComponent *
+e_cal_backend_file_store_get_component (ECalBackendStore *store, const gchar *uid, const gchar *rid)
+{
+ ECalBackendFileStore *fstore = E_CAL_BACKEND_FILE_STORE (store);
+ ECalBackendFileStorePrivate *priv;
+
+ priv = GET_PRIVATE (fstore);
+
+ return get_component (fstore, uid, rid);
+}
+
+static gboolean
+e_cal_backend_file_store_put_component (ECalBackendStore *store, ECalComponent *comp)
+{
+ ECalBackendFileStore *fstore = E_CAL_BACKEND_FILE_STORE (store);
+ ECalBackendFileStorePrivate *priv;
+ gboolean ret_val = FALSE;
+
+ priv = GET_PRIVATE (fstore);
+
+ ret_val = put_component (fstore, comp);
+
+ if (ret_val) {
+ priv->dirty = TRUE;
+
+ if (!priv->freeze_changes)
+ save_cache (fstore);
+ }
+
+ return ret_val;
+}
+
+static gboolean
+e_cal_backend_file_store_remove_component (ECalBackendStore *store, const gchar *uid, const gchar *rid)
+{
+ ECalBackendFileStore *fstore = E_CAL_BACKEND_FILE_STORE (store);
+ ECalBackendFileStorePrivate *priv;
+ gboolean ret_val = FALSE;
+
+ priv = GET_PRIVATE (fstore);
+
+ ret_val = remove_component (fstore, uid, rid);
+
+ if (ret_val) {
+ priv->dirty = TRUE;
+
+ if (!priv->freeze_changes)
+ save_cache (fstore);
+ }
+
+ return ret_val;
+}
+
+static const icaltimezone *
+e_cal_backend_file_store_get_timezone (ECalBackendStore *store, const gchar *tzid)
+{
+ ECalBackendFileStore *fstore = E_CAL_BACKEND_FILE_STORE (store);
+ ECalBackendFileStorePrivate *priv;
+ const icaltimezone *zone = NULL;
+
+ priv = GET_PRIVATE (fstore);
+
+ g_static_rw_lock_reader_lock (&priv->lock);
+ zone = g_hash_table_lookup (priv->timezones, tzid);
+ g_static_rw_lock_reader_unlock (&priv->lock);
+
+ return zone;
+}
+
+static gboolean
+e_cal_backend_file_store_put_timezone (ECalBackendStore *store, const icaltimezone *zone)
+{
+ ECalBackendFileStore *fstore = E_CAL_BACKEND_FILE_STORE (store);
+ ECalBackendFileStorePrivate *priv;
+ gboolean ret_val = FALSE;
+
+ priv = GET_PRIVATE (fstore);
+
+ g_static_rw_lock_writer_lock (&priv->lock);
+ g_hash_table_insert (priv->timezones, g_strdup (icaltimezone_get_tzid ((icaltimezone *) zone)), (icaltimezone *) zone);
+ g_static_rw_lock_writer_unlock (&priv->lock);
+
+ if (ret_val) {
+ priv->dirty = TRUE;
+
+ if (!priv->freeze_changes)
+ save_cache (fstore);
+ }
+
+ return ret_val;
+}
+
+static gboolean
+e_cal_backend_file_store_remove_timezone (ECalBackendStore *store, const gchar *tzid)
+{
+ ECalBackendFileStore *fstore = E_CAL_BACKEND_FILE_STORE (store);
+ ECalBackendFileStorePrivate *priv;
+ gboolean ret_val = FALSE;
+
+ priv = GET_PRIVATE (fstore);
+
+ g_static_rw_lock_writer_lock (&priv->lock);
+ ret_val = g_hash_table_remove (priv->timezones, tzid);
+ g_static_rw_lock_writer_unlock (&priv->lock);
+
+ if (ret_val) {
+ priv->dirty = TRUE;
+
+ if (!priv->freeze_changes)
+ save_cache (fstore);
+ }
+
+ return ret_val;
+}
+
+static const gchar *
+e_cal_backend_file_store_get_key_value (ECalBackendStore *store, const gchar *key)
+{
+ ECalBackendFileStore *fstore = E_CAL_BACKEND_FILE_STORE (store);
+ ECalBackendFileStorePrivate *priv;
+ const gchar *value;
+
+ priv = GET_PRIVATE (fstore);
+
+ g_static_rw_lock_reader_lock (&priv->lock);
+ value = e_file_cache_get_object (priv->keys_cache, key);
+ g_static_rw_lock_reader_unlock (&priv->lock);
+
+ return value;
+}
+
+static gboolean
+e_cal_backend_file_store_put_key_value (ECalBackendStore *store, const gchar *key, const gchar *value)
+{
+ ECalBackendFileStore *fstore = E_CAL_BACKEND_FILE_STORE (store);
+ ECalBackendFileStorePrivate *priv;
+ gboolean ret_val = FALSE;
+
+ priv = GET_PRIVATE (fstore);
+
+ g_static_rw_lock_writer_lock (&priv->lock);
+ ret_val = e_file_cache_replace_object (priv->keys_cache, key, value);
+ g_static_rw_lock_writer_unlock (&priv->lock);
+
+ return ret_val;
+}
+
+static const icaltimezone *
+e_cal_backend_file_store_get_default_timezone (ECalBackendStore *store)
+{
+ ECalBackendFileStore *fstore = E_CAL_BACKEND_FILE_STORE (store);
+ ECalBackendFileStorePrivate *priv;
+ const gchar *tzid;
+ const icaltimezone *zone = NULL;
+
+ priv = GET_PRIVATE (fstore);
+
+ g_static_rw_lock_reader_lock (&priv->lock);
+
+ tzid = e_file_cache_get_object (priv->keys_cache, "default-zone");
+ if (tzid)
+ zone = g_hash_table_lookup (priv->timezones, tzid);
+
+ g_static_rw_lock_reader_unlock (&priv->lock);
+
+ return zone;
+}
+
+static gboolean
+e_cal_backend_file_store_set_default_timezone (ECalBackendStore *store, const icaltimezone *zone)
+{
+ ECalBackendFileStore *fstore = E_CAL_BACKEND_FILE_STORE (store);
+ ECalBackendFileStorePrivate *priv;
+ const gchar *tzid;
+
+ priv = GET_PRIVATE (fstore);
+
+ g_static_rw_lock_writer_lock (&priv->lock);
+
+ tzid = icaltimezone_get_tzid ((icaltimezone*) zone);
+ g_hash_table_insert (priv->timezones, g_strdup (tzid), (icaltimezone *) zone);
+ e_file_cache_replace_object (priv->keys_cache, "default-zone", tzid);
+
+ g_static_rw_lock_writer_unlock (&priv->lock);
+
+ return TRUE;
+}
+
+static void
+e_cal_backend_file_store_thaw_changes (ECalBackendStore *store)
+{
+ ECalBackendFileStore *fstore = E_CAL_BACKEND_FILE_STORE (store);
+ ECalBackendFileStorePrivate *priv;
+
+ priv = GET_PRIVATE (fstore);
+
+ priv->freeze_changes = FALSE;
+
+ e_file_cache_thaw_changes (priv->keys_cache);
+ if (priv->dirty) {
+ save_cache (fstore);
+ }
+}
+
+static void
+e_cal_backend_file_store_freeze_changes (ECalBackendStore *store)
+{
+ ECalBackendFileStore *fstore = E_CAL_BACKEND_FILE_STORE (store);
+ ECalBackendFileStorePrivate *priv;
+
+ priv = GET_PRIVATE (fstore);
+
+ priv->freeze_changes = TRUE;
+ e_file_cache_freeze_changes (priv->keys_cache);
+}
+
+static void
+add_comp_to_slist (gpointer key, gpointer value, gpointer user_data)
+{
+ GSList **slist = (GSList **) user_data;
+ ECalComponent *comp = (ECalComponent *) value;
+
+ g_object_ref (comp);
+ *slist = g_slist_prepend (*slist, comp);
+}
+
+static GSList *
+e_cal_backend_file_store_get_components_by_uid (ECalBackendStore *store, const gchar *uid)
+{
+ ECalBackendFileStore *fstore = E_CAL_BACKEND_FILE_STORE (store);
+ ECalBackendFileStorePrivate *priv;
+ FullCompObject *obj = NULL;
+ GSList *comps = NULL;
+
+ priv = GET_PRIVATE (fstore);
+
+ g_static_rw_lock_reader_lock (&priv->lock);
+
+ obj = g_hash_table_lookup (priv->comp_uid_hash, uid);
+ if (obj == NULL) {
+ goto end;
+ }
+
+ if (obj->comp) {
+ g_object_ref (obj->comp);
+ comps = g_slist_append (comps, obj->comp);
+ }
+
+ g_hash_table_foreach (obj->recurrences, (GHFunc) add_comp_to_slist, &comps);
+end:
+ g_static_rw_lock_reader_unlock (&priv->lock);
+ return comps;
+}
+
+static void
+add_timezone (ECalBackendFileStore *fstore, icalcomponent *vtzcomp)
+{
+ ECalBackendFileStorePrivate *priv;
+ icalproperty *prop;
+ icaltimezone *zone;
+ const char *tzid;
+
+ prop = icalcomponent_get_first_property (vtzcomp, ICAL_TZID_PROPERTY);
+ if (!prop)
+ return;
+
+ tzid = icalproperty_get_tzid (prop);
+ if (g_hash_table_lookup (priv->timezones, tzid))
+ return;
+
+ zone = icaltimezone_new ();
+ if (!icaltimezone_set_component (zone, icalcomponent_new_clone (vtzcomp))) {
+ icaltimezone_free (zone, TRUE);
+ return;
+ }
+
+ g_static_rw_lock_writer_lock (&priv->lock);
+ g_hash_table_insert (priv->timezones, g_strdup (tzid), zone);
+ g_static_rw_lock_writer_unlock (&priv->lock);
+}
+
+static void
+scan_vcalendar (ECalBackendFileStore *fstore, icalcomponent *top_icalcomp)
+{
+ ECalBackendFileStorePrivate *priv;
+ icalcompiter iter;
+
+ priv = GET_PRIVATE(fstore);
+
+ for (iter = icalcomponent_begin_component (top_icalcomp, ICAL_ANY_COMPONENT);
+ icalcompiter_deref (&iter) != NULL;
+ icalcompiter_next (&iter)) {
+ icalcomponent *icalcomp;
+ icalcomponent_kind kind;
+ ECalComponent *comp;
+
+ icalcomp = icalcompiter_deref (&iter);
+
+ kind = icalcomponent_isa (icalcomp);
+
+ if (!(kind == ICAL_VEVENT_COMPONENT
+ || kind == ICAL_VTODO_COMPONENT
+ || kind == ICAL_VJOURNAL_COMPONENT
+ || kind == ICAL_VTIMEZONE_COMPONENT))
+ continue;
+
+ if (kind == ICAL_VTIMEZONE_COMPONENT) {
+ add_timezone (fstore, icalcomp);
+ continue;
+ }
+
+ comp = e_cal_component_new ();
+
+ if (!e_cal_component_set_icalcomponent (comp, icalcomp))
+ continue;
+
+ put_component (fstore, comp);
+ }
+}
+
+static gboolean
+e_cal_backend_file_store_load (ECalBackendStore *store)
+{
+ ECalBackendFileStore *fstore = E_CAL_BACKEND_FILE_STORE (store);
+ ECalBackendFileStorePrivate *priv;
+ icalcomponent *icalcomp;
+
+ priv = GET_PRIVATE(fstore);
+
+ if (!priv->cache_file_name || !priv->key_file_name)
+ return FALSE;
+
+ /* Parse keys */
+ priv->keys_cache = e_file_cache_new (priv->key_file_name);
+
+ /* Parse components */
+ icalcomp = e_cal_util_parse_ics_file (priv->cache_file_name);
+ if (!icalcomp)
+ return FALSE;
+
+ if (icalcomponent_isa (icalcomp) != ICAL_VCALENDAR_COMPONENT) {
+ icalcomponent_free (icalcomp);
+
+ return FALSE;
+ }
+
+ scan_vcalendar (fstore, icalcomp);
+
+ return TRUE;
+}
+
+static void
+save_instance (gpointer key, gpointer value, gpointer user_data)
+{
+ icalcomponent *vcalcomp = user_data;
+ icalcomponent *icalcomp;
+ ECalComponent *comp = value;
+
+ icalcomp = icalcomponent_new_clone (e_cal_component_get_icalcomponent (comp));
+ icalcomponent_add_component (vcalcomp, icalcomp);
+}
+
+static void
+save_object (gpointer key, gpointer value, gpointer user_data)
+{
+ FullCompObject *obj = value;
+ icalcomponent *icalcomp, *vcalcomp = user_data;
+
+ if (obj->comp) {
+ icalcomp = icalcomponent_new_clone (e_cal_component_get_icalcomponent (obj->comp));
+ icalcomponent_add_component (vcalcomp, icalcomp);
+ }
+
+ g_hash_table_foreach (obj->recurrences, save_instance, vcalcomp);
+}
+
+static void
+save_timezone (gpointer key, gpointer tz, gpointer vcalcomp)
+{
+ icalcomponent *tzcomp;
+
+ tzcomp = icalcomponent_new_clone (icaltimezone_get_component (tz));
+ icalcomponent_add_component (vcalcomp, tzcomp);
+}
+
+static gboolean
+timeout_save_cache (gpointer user_data)
+{
+ ECalBackendFileStore *fstore = user_data;
+ ECalBackendFileStorePrivate *priv;
+ icalcomponent *vcalcomp;
+ gchar *data = NULL, *tmpfile;
+ gsize len, nwrote;
+ FILE *f;
+
+ priv = GET_PRIVATE(fstore);
+
+ g_static_rw_lock_reader_lock (&priv->lock);
+
+ priv->save_timeout_id = 0;
+
+ vcalcomp = e_cal_util_new_top_level ();
+ g_hash_table_foreach (priv->timezones, save_timezone, vcalcomp);
+ g_hash_table_foreach (priv->comp_uid_hash, save_object, vcalcomp);
+ data = icalcomponent_as_ical_string_r (vcalcomp);
+ icalcomponent_free (vcalcomp);
+
+ tmpfile = g_strdup_printf ("%s~", priv->cache_file_name);
+ f = g_fopen (tmpfile, "wb");
+ if (!f)
+ goto error;
+
+ len = strlen (data);
+ nwrote = fwrite (data, 1, len, f);
+ if (fclose (f) != 0 || nwrote != len)
+ goto error;
+
+ if (g_rename (tmpfile, priv->cache_file_name) != 0)
+ g_unlink (tmpfile);
+
+ e_file_cache_thaw_changes (priv->keys_cache);
+
+error:
+ g_static_rw_lock_reader_unlock (&priv->lock);
+ g_free (tmpfile);
+ g_free (data);
+ return FALSE;
+}
+
+static void
+save_cache (ECalBackendFileStore *store)
+{
+ ECalBackendFileStorePrivate *priv;
+
+ priv = GET_PRIVATE(store);
+
+ if (priv->save_timeout_id) {
+ g_source_remove (priv->save_timeout_id);
+ }
+
+ priv->save_timeout_id = g_timeout_add (IDLE_SAVE_TIMEOUT, timeout_save_cache, store);
+}
+
+static void
+e_cal_backend_file_store_construct (ECalBackendFileStore *fstore)
+{
+ ECalBackendFileStorePrivate *priv;
+ ECalBackendStore *store = E_CAL_BACKEND_STORE (fstore);
+ const gchar *path;
+
+ priv = GET_PRIVATE(store);
+
+ path = e_cal_backend_store_get_path (store);
+ priv->cache_file_name = g_build_filename (path, CACHE_FILE_NAME, NULL);
+ priv->key_file_name = g_build_filename (path, KEY_FILE_NAME, NULL);
+}
+
+static void
+e_cal_backend_file_store_dispose (GObject *object)
+{
+ G_OBJECT_CLASS (e_cal_backend_file_store_parent_class)->dispose (object);
+}
+
+static void
+e_cal_backend_file_store_finalize (GObject *object)
+{
+ ECalBackendFileStore *fstore = (ECalBackendFileStore *) object;
+ ECalBackendFileStorePrivate *priv;
+
+ priv = GET_PRIVATE(fstore);
+
+ if (priv->save_timeout_id) {
+ g_source_remove (priv->save_timeout_id);
+ timeout_save_cache (fstore);
+ priv->save_timeout_id = 0;
+ }
+
+ if (priv->timezones) {
+ g_hash_table_destroy (priv->timezones);
+ priv->timezones = NULL;
+ }
+
+ if (priv->comp_uid_hash) {
+ g_hash_table_destroy (priv->comp_uid_hash);
+ priv->comp_uid_hash = NULL;
+ }
+
+ if (priv->keys_cache) {
+ g_object_unref (priv->keys_cache);
+ priv->keys_cache = NULL;
+ }
+
+ if (priv->cache_file_name) {
+ g_free (priv->cache_file_name);
+ priv->cache_file_name = NULL;
+ }
+
+ if (priv->key_file_name) {
+ g_free (priv->key_file_name);
+ priv->key_file_name = NULL;
+ }
+
+ priv->dirty = FALSE;
+ priv->freeze_changes = FALSE;
+
+ G_OBJECT_CLASS (e_cal_backend_file_store_parent_class)->finalize (object);
+}
+
+static void
+e_cal_backend_file_store_class_init (ECalBackendFileStoreClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ ECalBackendStoreClass *store_class = E_CAL_BACKEND_STORE_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (ECalBackendFileStorePrivate));
+
+ object_class->dispose = e_cal_backend_file_store_dispose;
+ object_class->finalize = e_cal_backend_file_store_finalize;
+
+ store_class->load = e_cal_backend_file_store_load;
+ store_class->get_component = e_cal_backend_file_store_get_component;
+ store_class->put_component = e_cal_backend_file_store_put_component;
+ store_class->remove_component = e_cal_backend_file_store_remove_component;
+ store_class->get_timezone = e_cal_backend_file_store_get_timezone;
+ store_class->put_timezone = e_cal_backend_file_store_put_timezone;
+ store_class->remove_timezone = e_cal_backend_file_store_remove_timezone;
+ store_class->get_default_timezone = e_cal_backend_file_store_get_default_timezone;
+ store_class->set_default_timezone = e_cal_backend_file_store_set_default_timezone;
+ store_class->get_components_by_uid = e_cal_backend_file_store_get_components_by_uid;
+ store_class->get_key = e_cal_backend_file_store_get_key_value;
+ store_class->put_key = e_cal_backend_file_store_put_key_value;
+ store_class->thaw_changes = e_cal_backend_file_store_thaw_changes;
+ store_class->freeze_changes = e_cal_backend_file_store_freeze_changes;
+}
+
+static void
+e_cal_backend_file_store_init (ECalBackendFileStore *self)
+{
+ ECalBackendFileStorePrivate *priv;
+
+ priv = GET_PRIVATE(self);
+
+ priv->timezones = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+ priv->comp_uid_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) destroy_full_object);
+ priv->keys_cache = NULL;
+ g_static_rw_lock_init (&priv->lock);
+ priv->cache_file_name = NULL;
+ priv->key_file_name = NULL;
+ priv->dirty = FALSE;
+ priv->freeze_changes = FALSE;
+ priv->save_timeout_id = 0;
+}
+
+ECalBackendFileStore*
+e_cal_backend_file_store_new (const gchar *uri, ECalSourceType source_type)
+{
+ ECalBackendFileStore *fstore;
+
+ fstore = g_object_new (E_TYPE_CAL_BACKEND_FILE_STORE, "source_type", source_type, "uri", uri);
+ e_cal_backend_file_store_construct (fstore);
+
+ return fstore;
+}
--- /dev/null
+/*-*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* e-cal-backend-store.c
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ * Authors: Chenthill Palanisamy <pchenthill@novell.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "e-cal-backend-store.h"
+
+G_DEFINE_TYPE (ECalBackendStore, e_cal_backend_store, G_TYPE_OBJECT)
+
+#define GET_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), E_TYPE_CAL_BACKEND_STORE, ECalBackendStorePrivate))
+
+typedef struct _ECalBackendStorePrivate ECalBackendStorePrivate;
+
+struct _ECalBackendStorePrivate {
+ ECalSourceType source_type;
+ gchar *uri;
+ gchar *path;
+};
+
+/* Property IDs */
+enum {
+ PROP_0,
+ PROP_SOURCE_TYPE,
+ PROP_URI
+};
+
+static const gchar *
+get_component (ECalSourceType source_type)
+{
+ switch (source_type) {
+ case E_CAL_SOURCE_TYPE_EVENT :
+ return "calendar";
+ case E_CAL_SOURCE_TYPE_TODO :
+ return "tasks";
+ case E_CAL_SOURCE_TYPE_JOURNAL :
+ return "journal";
+ case E_CAL_SOURCE_TYPE_LAST :
+ default :
+ return "invalid";
+ }
+
+}
+
+static void
+set_store_path (ECalBackendStore *store)
+{
+ ECalBackendStorePrivate *priv;
+
+ priv = GET_PRIVATE(store);
+
+ if (priv->uri)
+ {
+ const gchar *component = get_component (priv->source_type);
+ char *mangled_uri = NULL;
+
+ mangled_uri = g_strdup (priv->uri);
+ mangled_uri = g_strdelimit (mangled_uri, ":/",'_');
+
+ if (priv->path)
+ g_free (priv->path);
+
+ priv->path = g_build_filename (g_get_home_dir (), ".evolution/cache/",
+ component, mangled_uri, NULL);
+ }
+}
+
+static void
+set_uri (ECalBackendStore *store, gchar *uri)
+{
+ ECalBackendStorePrivate *priv;
+
+ priv = GET_PRIVATE(store);
+
+ if (priv->uri)
+ g_free (priv->uri);
+
+ priv->uri = uri;
+}
+
+static void
+e_cal_backend_store_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *spec)
+{
+ ECalBackendStore *store;
+ ECalBackendStorePrivate *priv;
+
+ store = E_CAL_BACKEND_STORE (object);
+ priv = GET_PRIVATE(store);
+
+ switch (property_id) {
+ case PROP_SOURCE_TYPE:
+ priv->source_type = g_value_get_enum (value);
+ case PROP_URI:
+ set_uri (store, g_value_dup_string (value));
+ set_store_path (store);
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, spec);
+ }
+}
+
+static void
+e_cal_backend_store_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *spec)
+{
+ ECalBackendStore *store;
+ ECalBackendStorePrivate *priv;
+
+ store = E_CAL_BACKEND_STORE (object);
+ priv = GET_PRIVATE(store);
+
+ switch (property_id)
+ {
+ case PROP_SOURCE_TYPE:
+ g_value_set_enum (value, priv->source_type);
+ case PROP_URI :
+ g_value_set_string (value, priv->uri);
+ break;
+ default :
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, spec);
+ }
+}
+
+static void
+e_cal_backend_store_dispose (GObject *object)
+{
+ G_OBJECT_CLASS (e_cal_backend_store_parent_class)->dispose (object);
+}
+
+static void
+e_cal_backend_store_finalize (GObject *object)
+{
+ ECalBackendStore *store = (ECalBackendStore *) object;
+ ECalBackendStorePrivate *priv;
+
+ priv = GET_PRIVATE(store);
+
+ if (priv->uri) {
+ g_free (priv->uri);
+ priv->uri = NULL;
+ }
+
+ if (priv->path) {
+ g_free (priv->path);
+ priv->uri = NULL;
+ }
+
+ G_OBJECT_CLASS (e_cal_backend_store_parent_class)->finalize (object);
+}
+
+static void
+e_cal_backend_store_class_init (ECalBackendStoreClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (ECalBackendStorePrivate));
+
+ object_class->dispose = e_cal_backend_store_dispose;
+ object_class->finalize = e_cal_backend_store_finalize;
+ object_class->set_property = e_cal_backend_store_set_property;
+ object_class->get_property = e_cal_backend_store_get_property;
+
+ klass->load = NULL;
+ klass->get_component = NULL;
+ klass->put_component = NULL;
+ klass->remove_component = NULL;
+ klass->get_timezone = NULL;
+ klass->put_timezone = NULL;
+ klass->remove_timezone = NULL;
+ klass->get_default_timezone = NULL;
+ klass->set_default_timezone = NULL;
+ klass->get_components_by_uid = NULL;
+ klass->get_key = NULL;
+ klass->put_key = NULL;
+
+ g_object_class_install_property (object_class, PROP_SOURCE_TYPE,
+ g_param_spec_enum ("source_type", NULL, NULL,
+ e_cal_source_type_enum_get_type (),
+ E_CAL_SOURCE_TYPE_EVENT,
+ G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class, PROP_URI,
+ g_param_spec_string ("uri", NULL, NULL, "",
+ G_PARAM_READABLE | G_PARAM_WRITABLE
+ | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+e_cal_backend_store_init (ECalBackendStore *store)
+{
+ ECalBackendStorePrivate *priv;
+
+ priv = GET_PRIVATE(store);
+
+ priv->uri = NULL;
+ priv->path = NULL;
+ priv->source_type = E_CAL_SOURCE_TYPE_EVENT;
+}
+
+gboolean
+e_cal_backend_store_load (ECalBackendStore *store)
+{
+ g_return_val_if_fail (store != NULL, FALSE);
+ g_return_val_if_fail (E_IS_CAL_BACKEND_STORE (store), FALSE);
+
+ return (E_CAL_BACKEND_STORE_GET_CLASS (store))->load (store);
+}
+
+ECalComponent *
+e_cal_backend_store_get_component (ECalBackendStore *store, const gchar *uid, const gchar *rid)
+{
+ g_return_val_if_fail (store != NULL, NULL);
+ g_return_val_if_fail (E_IS_CAL_BACKEND_STORE (store), NULL);
+ g_return_val_if_fail (uid != NULL, NULL);
+ g_return_val_if_fail (rid != NULL, NULL);
+
+ return (E_CAL_BACKEND_STORE_GET_CLASS (store))->get_component (store, uid, rid);
+}
+
+gboolean
+e_cal_backend_store_put_component (ECalBackendStore *store, ECalComponent *comp)
+{
+ g_return_val_if_fail (store != NULL, FALSE);
+ g_return_val_if_fail (E_IS_CAL_BACKEND_STORE (store), FALSE);
+ g_return_val_if_fail (comp != NULL, FALSE);
+ g_return_val_if_fail (E_IS_CAL_COMPONENT (comp) != FALSE, FALSE);
+
+ return (E_CAL_BACKEND_STORE_GET_CLASS (store))->put_component (store, comp);
+}
+
+gboolean
+e_cal_backend_store_remove_component (ECalBackendStore *store, const gchar *uid, const gchar *rid)
+{
+ g_return_val_if_fail (store != NULL, FALSE);
+ g_return_val_if_fail (E_IS_CAL_BACKEND_STORE (store), FALSE);
+ g_return_val_if_fail (uid != NULL, FALSE);
+ g_return_val_if_fail (rid != NULL, FALSE);
+
+ return (E_CAL_BACKEND_STORE_GET_CLASS (store))->remove_component (store, uid, rid);
+}
+
+const icaltimezone *
+e_cal_backend_store_get_timezone (ECalBackendStore *store, const gchar *tzid)
+{
+ g_return_val_if_fail (store != NULL, NULL);
+ g_return_val_if_fail (E_IS_CAL_BACKEND_STORE (store), NULL);
+ g_return_val_if_fail (tzid != NULL, NULL);
+
+ return (E_CAL_BACKEND_STORE_GET_CLASS (store))->get_timezone (store, tzid);
+}
+
+gboolean
+e_cal_backend_store_put_timezone (ECalBackendStore *store, const icaltimezone *zone)
+{
+ g_return_val_if_fail (store != NULL, FALSE);
+ g_return_val_if_fail (E_IS_CAL_BACKEND_STORE (store), FALSE);
+ g_return_val_if_fail (zone != NULL, FALSE);
+
+ return (E_CAL_BACKEND_STORE_GET_CLASS (store))->put_timezone (store, zone);
+}
+
+gboolean
+e_cal_backend_store_remove_timezone (ECalBackendStore *store, const gchar *tzid)
+{
+ g_return_val_if_fail (store != NULL, FALSE);
+ g_return_val_if_fail (E_IS_CAL_BACKEND_STORE (store), FALSE);
+ g_return_val_if_fail (tzid != NULL, FALSE);
+
+ return (E_CAL_BACKEND_STORE_GET_CLASS (store))->remove_timezone (store, tzid);
+}
+
+const icaltimezone *
+e_cal_backend_store_get_default_timezone (ECalBackendStore *store)
+{
+ g_return_val_if_fail (store != NULL, NULL);
+ g_return_val_if_fail (E_IS_CAL_BACKEND_STORE (store), NULL);
+
+ return (E_CAL_BACKEND_STORE_GET_CLASS (store))->get_default_timezone (store);
+}
+
+gboolean
+e_cal_backend_store_set_default_timezone (ECalBackendStore *store, const icaltimezone *zone)
+{
+ g_return_val_if_fail (store != NULL, FALSE);
+ g_return_val_if_fail (E_IS_CAL_BACKEND_STORE (store), FALSE);
+ g_return_val_if_fail (zone != NULL, FALSE);
+
+ return (E_CAL_BACKEND_STORE_GET_CLASS (store))->set_default_timezone (store, zone);
+}
+
+GSList *
+e_cal_backend_store_get_components_by_uid (ECalBackendStore *store, const gchar *uid)
+{
+ g_return_val_if_fail (store != NULL, NULL);
+ g_return_val_if_fail (E_IS_CAL_BACKEND_STORE (store), NULL);
+ g_return_val_if_fail (uid != NULL, NULL);
+
+ return (E_CAL_BACKEND_STORE_GET_CLASS (store))->get_components_by_uid (store, uid);
+}
+
+const gchar *
+e_cal_backend_store_get_key (ECalBackendStore *store, const gchar *key)
+{
+ g_return_val_if_fail (store != NULL, NULL);
+ g_return_val_if_fail (E_IS_CAL_BACKEND_STORE (store), NULL);
+ g_return_val_if_fail (key != NULL, NULL);
+
+ return (E_CAL_BACKEND_STORE_GET_CLASS (store))->get_key (store, key);
+}
+
+gboolean
+e_cal_backend_store_put_key (ECalBackendStore *store, const gchar *key, const gchar *value)
+{
+ g_return_val_if_fail (store != NULL, FALSE);
+ g_return_val_if_fail (E_IS_CAL_BACKEND_STORE (store), FALSE);
+ g_return_val_if_fail (key != NULL, FALSE);
+
+ return (E_CAL_BACKEND_STORE_GET_CLASS (store))->put_key (store, key, value);
+}
+
+void
+e_cal_backend_store_thaw_changes (ECalBackendStore *store)
+{
+ g_return_if_fail (store != NULL);
+ g_return_if_fail (E_IS_CAL_BACKEND_STORE (store));
+
+ (E_CAL_BACKEND_STORE_GET_CLASS (store))->thaw_changes (store);
+}
+
+void
+e_cal_backend_store_freeze_changes (ECalBackendStore *store)
+{
+ g_return_if_fail (store != NULL);
+ g_return_if_fail (E_IS_CAL_BACKEND_STORE (store));
+
+ (E_CAL_BACKEND_STORE_GET_CLASS (store))->freeze_changes (store);
+}
--- /dev/null
+/*-*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* e-cal-backend-store.h
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ * Authors: Chenthill Palanisamy <pchenthill@novell.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _E_CAL_BACKEND_STORE
+#define _E_CAL_BACKEND_STORE
+
+#include <glib-object.h>
+#include <libecal/e-cal-component.h>
+#include <libecal/e-cal.h>
+
+G_BEGIN_DECLS
+
+#define E_TYPE_CAL_BACKEND_STORE e_cal_backend_store_get_type()
+
+#define E_CAL_BACKEND_STORE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_CAL_BACKEND_STORE, ECalBackendStore))
+
+#define E_CAL_BACKEND_STORE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_CAL_BACKEND_STORE, ECalBackendStoreClass))
+
+#define E_IS_CAL_BACKEND_STORE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_CAL_BACKEND_STORE))
+
+#define E_IS_CAL_BACKEND_STORE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_CAL_BACKEND_STORE))
+
+#define E_CAL_BACKEND_STORE_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_CAL_BACKEND_STORE, ECalBackendStoreClass))
+
+typedef struct {
+ GObject parent;
+} ECalBackendStore;
+
+typedef struct {
+ GObjectClass parent_class;
+
+ /* virtual methods */
+ gboolean (* load) (ECalBackendStore *store);
+
+ ECalComponent *(* get_component) (ECalBackendStore *store, const gchar *uid, const gchar *rid);
+ gboolean (* put_component) (ECalBackendStore *store, ECalComponent *comp);
+ gboolean (* remove_component) (ECalBackendStore *store, const gchar *uid, const gchar *rid);
+ GSList *(* get_components_by_uid) (ECalBackendStore *store, const gchar *uid);
+
+ const icaltimezone *(* get_timezone) (ECalBackendStore *store, const gchar *tzid);
+ gboolean (* put_timezone) (ECalBackendStore *store, const icaltimezone *zone);
+ gboolean (* remove_timezone) (ECalBackendStore *store, const gchar *tzid);
+
+ const icaltimezone *(* get_default_timezone) (ECalBackendStore *store);
+ gboolean (* set_default_timezone) (ECalBackendStore *store, const icaltimezone *zone);
+
+ void (* thaw_changes) (ECalBackendStore *store);
+ void (* freeze_changes) (ECalBackendStore *store);
+
+ const gchar *(* get_key) (ECalBackendStore *store, const gchar *key);
+ gboolean (* put_key) (ECalBackendStore *store, const gchar *key, const gchar *value);
+
+} ECalBackendStoreClass;
+
+GType e_cal_backend_store_get_type (void);
+
+const char *e_cal_backend_store_get_path (ECalBackendStore *store);
+
+gboolean e_cal_backend_store_load (ECalBackendStore *store);
+ECalComponent *e_cal_backend_store_get_component (ECalBackendStore *store, const gchar *uid, const gchar *rid);
+gboolean e_cal_backend_store_put_component (ECalBackendStore *store, ECalComponent *comp);
+gboolean e_cal_backend_store_remove_component (ECalBackendStore *store, const gchar *uid, const gchar *rid);
+const icaltimezone *e_cal_backend_store_get_timezone (ECalBackendStore *store, const gchar *tzid);
+gboolean e_cal_backend_store_put_timezone (ECalBackendStore *store, const icaltimezone *zone);
+gboolean e_cal_backend_store_remove_timezone (ECalBackendStore *store, const gchar *tzid);
+const icaltimezone *e_cal_backend_store_get_default_timezone (ECalBackendStore *store);
+gboolean e_cal_backend_store_set_default_timezone (ECalBackendStore *store, const icaltimezone *zone);
+GSList *e_cal_backend_store_get_components_by_uid (ECalBackendStore *store, const gchar *uid);
+GSList *e_cal_backend_store_get_objects_list (ECalBackendStore *store, const gchar *sexp);
+const gchar *e_cal_backend_store_get_key (ECalBackendStore *store, const gchar *key);
+gboolean e_cal_backend_store_put_key (ECalBackendStore *store, const gchar *key, const gchar *value);
+void e_cal_backend_store_thaw_changes (ECalBackendStore *store);
+void e_cal_backend_store_freeze_changes (ECalBackendStore *store);
+
+
+G_END_DECLS
+
+#endif /* _E_CAL_BACKEND_STORE */