From b432e76d607ed2d00fe4283d5c59cee96035dc22 Mon Sep 17 00:00:00 2001 From: Chenthill Palanisamy Date: Tue, 14 Jul 2009 02:02:31 +0530 Subject: [PATCH] Initial commit for calendar cache rewrite. Will be migrating the backends to new cache after some testing. --- calendar/libedata-cal/Makefile.am | 4 + calendar/libedata-cal/e-cal-backend-file-store.c | 753 +++++++++++++++++++++++ calendar/libedata-cal/e-cal-backend-file-store.h | 61 ++ calendar/libedata-cal/e-cal-backend-store.c | 350 +++++++++++ calendar/libedata-cal/e-cal-backend-store.h | 101 +++ 5 files changed, 1269 insertions(+) create mode 100644 calendar/libedata-cal/e-cal-backend-file-store.c create mode 100644 calendar/libedata-cal/e-cal-backend-file-store.h create mode 100644 calendar/libedata-cal/e-cal-backend-store.c create mode 100644 calendar/libedata-cal/e-cal-backend-store.h diff --git a/calendar/libedata-cal/Makefile.am b/calendar/libedata-cal/Makefile.am index af88409..b3b66b8 100644 --- a/calendar/libedata-cal/Makefile.am +++ b/calendar/libedata-cal/Makefile.am @@ -40,6 +40,8 @@ libedata_cal_1_2_la_SOURCES = \ e-cal-backend-sexp.c \ e-cal-backend-sync.c \ e-cal-backend-util.c \ + e-cal-backend-store.c \ + e-cal-backend-file-store.c \ e-data-cal.c \ e-data-cal-factory.c \ e-data-cal-view.c @@ -68,6 +70,8 @@ libedata_calinclude_HEADERS = \ e-data-cal.h \ e-data-cal-common.h \ e-data-cal-factory.h \ + e-cal-backend-store.h \ + e-cal-backend-file-store.h \ e-data-cal-view.h %-$(API_VERSION).pc: %.pc diff --git a/calendar/libedata-cal/e-cal-backend-file-store.c b/calendar/libedata-cal/e-cal-backend-file-store.c new file mode 100644 index 0000000..9238adf --- /dev/null +++ b/calendar/libedata-cal/e-cal-backend-file-store.c @@ -0,0 +1,753 @@ +/*-*- 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 + * + * 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 +#include "e-cal-backend-file-store.h" +#include "libebackend/e-file-cache.h" +#include + +#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; +} diff --git a/calendar/libedata-cal/e-cal-backend-file-store.h b/calendar/libedata-cal/e-cal-backend-file-store.h new file mode 100644 index 0000000..9548c99 --- /dev/null +++ b/calendar/libedata-cal/e-cal-backend-file-store.h @@ -0,0 +1,61 @@ +/*-*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* e-cal-backend-file-store.h + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + * Authors: Chenthill Palanisamy + * + * 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_FILE_STORE +#define _E_CAL_BACKEND_FILE_STORE + +#include +#include "e-cal-backend-store.h" + +G_BEGIN_DECLS + +#define E_TYPE_CAL_BACKEND_FILE_STORE e_cal_backend_file_store_get_type() + +#define E_CAL_BACKEND_FILE_STORE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_CAL_BACKEND_FILE_STORE, ECalBackendFileStore)) + +#define E_CAL_BACKEND_FILE_STORE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_CAL_BACKEND_FILE_STORE, ECalBackendFileStoreClass)) + +#define E_IS_CAL_BACKEND_FILE_STORE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_CAL_BACKEND_FILE_STORE)) + +#define E_IS_CAL_BACKEND_FILE_STORE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_CAL_BACKEND_FILE_STORE)) + +#define E_CAL_BACKEND_FILE_STORE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_CAL_BACKEND_FILE_STORE, ECalBackendFileStoreClass)) + +typedef struct { + ECalBackendStore parent; +} ECalBackendFileStore; + +typedef struct { + ECalBackendStoreClass parent_class; +} ECalBackendFileStoreClass; + +GType e_cal_backend_file_store_get_type (void); + +ECalBackendFileStore* e_cal_backend_file_store_new (const gchar *uri, ECalSourceType source_type); + +G_END_DECLS + +#endif /* _E_CAL_BACKEND_FILE_STORE */ diff --git a/calendar/libedata-cal/e-cal-backend-store.c b/calendar/libedata-cal/e-cal-backend-store.c new file mode 100644 index 0000000..0d6d86f --- /dev/null +++ b/calendar/libedata-cal/e-cal-backend-store.c @@ -0,0 +1,350 @@ +/*-*- 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 + * + * 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); +} diff --git a/calendar/libedata-cal/e-cal-backend-store.h b/calendar/libedata-cal/e-cal-backend-store.h new file mode 100644 index 0000000..cea1bf1 --- /dev/null +++ b/calendar/libedata-cal/e-cal-backend-store.h @@ -0,0 +1,101 @@ +/*-*- 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 + * + * 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 +#include +#include + +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 */ -- 2.7.4