aboutsummaryrefslogtreecommitdiffstats
path: root/calendar/pcs/cal-backend-file.c
diff options
context:
space:
mode:
Diffstat (limited to 'calendar/pcs/cal-backend-file.c')
-rw-r--r--calendar/pcs/cal-backend-file.c1988
1 files changed, 0 insertions, 1988 deletions
diff --git a/calendar/pcs/cal-backend-file.c b/calendar/pcs/cal-backend-file.c
deleted file mode 100644
index a3cd2c360f..0000000000
--- a/calendar/pcs/cal-backend-file.c
+++ /dev/null
@@ -1,1988 +0,0 @@
-/* Evolution calendar - iCalendar file backend
- *
- * Copyright (C) 2000-2003 Ximian, Inc.
- *
- * Authors: Federico Mena-Quintero <federico@ximian.com>
- * Rodrigo Moya <rodrigo@ximian.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of version 2 of the GNU 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#include <config.h>
-#include <string.h>
-#include <unistd.h>
-#include <bonobo/bonobo-exception.h>
-#include <bonobo/bonobo-moniker-util.h>
-#include <libgnome/gnome-i18n.h>
-#include <libgnomevfs/gnome-vfs.h>
-#include "e-util/e-xml-hash-utils.h"
-#include "cal-util/cal-recur.h"
-#include "cal-util/cal-util.h"
-#include "cal-backend-file-events.h"
-#include "cal-backend-util.h"
-#include "cal-backend-object-sexp.h"
-
-
-
-/* Placeholder for each component and its recurrences */
-typedef struct {
- CalComponent *full_object;
- GHashTable *recurrences;
-} CalBackendFileObject;
-
-/* Private part of the CalBackendFile structure */
-struct _CalBackendFilePrivate {
- /* URI where the calendar data is stored */
- char *uri;
-
- /* Filename in the dir */
- char *file_name;
- gboolean read_only;
-
- /* Toplevel VCALENDAR component */
- icalcomponent *icalcomp;
-
- /* All the objects in the calendar, hashed by UID. The
- * hash key *is* the uid returned by cal_component_get_uid(); it is not
- * copied, so don't free it when you remove an object from the hash
- * table. Each item in the hash table is a CalBackendFileObject.
- */
- GHashTable *comp_uid_hash;
-
- GList *comp;
-
- /* Config database handle for free/busy organizer information */
- EConfigListener *config_listener;
-
- /* The calendar's default timezone, used for resolving DATE and
- floating DATE-TIME values. */
- icaltimezone *default_zone;
-
- /* The list of live queries */
- GList *queries;
-};
-
-
-
-static void cal_backend_file_dispose (GObject *object);
-static void cal_backend_file_finalize (GObject *object);
-
-static CalBackendSyncClass *parent_class;
-
-
-
-/* g_hash_table_foreach() callback to destroy recurrences in the hash table */
-static void
-free_recurrence (gpointer key, gpointer value, gpointer data)
-{
- char *rid = key;
- CalComponent *comp = value;
-
- g_free (rid);
- g_object_unref (comp);
-}
-
-/* g_hash_table_foreach() callback to destroy a CalBackendFileObject */
-static void
-free_object (gpointer key, gpointer value, gpointer data)
-{
- CalBackendFileObject *obj_data = value;
-
- g_object_unref (obj_data->full_object);
- g_hash_table_foreach (obj_data->recurrences, (GHFunc) free_recurrence, NULL);
- g_hash_table_destroy (obj_data->recurrences);
-}
-
-/* Saves the calendar data */
-static void
-save (CalBackendFile *cbfile)
-{
- CalBackendFilePrivate *priv;
- GnomeVFSURI *uri, *backup_uri;
- GnomeVFSHandle *handle = NULL;
- GnomeVFSResult result = GNOME_VFS_ERROR_BAD_FILE;
- GnomeVFSFileSize out;
- gchar *tmp, *backup_uristr;
- char *buf;
-
- priv = cbfile->priv;
- g_assert (priv->uri != NULL);
- g_assert (priv->icalcomp != NULL);
-
- uri = gnome_vfs_uri_new (priv->uri);
- if (!uri)
- goto error_malformed_uri;
-
- /* save calendar to backup file */
- tmp = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_NONE);
- if (!tmp) {
- gnome_vfs_uri_unref (uri);
- goto error_malformed_uri;
- }
-
- backup_uristr = g_strconcat (tmp, "~", NULL);
- backup_uri = gnome_vfs_uri_new (backup_uristr);
-
- g_free (tmp);
- g_free (backup_uristr);
-
- if (!backup_uri) {
- gnome_vfs_uri_unref (uri);
- goto error_malformed_uri;
- }
-
- result = gnome_vfs_create_uri (&handle, backup_uri,
- GNOME_VFS_OPEN_WRITE,
- FALSE, 0666);
- if (result != GNOME_VFS_OK) {
- gnome_vfs_uri_unref (uri);
- gnome_vfs_uri_unref (backup_uri);
- goto error;
- }
-
- buf = icalcomponent_as_ical_string (priv->icalcomp);
- result = gnome_vfs_write (handle, buf, strlen (buf) * sizeof (char), &out);
- gnome_vfs_close (handle);
- if (result != GNOME_VFS_OK) {
- gnome_vfs_uri_unref (uri);
- gnome_vfs_uri_unref (backup_uri);
- goto error;
- }
-
- /* now copy the temporary file to the real file */
- result = gnome_vfs_move_uri (backup_uri, uri, TRUE);
-
- gnome_vfs_uri_unref (uri);
- gnome_vfs_uri_unref (backup_uri);
- if (result != GNOME_VFS_OK)
- goto error;
-
- return;
-
- error_malformed_uri:
- cal_backend_notify_error (CAL_BACKEND (cbfile),
- _("Can't save calendar data: Malformed URI."));
- return;
-
- error:
- cal_backend_notify_error (CAL_BACKEND (cbfile), gnome_vfs_result_to_string (result));
- return;
-}
-
-/* Dispose handler for the file backend */
-static void
-cal_backend_file_dispose (GObject *object)
-{
- CalBackendFile *cbfile;
- CalBackendFilePrivate *priv;
-
- cbfile = CAL_BACKEND_FILE (object);
- priv = cbfile->priv;
-
- /* Save if necessary */
-
- if (priv->comp_uid_hash) {
- g_hash_table_foreach (priv->comp_uid_hash, (GHFunc) free_object, NULL);
- g_hash_table_destroy (priv->comp_uid_hash);
- priv->comp_uid_hash = NULL;
- }
-
- g_list_free (priv->comp);
- priv->comp = NULL;
-
- if (priv->icalcomp) {
- icalcomponent_free (priv->icalcomp);
- priv->icalcomp = NULL;
- }
-
- if (priv->config_listener) {
- g_object_unref (priv->config_listener);
- priv->config_listener = NULL;
- }
-
- if (G_OBJECT_CLASS (parent_class)->dispose)
- (* G_OBJECT_CLASS (parent_class)->dispose) (object);
-}
-
-/* Finalize handler for the file backend */
-static void
-cal_backend_file_finalize (GObject *object)
-{
- CalBackendFile *cbfile;
- CalBackendFilePrivate *priv;
-
- g_return_if_fail (object != NULL);
- g_return_if_fail (IS_CAL_BACKEND_FILE (object));
-
- cbfile = CAL_BACKEND_FILE (object);
- priv = cbfile->priv;
-
- /* Clean up */
-
- if (priv->uri) {
- g_free (priv->uri);
- priv->uri = NULL;
- }
-
- g_free (priv);
- cbfile->priv = NULL;
-
- if (G_OBJECT_CLASS (parent_class)->finalize)
- (* G_OBJECT_CLASS (parent_class)->finalize) (object);
-}
-
-
-
-/* Looks up a component by its UID on the backend's component hash table */
-static CalComponent *
-lookup_component (CalBackendFile *cbfile, const char *uid)
-{
- CalBackendFilePrivate *priv;
- CalBackendFileObject *obj_data;
-
- priv = cbfile->priv;
-
- obj_data = g_hash_table_lookup (priv->comp_uid_hash, uid);
- return obj_data ? obj_data->full_object : NULL;
-}
-
-
-
-/* Calendar backend methods */
-
-/* Is_read_only handler for the file backend */
-static CalBackendSyncStatus
-cal_backend_file_is_read_only (CalBackendSync *backend, Cal *cal, gboolean *read_only)
-{
- CalBackendFile *cbfile = (CalBackendFile *) backend;
-
- *read_only = cbfile->priv->read_only;
-
- return GNOME_Evolution_Calendar_Success;
-}
-
-/* Get_email_address handler for the file backend */
-static CalBackendSyncStatus
-cal_backend_file_get_cal_address (CalBackendSync *backend, Cal *cal, char **address)
-{
- /* A file backend has no particular email address associated
- * with it (although that would be a useful feature some day).
- */
- *address = NULL;
-
- return GNOME_Evolution_Calendar_Success;
-}
-
-static CalBackendSyncStatus
-cal_backend_file_get_ldap_attribute (CalBackendSync *backend, Cal *cal, char **attribute)
-{
- *attribute = NULL;
-
- return GNOME_Evolution_Calendar_Success;
-}
-
-static CalBackendSyncStatus
-cal_backend_file_get_alarm_email_address (CalBackendSync *backend, Cal *cal, char **address)
-{
- /* A file backend has no particular email address associated
- * with it (although that would be a useful feature some day).
- */
- *address = NULL;
-
- return GNOME_Evolution_Calendar_Success;
-}
-
-static CalBackendSyncStatus
-cal_backend_file_get_static_capabilities (CalBackendSync *backend, Cal *cal, char **capabilities)
-{
- *capabilities = CAL_STATIC_CAPABILITY_NO_EMAIL_ALARMS;
-
- return GNOME_Evolution_Calendar_Success;
-}
-
-/* function to resolve timezones */
-static icaltimezone *
-resolve_tzid (const char *tzid, gpointer user_data)
-{
- icalcomponent *vcalendar_comp = user_data;
-
- if (!tzid || !tzid[0])
- return NULL;
- else if (!strcmp (tzid, "UTC"))
- return icaltimezone_get_utc_timezone ();
-
- return icalcomponent_get_timezone (vcalendar_comp, tzid);
-}
-
-/* Checks if the specified component has a duplicated UID and if so changes it */
-static void
-check_dup_uid (CalBackendFile *cbfile, CalComponent *comp)
-{
- CalBackendFilePrivate *priv;
- CalBackendFileObject *obj_data;
- const char *uid;
- char *new_uid;
-
- priv = cbfile->priv;
-
- cal_component_get_uid (comp, &uid);
-
- obj_data = g_hash_table_lookup (priv->comp_uid_hash, uid);
- if (!obj_data)
- return; /* Everything is fine */
-
- g_message ("check_dup_uid(): Got object with duplicated UID `%s', changing it...", uid);
-
- new_uid = cal_component_gen_uid ();
- cal_component_set_uid (comp, new_uid);
- g_free (new_uid);
-
- /* FIXME: I think we need to reset the SEQUENCE property and reset the
- * CREATED/DTSTAMP/LAST-MODIFIED.
- */
-
- save (cbfile);
-}
-
-static const char *
-get_rid_string (CalComponent *comp)
-{
- CalComponentRange range;
- struct icaltimetype tt;
-
- cal_component_get_recurid (comp, &range);
- if (!range.datetime.value)
- return "0";
- tt = *range.datetime.value;
- cal_component_free_range (&range);
-
- return icaltime_is_valid_time (tt) && !icaltime_is_null_time (tt) ?
- icaltime_as_ical_string (tt) : "0";
-}
-
-static struct icaltimetype
-get_rid_icaltime (CalComponent *comp)
-{
- CalComponentRange range;
- struct icaltimetype tt;
-
- cal_component_get_recurid (comp, &range);
- if (!range.datetime.value)
- return icaltime_null_time ();
- tt = *range.datetime.value;
- cal_component_free_range (&range);
-
- return tt;
-}
-
-/* Tries to add an icalcomponent to the file backend. We only store the objects
- * of the types we support; all others just remain in the toplevel component so
- * that we don't lose them.
- */
-static void
-add_component (CalBackendFile *cbfile, CalComponent *comp, gboolean add_to_toplevel)
-{
- CalBackendFilePrivate *priv;
- CalBackendFileObject *obj_data;
- const char *uid;
- GSList *categories;
-
- priv = cbfile->priv;
-
- if (cal_component_is_instance (comp)) { /* FIXME: more checks needed, to detect detached instances */
- const char *rid;
-
- cal_component_get_uid (comp, &uid);
-
- obj_data = g_hash_table_lookup (priv->comp_uid_hash, uid);
- if (!obj_data) {
- g_warning (G_STRLOC ": Got an instance of a non-existing component");
- return;
- }
-
- rid = get_rid_string (comp);
- if (g_hash_table_lookup (obj_data->recurrences, rid)) {
- g_warning (G_STRLOC ": Tried to adding an already existing recurrence");
- return;
- }
-
- g_hash_table_insert (obj_data->recurrences, g_strdup (rid), comp);
- } else {
- /* Ensure that the UID is unique; some broken implementations spit
- * components with duplicated UIDs.
- */
- check_dup_uid (cbfile, comp);
- cal_component_get_uid (comp, &uid);
-
- obj_data = g_new0 (CalBackendFileObject, 1);
- obj_data->full_object = comp;
- obj_data->recurrences = g_hash_table_new (g_str_hash, g_str_equal);
-
- g_hash_table_insert (priv->comp_uid_hash, (gpointer) uid, obj_data);
- }
-
- priv->comp = g_list_prepend (priv->comp, comp);
-
- /* Put the object in the toplevel component if required */
-
- if (add_to_toplevel) {
- icalcomponent *icalcomp;
-
- icalcomp = cal_component_get_icalcomponent (comp);
- g_assert (icalcomp != NULL);
-
- icalcomponent_add_component (priv->icalcomp, icalcomp);
- }
-
- /* Update the set of categories */
- cal_component_get_categories_list (comp, &categories);
- cal_backend_ref_categories (CAL_BACKEND (cbfile), categories);
- cal_component_free_categories_list (categories);
-}
-
-/* g_hash_table_foreach() callback to remove recurrences from the calendar */
-static void
-remove_recurrence_cb (gpointer key, gpointer value, gpointer data)
-{
- GList *l;
- GSList *categories;
- icalcomponent *icalcomp;
- CalBackendFilePrivate *priv;
- CalComponent *comp = value;
- CalBackendFile *cbfile = data;
-
- priv = cbfile->priv;
-
- /* remove the recurrence from the top-level calendar */
- icalcomp = cal_component_get_icalcomponent (comp);
- g_assert (icalcomp != NULL);
-
- icalcomponent_remove_component (priv->icalcomp, icalcomp);
-
- /* remove it from our mapping */
- l = g_list_find (priv->comp, comp);
- priv->comp = g_list_delete_link (priv->comp, l);
-
- /* update the set of categories */
- cal_component_get_categories_list (comp, &categories);
- cal_backend_unref_categories (CAL_BACKEND (cbfile), categories);
- cal_component_free_categories_list (categories);
-}
-
-/* Removes a component from the backend's hash and lists. Does not perform
- * notification on the clients. Also removes the component from the toplevel
- * icalcomponent.
- */
-static void
-remove_component (CalBackendFile *cbfile, CalComponent *comp)
-{
- CalBackendFilePrivate *priv;
- icalcomponent *icalcomp;
- const char *uid;
- GList *l;
- GSList *categories;
- CalBackendFileObject *obj_data;
-
- priv = cbfile->priv;
-
- /* Remove the icalcomp from the toplevel */
-
- icalcomp = cal_component_get_icalcomponent (comp);
- g_assert (icalcomp != NULL);
-
- icalcomponent_remove_component (priv->icalcomp, icalcomp);
-
- /* Remove it from our mapping */
-
- cal_component_get_uid (comp, &uid);
- obj_data = g_hash_table_lookup (priv->comp_uid_hash, uid);
- if (!obj_data)
- return;
-
- g_hash_table_remove (priv->comp_uid_hash, uid);
-
- l = g_list_find (priv->comp, comp);
- g_assert (l != NULL);
- priv->comp = g_list_delete_link (priv->comp, l);
-
- /* remove the recurrences also */
- g_hash_table_foreach (obj_data->recurrences, (GHFunc) remove_recurrence_cb, cbfile);
-
- /* Update the set of categories */
- cal_component_get_categories_list (comp, &categories);
- cal_backend_unref_categories (CAL_BACKEND (cbfile), categories);
- cal_component_free_categories_list (categories);
-
- free_object ((gpointer) uid, (gpointer) obj_data, NULL);
-}
-
-/* Scans the toplevel VCALENDAR component and stores the objects it finds */
-static void
-scan_vcalendar (CalBackendFile *cbfile)
-{
- CalBackendFilePrivate *priv;
- icalcompiter iter;
-
- priv = cbfile->priv;
- g_assert (priv->icalcomp != NULL);
- g_assert (priv->comp_uid_hash != NULL);
-
- for (iter = icalcomponent_begin_component (priv->icalcomp, ICAL_ANY_COMPONENT);
- icalcompiter_deref (&iter) != NULL;
- icalcompiter_next (&iter)) {
- icalcomponent *icalcomp;
- icalcomponent_kind kind;
- CalComponent *comp;
-
- icalcomp = icalcompiter_deref (&iter);
-
- kind = icalcomponent_isa (icalcomp);
-
- if (!(kind == ICAL_VEVENT_COMPONENT
- || kind == ICAL_VTODO_COMPONENT
- || kind == ICAL_VJOURNAL_COMPONENT))
- continue;
-
- comp = cal_component_new ();
-
- if (!cal_component_set_icalcomponent (comp, icalcomp))
- continue;
-
- add_component (cbfile, comp, FALSE);
- }
-}
-
-/* Parses an open iCalendar file and loads it into the backend */
-static CalBackendSyncStatus
-open_cal (CalBackendFile *cbfile, const char *uristr)
-{
- CalBackendFilePrivate *priv;
- icalcomponent *icalcomp;
-
- priv = cbfile->priv;
-
- icalcomp = cal_util_parse_ics_file (uristr);
- if (!icalcomp)
- return GNOME_Evolution_Calendar_OtherError;
-
- /* FIXME: should we try to demangle XROOT components and
- * individual components as well?
- */
-
- if (icalcomponent_isa (icalcomp) != ICAL_VCALENDAR_COMPONENT) {
- icalcomponent_free (icalcomp);
-
- return GNOME_Evolution_Calendar_OtherError;
- }
-
- priv->icalcomp = icalcomp;
-
- priv->comp_uid_hash = g_hash_table_new (g_str_hash, g_str_equal);
- scan_vcalendar (cbfile);
-
- priv->uri = g_strdup (uristr);
-
- return GNOME_Evolution_Calendar_Success;
-}
-
-static CalBackendSyncStatus
-create_cal (CalBackendFile *cbfile, const char *uristr)
-{
- CalBackendFilePrivate *priv;
-
- priv = cbfile->priv;
-
- /* Create the new calendar information */
- priv->icalcomp = cal_util_new_top_level ();
-
- /* Create our internal data */
- priv->comp_uid_hash = g_hash_table_new (g_str_hash, g_str_equal);
-
- priv->uri = g_strdup (uristr);
-
- save (cbfile);
-
- return GNOME_Evolution_Calendar_Success;
-}
-
-static char *
-get_uri_string (CalBackend *backend)
-{
- CalBackendFile *cbfile;
- CalBackendFilePrivate *priv;
- const char *master_uri;
- char *full_uri, *str_uri;
- GnomeVFSURI *uri;
-
- cbfile = CAL_BACKEND_FILE (backend);
- priv = cbfile->priv;
-
- master_uri = cal_backend_get_uri (backend);
- g_message (G_STRLOC ": Trying to open %s", master_uri);
-
- /* FIXME Check the error conditions a little more elegantly here */
- if (g_strrstr ("tasks.ics", master_uri) || g_strrstr ("calendar.ics", master_uri)) {
- g_warning (G_STRLOC ": Existing file name %s", master_uri);
-
- return NULL;
- }
-
- full_uri = g_strdup_printf ("%s%s%s", master_uri, G_DIR_SEPARATOR_S, priv->file_name);
- uri = gnome_vfs_uri_new (full_uri);
- g_free (full_uri);
-
- if (!uri)
- return NULL;
-
- str_uri = gnome_vfs_uri_to_string (uri,
- (GNOME_VFS_URI_HIDE_USER_NAME
- | GNOME_VFS_URI_HIDE_PASSWORD
- | GNOME_VFS_URI_HIDE_HOST_NAME
- | GNOME_VFS_URI_HIDE_HOST_PORT
- | GNOME_VFS_URI_HIDE_TOPLEVEL_METHOD));
- gnome_vfs_uri_unref (uri);
-
- if (!str_uri || !strlen (str_uri)) {
- g_free (str_uri);
-
- return NULL;
- }
-
- return str_uri;
-}
-
-/* Open handler for the file backend */
-static CalBackendSyncStatus
-cal_backend_file_open (CalBackendSync *backend, Cal *cal, gboolean only_if_exists)
-{
- CalBackendFile *cbfile;
- CalBackendFilePrivate *priv;
- char *str_uri;
- CalBackendSyncStatus status;
-
- cbfile = CAL_BACKEND_FILE (backend);
- priv = cbfile->priv;
-
- /* Claim a succesful open if we are already open */
- if (priv->uri && priv->comp_uid_hash)
- return GNOME_Evolution_Calendar_Success;
-
- str_uri = get_uri_string (CAL_BACKEND (backend));
- if (!str_uri)
- return GNOME_Evolution_Calendar_OtherError;
-
- if (access (str_uri, R_OK) == 0) {
- status = open_cal (cbfile, str_uri);
- if (access (str_uri, W_OK) != 0)
- priv->read_only = TRUE;
- } else {
- if (only_if_exists)
- status = GNOME_Evolution_Calendar_NoSuchCal;
- else
- status = create_cal (cbfile, str_uri);
- }
-
- g_free (str_uri);
-
- return status;
-}
-
-static CalBackendSyncStatus
-cal_backend_file_remove (CalBackendSync *backend, Cal *cal)
-{
- CalBackendFile *cbfile;
- CalBackendFilePrivate *priv;
- char *str_uri;
-
- cbfile = CAL_BACKEND_FILE (backend);
- priv = cbfile->priv;
-
- str_uri = get_uri_string (CAL_BACKEND (backend));
- if (!str_uri)
- return GNOME_Evolution_Calendar_OtherError;
-
- if (access (str_uri, W_OK) != 0) {
- g_free (str_uri);
-
- return GNOME_Evolution_Calendar_PermissionDenied;
- }
-
- /* FIXME Remove backup file and whole directory too? */
- if (unlink (str_uri) != 0) {
- g_free (str_uri);
-
- return GNOME_Evolution_Calendar_OtherError;
- }
-
- g_free (str_uri);
-
- return GNOME_Evolution_Calendar_Success;
-}
-
-/* is_loaded handler for the file backend */
-static gboolean
-cal_backend_file_is_loaded (CalBackend *backend)
-{
- CalBackendFile *cbfile;
- CalBackendFilePrivate *priv;
-
- cbfile = CAL_BACKEND_FILE (backend);
- priv = cbfile->priv;
-
- return (priv->icalcomp != NULL);
-}
-
-/* is_remote handler for the file backend */
-static CalMode
-cal_backend_file_get_mode (CalBackend *backend)
-{
- CalBackendFile *cbfile;
- CalBackendFilePrivate *priv;
-
- cbfile = CAL_BACKEND_FILE (backend);
- priv = cbfile->priv;
-
- return CAL_MODE_LOCAL;
-}
-
-/* Set_mode handler for the file backend */
-static void
-cal_backend_file_set_mode (CalBackend *backend, CalMode mode)
-{
- cal_backend_notify_mode (backend,
- GNOME_Evolution_Calendar_Listener_MODE_NOT_SUPPORTED,
- GNOME_Evolution_Calendar_MODE_LOCAL);
-
-}
-
-static CalBackendSyncStatus
-cal_backend_file_get_default_object (CalBackendSync *backend, Cal *cal, char **object)
-{
- CalComponent *comp;
-
- comp = cal_component_new ();
-
- switch (cal_backend_get_kind (CAL_BACKEND (backend))) {
- case ICAL_VEVENT_COMPONENT:
- cal_component_set_new_vtype (comp, CAL_COMPONENT_EVENT);
- break;
- case ICAL_VTODO_COMPONENT:
- cal_component_set_new_vtype (comp, CAL_COMPONENT_TODO);
- break;
- case ICAL_VJOURNAL_COMPONENT:
- cal_component_set_new_vtype (comp, CAL_COMPONENT_JOURNAL);
- break;
- default:
- g_object_unref (comp);
- return GNOME_Evolution_Calendar_ObjectNotFound;
- }
-
- *object = cal_component_get_as_string (comp);
- g_object_unref (comp);
-
- return GNOME_Evolution_Calendar_Success;
-}
-
-/* Get_object_component handler for the file backend */
-static CalBackendSyncStatus
-cal_backend_file_get_object (CalBackendSync *backend, Cal *cal, const char *uid, const char *rid, char **object)
-{
- CalBackendFile *cbfile;
- CalBackendFilePrivate *priv;
- CalBackendFileObject *obj_data;
- CalComponent *comp = NULL;
- gboolean free_comp = FALSE;
-
- cbfile = CAL_BACKEND_FILE (backend);
- priv = cbfile->priv;
-
- g_return_val_if_fail (priv->icalcomp != NULL, GNOME_Evolution_Calendar_InvalidObject);
- g_return_val_if_fail (uid != NULL, GNOME_Evolution_Calendar_ObjectNotFound);
- g_assert (priv->comp_uid_hash != NULL);
-
- obj_data = g_hash_table_lookup (priv->comp_uid_hash, uid);
- if (!obj_data)
- return GNOME_Evolution_Calendar_ObjectNotFound;
-
- if (rid && *rid) {
- comp = g_hash_table_lookup (obj_data->recurrences, rid);
- if (!comp) {
- icalcomponent *icalcomp;
- struct icaltimetype itt;
-
- itt = icaltime_from_string (rid);
- icalcomp = cal_util_construct_instance (
- cal_component_get_icalcomponent (obj_data->full_object),
- itt);
- if (!icalcomp)
- return GNOME_Evolution_Calendar_ObjectNotFound;
-
- comp = cal_component_new ();
- free_comp = TRUE;
- cal_component_set_icalcomponent (comp, icalcomp);
- }
- } else
- comp = obj_data->full_object;
-
- if (!comp)
- return GNOME_Evolution_Calendar_ObjectNotFound;
-
- *object = cal_component_get_as_string (comp);
-
- if (free_comp)
- g_object_unref (comp);
-
- return GNOME_Evolution_Calendar_Success;
-}
-
-/* Get_timezone_object handler for the file backend */
-static CalBackendSyncStatus
-cal_backend_file_get_timezone (CalBackendSync *backend, Cal *cal, const char *tzid, char **object)
-{
- CalBackendFile *cbfile;
- CalBackendFilePrivate *priv;
- icaltimezone *zone;
- icalcomponent *icalcomp;
-
- cbfile = CAL_BACKEND_FILE (backend);
- priv = cbfile->priv;
-
- g_return_val_if_fail (priv->icalcomp != NULL, GNOME_Evolution_Calendar_NoSuchCal);
- g_return_val_if_fail (tzid != NULL, GNOME_Evolution_Calendar_ObjectNotFound);
-
- if (!strcmp (tzid, "UTC")) {
- zone = icaltimezone_get_utc_timezone ();
- } else {
- zone = icalcomponent_get_timezone (priv->icalcomp, tzid);
- if (!zone) {
- zone = icaltimezone_get_builtin_timezone_from_tzid (tzid);
- if (!zone)
- return GNOME_Evolution_Calendar_ObjectNotFound;
- }
- }
-
- icalcomp = icaltimezone_get_component (zone);
- if (!icalcomp)
- return GNOME_Evolution_Calendar_InvalidObject;
-
- *object = g_strdup (icalcomponent_as_ical_string (icalcomp));
-
- return GNOME_Evolution_Calendar_Success;
-}
-
-/* Add_timezone handler for the file backend */
-static CalBackendSyncStatus
-cal_backend_file_add_timezone (CalBackendSync *backend, Cal *cal, const char *tzobj)
-{
- icalcomponent *tz_comp;
- CalBackendFile *cbfile;
- CalBackendFilePrivate *priv;
-
- cbfile = (CalBackendFile *) backend;
-
- g_return_val_if_fail (IS_CAL_BACKEND_FILE (cbfile), GNOME_Evolution_Calendar_OtherError);
- g_return_val_if_fail (tzobj != NULL, GNOME_Evolution_Calendar_OtherError);
-
- priv = cbfile->priv;
-
- tz_comp = icalparser_parse_string (tzobj);
- if (!tz_comp)
- return GNOME_Evolution_Calendar_InvalidObject;
-
- if (icalcomponent_isa (tz_comp) == ICAL_VTIMEZONE_COMPONENT) {
- icaltimezone *zone;
-
- zone = icaltimezone_new ();
- icaltimezone_set_component (zone, tz_comp);
- if (!icalcomponent_get_timezone (priv->icalcomp,
- icaltimezone_get_tzid (zone))) {
- icalcomponent_add_component (priv->icalcomp, tz_comp);
- save (cbfile);
- }
-
- icaltimezone_free (zone, 1);
- }
-
- return GNOME_Evolution_Calendar_Success;
-}
-
-
-static CalBackendSyncStatus
-cal_backend_file_set_default_timezone (CalBackendSync *backend, Cal *cal, const char *tzid)
-{
- CalBackendFile *cbfile;
- CalBackendFilePrivate *priv;
- icaltimezone *zone;
-
- cbfile = CAL_BACKEND_FILE (backend);
- priv = cbfile->priv;
-
- g_return_val_if_fail (priv->icalcomp != NULL, GNOME_Evolution_Calendar_NoSuchCal);
-
- /* Look up the VTIMEZONE in our icalcomponent. */
- zone = icalcomponent_get_timezone (priv->icalcomp, tzid);
- if (!zone)
- return GNOME_Evolution_Calendar_ObjectNotFound;
-
- /* Set the default timezone to it. */
- priv->default_zone = zone;
-
- return GNOME_Evolution_Calendar_Success;
-}
-
-typedef struct {
- GList *obj_list;
- gboolean search_needed;
- const char *query;
- CalBackendObjectSExp *obj_sexp;
- CalBackend *backend;
- icaltimezone *default_zone;
-} MatchObjectData;
-
-static void
-match_recurrence_sexp (gpointer key, gpointer value, gpointer data)
-{
- CalComponent *comp = value;
- MatchObjectData *match_data = data;
-
- if ((!match_data->search_needed) ||
- (cal_backend_object_sexp_match_comp (match_data->obj_sexp, comp, match_data->backend))) {
- match_data->obj_list = g_list_append (match_data->obj_list,
- cal_component_get_as_string (comp));
- }
-}
-
-static void
-match_object_sexp (gpointer key, gpointer value, gpointer data)
-{
- CalBackendFileObject *obj_data = value;
- MatchObjectData *match_data = data;
-
- if ((!match_data->search_needed) ||
- (cal_backend_object_sexp_match_comp (match_data->obj_sexp, obj_data->full_object, match_data->backend))) {
- match_data->obj_list = g_list_append (match_data->obj_list,
- cal_component_get_as_string (obj_data->full_object));
-
- /* match also recurrences */
- g_hash_table_foreach (obj_data->recurrences,
- (GHFunc) match_recurrence_sexp,
- match_data);
- }
-}
-
-/* Get_objects_in_range handler for the file backend */
-static CalBackendSyncStatus
-cal_backend_file_get_object_list (CalBackendSync *backend, Cal *cal, const char *sexp, GList **objects)
-{
- CalBackendFile *cbfile;
- CalBackendFilePrivate *priv;
- MatchObjectData match_data;
-
- cbfile = CAL_BACKEND_FILE (backend);
- priv = cbfile->priv;
-
- g_message (G_STRLOC ": Getting object list (%s)", sexp);
-
- match_data.search_needed = TRUE;
- match_data.query = sexp;
- match_data.obj_list = NULL;
- match_data.backend = CAL_BACKEND (backend);
- match_data.default_zone = priv->default_zone;
-
- if (!strcmp (sexp, "#t"))
- match_data.search_needed = FALSE;
-
- match_data.obj_sexp = cal_backend_object_sexp_new (sexp);
- if (!match_data.obj_sexp)
- return GNOME_Evolution_Calendar_InvalidQuery;
-
- g_hash_table_foreach (priv->comp_uid_hash, (GHFunc) match_object_sexp, &match_data);
-
- *objects = match_data.obj_list;
-
- return GNOME_Evolution_Calendar_Success;
-}
-
-/* get_query handler for the file backend */
-static void
-cal_backend_file_start_query (CalBackend *backend, Query *query)
-{
- CalBackendFile *cbfile;
- CalBackendFilePrivate *priv;
- MatchObjectData match_data;
-
- cbfile = CAL_BACKEND_FILE (backend);
- priv = cbfile->priv;
-
- g_message (G_STRLOC ": Starting query (%s)", query_get_text (query));
-
- /* try to match all currently existing objects */
- match_data.search_needed = TRUE;
- match_data.query = query_get_text (query);
- match_data.obj_list = NULL;
- match_data.backend = backend;
- match_data.default_zone = priv->default_zone;
-
- if (!strcmp (match_data.query, "#t"))
- match_data.search_needed = FALSE;
-
- match_data.obj_sexp = query_get_object_sexp (query);
- if (!match_data.obj_sexp) {
- query_notify_query_done (query, GNOME_Evolution_Calendar_InvalidQuery);
- return;
- }
-
- g_hash_table_foreach (priv->comp_uid_hash, (GHFunc) match_object_sexp, &match_data);
-
- /* notify listeners of all objects */
- if (match_data.obj_list) {
- query_notify_objects_added (query, (const GList *) match_data.obj_list);
-
- /* free memory */
- g_list_foreach (match_data.obj_list, (GFunc) g_free, NULL);
- g_list_free (match_data.obj_list);
- }
-
- query_notify_query_done (query, GNOME_Evolution_Calendar_Success);
-}
-
-static gboolean
-free_busy_instance (CalComponent *comp,
- time_t instance_start,
- time_t instance_end,
- gpointer data)
-{
- icalcomponent *vfb = data;
- icalproperty *prop;
- icalparameter *param;
- struct icalperiodtype ipt;
- icaltimezone *utc_zone;
-
- utc_zone = icaltimezone_get_utc_timezone ();
-
- ipt.start = icaltime_from_timet_with_zone (instance_start, FALSE, utc_zone);
- ipt.end = icaltime_from_timet_with_zone (instance_end, FALSE, utc_zone);
- ipt.duration = icaldurationtype_null_duration ();
-
- /* add busy information to the vfb component */
- prop = icalproperty_new (ICAL_FREEBUSY_PROPERTY);
- icalproperty_set_freebusy (prop, ipt);
-
- param = icalparameter_new_fbtype (ICAL_FBTYPE_BUSY);
- icalproperty_add_parameter (prop, param);
-
- icalcomponent_add_property (vfb, prop);
-
- return TRUE;
-}
-
-static icalcomponent *
-create_user_free_busy (CalBackendFile *cbfile, const char *address, const char *cn,
- time_t start, time_t end)
-{
- CalBackendFilePrivate *priv;
- GList *l;
- icalcomponent *vfb;
- icaltimezone *utc_zone;
- CalBackendObjectSExp *obj_sexp;
- char *query;
-
- priv = cbfile->priv;
-
- /* create the (unique) VFREEBUSY object that we'll return */
- vfb = icalcomponent_new_vfreebusy ();
- if (address != NULL) {
- icalproperty *prop;
- icalparameter *param;
-
- prop = icalproperty_new_organizer (address);
- if (prop != NULL && cn != NULL) {
- param = icalparameter_new_cn (cn);
- icalproperty_add_parameter (prop, param);
- }
- if (prop != NULL)
- icalcomponent_add_property (vfb, prop);
- }
- utc_zone = icaltimezone_get_utc_timezone ();
- icalcomponent_set_dtstart (vfb, icaltime_from_timet_with_zone (start, FALSE, utc_zone));
- icalcomponent_set_dtend (vfb, icaltime_from_timet_with_zone (end, FALSE, utc_zone));
-
- /* add all objects in the given interval */
- query = g_strdup_printf ("occur-in-time-range? %lu %lu", start, end);
- obj_sexp = cal_backend_object_sexp_new (query);
- g_free (query);
-
- if (!obj_sexp)
- return vfb;
-
- for (l = priv->comp; l; l = l->next) {
- CalComponent *comp = l->data;
- icalcomponent *icalcomp, *vcalendar_comp;
- icalproperty *prop;
-
- icalcomp = cal_component_get_icalcomponent (comp);
- if (!icalcomp)
- continue;
-
- /* If the event is TRANSPARENT, skip it. */
- prop = icalcomponent_get_first_property (icalcomp,
- ICAL_TRANSP_PROPERTY);
- if (prop) {
- icalproperty_transp transp_val = icalproperty_get_transp (prop);
- if (transp_val == ICAL_TRANSP_TRANSPARENT ||
- transp_val == ICAL_TRANSP_TRANSPARENTNOCONFLICT)
- continue;
- }
-
- if (!cal_backend_object_sexp_match_comp (obj_sexp, l->data, CAL_BACKEND (cbfile)))
- continue;
-
- vcalendar_comp = icalcomponent_get_parent (icalcomp);
- cal_recur_generate_instances (comp, start, end,
- free_busy_instance,
- vfb,
- resolve_tzid,
- vcalendar_comp,
- priv->default_zone);
- }
-
- return vfb;
-}
-
-/* Get_free_busy handler for the file backend */
-static CalBackendSyncStatus
-cal_backend_file_get_free_busy (CalBackendSync *backend, Cal *cal, GList *users,
- time_t start, time_t end, GList **freebusy)
-{
- CalBackendFile *cbfile;
- CalBackendFilePrivate *priv;
- gchar *address, *name;
- icalcomponent *vfb;
- char *calobj;
- GList *l;
-
- cbfile = CAL_BACKEND_FILE (backend);
- priv = cbfile->priv;
-
- g_return_val_if_fail (priv->icalcomp != NULL, GNOME_Evolution_Calendar_NoSuchCal);
- g_return_val_if_fail (start != -1 && end != -1, GNOME_Evolution_Calendar_InvalidRange);
- g_return_val_if_fail (start <= end, GNOME_Evolution_Calendar_InvalidRange);
-
- *freebusy = NULL;
-
- if (users == NULL) {
- if (cal_backend_mail_account_get_default (priv->config_listener, &address, &name)) {
- vfb = create_user_free_busy (cbfile, address, name, start, end);
- calobj = icalcomponent_as_ical_string (vfb);
- *freebusy = g_list_append (*freebusy, g_strdup (calobj));
- icalcomponent_free (vfb);
- g_free (address);
- g_free (name);
- }
- } else {
- for (l = users; l != NULL; l = l->next ) {
- address = l->data;
- if (cal_backend_mail_account_is_valid (priv->config_listener, address, &name)) {
- vfb = create_user_free_busy (cbfile, address, name, start, end);
- calobj = icalcomponent_as_ical_string (vfb);
- *freebusy = g_list_append (*freebusy, g_strdup (calobj));
- icalcomponent_free (vfb);
- g_free (name);
- }
- }
- }
-
- return GNOME_Evolution_Calendar_Success;
-}
-
-typedef struct
-{
- CalBackendFile *backend;
- icalcomponent_kind kind;
- GList *deletes;
- EXmlHash *ehash;
-} CalBackendFileComputeChangesData;
-
-static void
-cal_backend_file_compute_changes_foreach_key (const char *key, gpointer data)
-{
- CalBackendFileComputeChangesData *be_data = data;
-
- if (!lookup_component (be_data->backend, key)) {
- CalComponent *comp;
-
- comp = cal_component_new ();
- if (be_data->kind == ICAL_VTODO_COMPONENT)
- cal_component_set_new_vtype (comp, CAL_COMPONENT_TODO);
- else
- cal_component_set_new_vtype (comp, CAL_COMPONENT_EVENT);
-
- cal_component_set_uid (comp, key);
- be_data->deletes = g_list_prepend (be_data->deletes, cal_component_get_as_string (comp));
-
- e_xmlhash_remove (be_data->ehash, key);
- }
-}
-
-static CalBackendSyncStatus
-cal_backend_file_compute_changes (CalBackendFile *cbfile, const char *change_id,
- GList **adds, GList **modifies, GList **deletes)
-{
- CalBackendFilePrivate *priv;
- char *filename;
- EXmlHash *ehash;
- CalBackendFileComputeChangesData be_data;
- GList *i;
-
- priv = cbfile->priv;
-
- /* FIXME Will this always work? */
- filename = g_strdup_printf ("%s/%s.db", priv->uri, change_id);
- ehash = e_xmlhash_new (filename);
- g_free (filename);
-
- /* Calculate adds and modifies */
- for (i = priv->comp; i != NULL; i = i->next) {
- const char *uid;
- char *calobj;
-
- cal_component_get_uid (i->data, &uid);
- calobj = cal_component_get_as_string (i->data);
-
- g_assert (calobj != NULL);
-
- /* check what type of change has occurred, if any */
- switch (e_xmlhash_compare (ehash, uid, calobj)) {
- case E_XMLHASH_STATUS_SAME:
- break;
- case E_XMLHASH_STATUS_NOT_FOUND:
- *adds = g_list_prepend (*adds, g_strdup (calobj));
- e_xmlhash_add (ehash, uid, calobj);
- break;
- case E_XMLHASH_STATUS_DIFFERENT:
- *modifies = g_list_prepend (*modifies, g_strdup (calobj));
- e_xmlhash_add (ehash, uid, calobj);
- break;
- }
-
- g_free (calobj);
- }
-
- /* Calculate deletions */
- be_data.backend = cbfile;
- be_data.kind = cal_backend_get_kind (CAL_BACKEND (cbfile));
- be_data.deletes = NULL;
- be_data.ehash = ehash;
- e_xmlhash_foreach_key (ehash, (EXmlHashFunc)cal_backend_file_compute_changes_foreach_key, &be_data);
-
- *deletes = be_data.deletes;
-
- e_xmlhash_write (ehash);
- e_xmlhash_destroy (ehash);
-
- return GNOME_Evolution_Calendar_Success;
-}
-
-/* Get_changes handler for the file backend */
-static CalBackendSyncStatus
-cal_backend_file_get_changes (CalBackendSync *backend, Cal *cal, const char *change_id,
- GList **adds, GList **modifies, GList **deletes)
-{
- CalBackendFile *cbfile;
- CalBackendFilePrivate *priv;
-
- cbfile = CAL_BACKEND_FILE (backend);
- priv = cbfile->priv;
-
- g_return_val_if_fail (priv->icalcomp != NULL, GNOME_Evolution_Calendar_NoSuchCal);
- g_return_val_if_fail (change_id != NULL, GNOME_Evolution_Calendar_ObjectNotFound);
-
- return cal_backend_file_compute_changes (cbfile, change_id, adds, modifies, deletes);
-}
-
-/* Discard_alarm handler for the file backend */
-static CalBackendSyncStatus
-cal_backend_file_discard_alarm (CalBackendSync *backend, Cal *cal, const char *uid, const char *auid)
-{
- /* we just do nothing with the alarm */
- return GNOME_Evolution_Calendar_Success;
-}
-
-static CalBackendSyncStatus
-cal_backend_file_create_object (CalBackendSync *backend, Cal *cal, const char *calobj, char **uid)
-{
- CalBackendFile *cbfile;
- CalBackendFilePrivate *priv;
- icalcomponent *icalcomp;
- icalcomponent_kind kind;
- CalComponent *comp;
- const char *comp_uid;
- struct icaltimetype current;
-
- cbfile = CAL_BACKEND_FILE (backend);
- priv = cbfile->priv;
-
- g_return_val_if_fail (priv->icalcomp != NULL, GNOME_Evolution_Calendar_NoSuchCal);
- g_return_val_if_fail (calobj != NULL, GNOME_Evolution_Calendar_ObjectNotFound);
-
- icalcomp = icalparser_parse_string ((char *) calobj);
- if (!icalcomp)
- return GNOME_Evolution_Calendar_InvalidObject;
-
- /* FIXME Check kind with the parent */
- kind = icalcomponent_isa (icalcomp);
- if (kind != ICAL_VEVENT_COMPONENT && kind != ICAL_VTODO_COMPONENT) {
- icalcomponent_free (icalcomp);
- return GNOME_Evolution_Calendar_InvalidObject;
- }
-
- /* Get the UID */
- comp_uid = icalcomponent_get_uid (icalcomp);
-
- /* check the object is not in our cache */
- if (lookup_component (cbfile, comp_uid)) {
- icalcomponent_free (icalcomp);
- return GNOME_Evolution_Calendar_CardIdAlreadyExists;
- }
-
- /* Create the cal component */
- comp = cal_component_new ();
- cal_component_set_icalcomponent (comp, icalcomp);
-
- /* Set the created and last modified times on the component */
- current = icaltime_from_timet (time (NULL), 0);
- cal_component_set_created (comp, &current);
- cal_component_set_last_modified (comp, &current);
-
- /* Add the object */
- add_component (cbfile, comp, TRUE);
-
- /* Save the file */
- save (cbfile);
-
- /* Return the UID */
- if (uid)
- *uid = g_strdup (comp_uid);
-
- return GNOME_Evolution_Calendar_Success;
-}
-
-static CalBackendSyncStatus
-cal_backend_file_modify_object (CalBackendSync *backend, Cal *cal, const char *calobj,
- CalObjModType mod, char **old_object)
-{
- CalBackendFile *cbfile;
- CalBackendFilePrivate *priv;
- icalcomponent *icalcomp;
- icalcomponent_kind kind;
- const char *comp_uid, *rid;
- char *real_rid;
- CalComponent *comp, *recurrence;
- CalBackendFileObject *obj_data;
- struct icaltimetype current;
-
- cbfile = CAL_BACKEND_FILE (backend);
- priv = cbfile->priv;
-
- g_return_val_if_fail (priv->icalcomp != NULL, GNOME_Evolution_Calendar_NoSuchCal);
- g_return_val_if_fail (calobj != NULL, GNOME_Evolution_Calendar_ObjectNotFound);
-
- icalcomp = icalparser_parse_string ((char *) calobj);
- if (!icalcomp)
- return GNOME_Evolution_Calendar_InvalidObject;
-
- /* check kind with the parent */
- kind = icalcomponent_isa (icalcomp);
- if (kind != ICAL_VEVENT_COMPONENT && kind != ICAL_VTODO_COMPONENT) {
- icalcomponent_free (icalcomp);
- return GNOME_Evolution_Calendar_InvalidObject;
- }
-
- /* Get the uid */
- comp_uid = icalcomponent_get_uid (icalcomp);
-
- /* Get the object from our cache */
- if (!(obj_data = g_hash_table_lookup (priv->comp_uid_hash, comp_uid))) {
- icalcomponent_free (icalcomp);
- return GNOME_Evolution_Calendar_ObjectNotFound;
- }
-
- /* Create the cal component */
- comp = cal_component_new ();
- cal_component_set_icalcomponent (comp, icalcomp);
-
- /* Set the last modified time on the component */
- current = icaltime_from_timet (time (NULL), 0);
- cal_component_set_last_modified (comp, &current);
-
- /* handle mod_type */
- switch (mod) {
- case CALOBJ_MOD_THIS :
- rid = get_rid_string (comp);
- if (!rid || !*rid) {
- g_object_unref (comp);
- return GNOME_Evolution_Calendar_ObjectNotFound;
- }
-
- if (g_hash_table_lookup_extended (obj_data->recurrences, rid,
- &real_rid, &recurrence)) {
- /* remove the component from our data */
- icalcomponent_remove_component (priv->icalcomp,
- cal_component_get_icalcomponent (recurrence));
- priv->comp = g_list_remove (priv->comp, recurrence);
- g_hash_table_remove (obj_data->recurrences, rid);
-
- /* free memory */
- g_free (real_rid);
- g_object_unref (recurrence);
- } else {
- char *old, *new;
-
- old = cal_component_get_as_string (obj_data->full_object);
-
- cal_util_remove_instances (cal_component_get_icalcomponent (obj_data->full_object),
- get_rid_icaltime (comp),
- mod);
-
- new = cal_component_get_as_string (obj_data->full_object);
-
- cal_backend_notify_object_modified (CAL_BACKEND (backend), old, new);
-
- g_free (old);
- g_free (new);
- }
-
- /* add the detached instance */
- g_hash_table_insert (obj_data->recurrences, g_strdup (get_rid_string (comp)), comp);
- break;
- case CALOBJ_MOD_THISANDPRIOR :
- break;
- case CALOBJ_MOD_THISANDFUTURE :
- break;
- case CALOBJ_MOD_ALL :
- /* in this case, we blow away all recurrences, and start over
- with a clean component */
- /* Remove the old version */
- remove_component (cbfile, obj_data->full_object);
-
- /* Add the new object */
- add_component (cbfile, comp, TRUE);
- break;
- }
-
- save (cbfile);
-
- if (old_object)
- *old_object = cal_component_get_as_string (comp);
-
- return GNOME_Evolution_Calendar_Success;
-}
-
-static void
-remove_instance (CalBackendFile *cbfile, CalBackendFileObject *obj_data, const char *rid)
-{
- char *hash_rid;
- CalComponent *comp;
- GSList *categories;
-
- if (!rid || !*rid)
- return;
-
- if (g_hash_table_lookup_extended (obj_data->recurrences, rid, &hash_rid, &comp)) {
- /* remove the component from our data */
- icalcomponent_remove_component (cbfile->priv->icalcomp,
- cal_component_get_icalcomponent (comp));
- cbfile->priv->comp = g_list_remove (cbfile->priv->comp, comp);
- g_hash_table_remove (obj_data->recurrences, rid);
-
- /* update the set of categories */
- cal_component_get_categories_list (comp, &categories);
- cal_backend_unref_categories (CAL_BACKEND (cbfile), categories);
- cal_component_free_categories_list (categories);
-
- /* free memory */
- g_free (hash_rid);
- g_object_unref (comp);
-
- return;
- }
-
- /* remove the component from our data, temporarily */
- icalcomponent_remove_component (cbfile->priv->icalcomp,
- cal_component_get_icalcomponent (obj_data->full_object));
- cbfile->priv->comp = g_list_remove (cbfile->priv->comp, obj_data->full_object);
-
- cal_util_remove_instances (cal_component_get_icalcomponent (obj_data->full_object),
- icaltime_from_string (rid), CALOBJ_MOD_THIS);
-
- /* add the modified object to the beginning of the list,
- so that it's always before any detached instance we
- might have */
- cbfile->priv->comp = g_list_prepend (cbfile->priv->comp, obj_data->full_object);
-}
-
-typedef struct {
- CalBackendFile *cbfile;
- CalBackendFileObject *obj_data;
- const char *rid;
- CalObjModType mod;
-} RemoveRecurrenceData;
-
-static gboolean
-remove_object_instance_cb (gpointer key, gpointer value, gpointer user_data)
-{
- time_t fromtt, instancett;
- GSList *categories;
- char *rid = key;
- CalComponent *instance = value;
- RemoveRecurrenceData *rrdata = user_data;
-
- fromtt = icaltime_as_timet (icaltime_from_string (rrdata->rid));
- instancett = icaltime_as_timet (get_rid_icaltime (instance));
-
- if (fromtt > 0 && instancett > 0) {
- if ((rrdata->mod == CALOBJ_MOD_THISANDPRIOR && instancett <= fromtt) ||
- (rrdata->mod == CALOBJ_MOD_THISANDFUTURE && instancett >= fromtt)) {
- /* remove the component from our data */
- icalcomponent_remove_component (rrdata->cbfile->priv->icalcomp,
- cal_component_get_icalcomponent (instance));
- rrdata->cbfile->priv->comp = g_list_remove (rrdata->cbfile->priv->comp, instance);
-
- /* update the set of categories */
- cal_component_get_categories_list (instance, &categories);
- cal_backend_unref_categories (CAL_BACKEND (rrdata->cbfile), categories);
- cal_component_free_categories_list (categories);
-
- /* free memory */
- g_free (rid);
- g_object_unref (instance);
-
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-/* Remove_object handler for the file backend */
-static CalBackendSyncStatus
-cal_backend_file_remove_object (CalBackendSync *backend, Cal *cal,
- const char *uid, const char *rid,
- CalObjModType mod, char **object)
-{
- CalBackendFile *cbfile;
- CalBackendFilePrivate *priv;
- CalBackendFileObject *obj_data;
- CalComponent *comp;
- GSList *categories;
- RemoveRecurrenceData rrdata;
-
- cbfile = CAL_BACKEND_FILE (backend);
- priv = cbfile->priv;
-
- g_return_val_if_fail (priv->icalcomp != NULL, GNOME_Evolution_Calendar_NoSuchCal);
- g_return_val_if_fail (uid != NULL, GNOME_Evolution_Calendar_ObjectNotFound);
-
- obj_data = g_hash_table_lookup (priv->comp_uid_hash, uid);
- if (!obj_data)
- return GNOME_Evolution_Calendar_ObjectNotFound;
-
- comp = obj_data->full_object;
-
- switch (mod) {
- case CALOBJ_MOD_ALL :
- *object = cal_component_get_as_string (comp);
- remove_component (cbfile, comp);
- break;
- case CALOBJ_MOD_THIS :
- if (!rid || !*rid)
- return GNOME_Evolution_Calendar_ObjectNotFound;
-
- remove_instance (cbfile, obj_data, rid);
- break;
- case CALOBJ_MOD_THISANDPRIOR :
- case CALOBJ_MOD_THISANDFUTURE :
- if (!rid || !*rid)
- return GNOME_Evolution_Calendar_ObjectNotFound;
-
- /* remove the component from our data, temporarily */
- icalcomponent_remove_component (priv->icalcomp,
- cal_component_get_icalcomponent (comp));
- priv->comp = g_list_remove (priv->comp, comp);
-
- cal_util_remove_instances (cal_component_get_icalcomponent (comp),
- icaltime_from_string (rid), mod);
-
- /* now remove all detached instances */
- rrdata.cbfile = cbfile;
- rrdata.obj_data = obj_data;
- rrdata.rid = rid;
- rrdata.mod = mod;
- g_hash_table_foreach_remove (obj_data->recurrences, (GHRFunc) remove_object_instance_cb, &rrdata);
-
- /* add the modified object to the beginning of the list,
- so that it's always before any detached instance we
- might have */
- priv->comp = g_list_prepend (priv->comp, comp);
- break;
- }
-
- save (cbfile);
-
- return GNOME_Evolution_Calendar_Success;
-}
-
-static gboolean
-cancel_received_object (CalBackendFile *cbfile, icalcomponent *icalcomp)
-{
- CalComponent *old_comp;
-
- /* Find the old version of the component. */
- old_comp = lookup_component (cbfile, icalcomponent_get_uid (icalcomp));
- if (!old_comp)
- return FALSE;
-
- /* And remove it */
- remove_component (cbfile, old_comp);
-
- return TRUE;
-}
-
-typedef struct {
- GHashTable *zones;
-
- gboolean found;
-} CalBackendFileTzidData;
-
-static void
-check_tzids (icalparameter *param, void *data)
-{
- CalBackendFileTzidData *tzdata = data;
- const char *tzid;
-
- tzid = icalparameter_get_tzid (param);
- if (!tzid || g_hash_table_lookup (tzdata->zones, tzid))
- tzdata->found = FALSE;
-}
-
-/* Update_objects handler for the file backend. */
-static CalBackendSyncStatus
-cal_backend_file_receive_objects (CalBackendSync *backend, Cal *cal, const char *calobj)
-{
- CalBackendFile *cbfile;
- CalBackendFilePrivate *priv;
- icalcomponent *toplevel_comp, *icalcomp = NULL;
- icalcomponent_kind kind;
- icalproperty_method method;
- icalcomponent *subcomp;
- GList *comps, *l;
- CalBackendFileTzidData tzdata;
- CalBackendSyncStatus status = GNOME_Evolution_Calendar_Success;
-
- cbfile = CAL_BACKEND_FILE (backend);
- priv = cbfile->priv;
-
- g_return_val_if_fail (priv->icalcomp != NULL, GNOME_Evolution_Calendar_InvalidObject);
- g_return_val_if_fail (calobj != NULL, GNOME_Evolution_Calendar_InvalidObject);
-
- /* Pull the component from the string and ensure that it is sane */
- toplevel_comp = icalparser_parse_string ((char *) calobj);
- if (!toplevel_comp)
- return GNOME_Evolution_Calendar_InvalidObject;
-
- kind = icalcomponent_isa (toplevel_comp);
- if (kind != ICAL_VCALENDAR_COMPONENT) {
- /* If its not a VCALENDAR, make it one to simplify below */
- icalcomp = toplevel_comp;
- toplevel_comp = cal_util_new_top_level ();
- icalcomponent_add_component (toplevel_comp, icalcomp);
- }
-
- method = icalcomponent_get_method (toplevel_comp);
-
- /* Build a list of timezones so we can make sure all the objects have valid info */
- tzdata.zones = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
-
- subcomp = icalcomponent_get_first_component (toplevel_comp, ICAL_VTIMEZONE_COMPONENT);
- while (subcomp) {
- icaltimezone *zone;
-
- zone = icaltimezone_new ();
- if (icaltimezone_set_component (zone, subcomp))
- g_hash_table_insert (tzdata.zones, g_strdup (icaltimezone_get_tzid (zone)), NULL);
-
- subcomp = icalcomponent_get_next_component (toplevel_comp, ICAL_VTIMEZONE_COMPONENT);
- }
-
- /* First we make sure all the components are usuable */
- comps = NULL;
- subcomp = icalcomponent_get_first_component (toplevel_comp, ICAL_ANY_COMPONENT);
- while (subcomp) {
- /* We ignore anything except VEVENT, VTODO and VJOURNAL
- components. */
- icalcomponent_kind child_kind = icalcomponent_isa (subcomp);
-
- switch (child_kind) {
- case ICAL_VEVENT_COMPONENT:
- case ICAL_VTODO_COMPONENT:
- case ICAL_VJOURNAL_COMPONENT:
- tzdata.found = TRUE;
- icalcomponent_foreach_tzid (subcomp, check_tzids, &tzdata);
-
- if (!tzdata.found) {
- status = GNOME_Evolution_Calendar_InvalidObject;
- goto error;
- }
-
- if (!icalcomponent_get_uid (subcomp)) {
- status = GNOME_Evolution_Calendar_InvalidObject;
- goto error;
- }
-
- comps = g_list_prepend (comps, subcomp);
- break;
- default:
- /* Ignore it */
- break;
- }
-
- subcomp = icalcomponent_get_next_component (toplevel_comp, ICAL_ANY_COMPONENT);
- }
-
- /* Now we manipulate the components we care about */
- for (l = comps; l; l = l->next) {
- subcomp = l->data;
-
- switch (method) {
- case ICAL_METHOD_PUBLISH:
- case ICAL_METHOD_REQUEST:
- /* FIXME Need to see the new create/modify stuff before we set this up */
- break;
- case ICAL_METHOD_REPLY:
- /* FIXME Update the status of the user, if we are the organizer */
- break;
- case ICAL_METHOD_ADD:
- /* FIXME This should be doable once all the recurid stuff is done */
- break;
- case ICAL_METHOD_COUNTER:
- status = GNOME_Evolution_Calendar_UnsupportedMethod;
- goto error;
- break;
- case ICAL_METHOD_DECLINECOUNTER:
- status = GNOME_Evolution_Calendar_UnsupportedMethod;
- goto error;
- break;
- case ICAL_METHOD_CANCEL:
- /* FIXME Do we need to remove the subcomp so it isn't merged? */
- if (cancel_received_object (cbfile, subcomp)) {
- const char *calobj = icalcomponent_as_ical_string (subcomp);
- cal_backend_notify_object_removed (CAL_BACKEND (backend), icalcomponent_get_uid (subcomp), calobj);
- }
- break;
- default:
- status = GNOME_Evolution_Calendar_UnsupportedMethod;
- goto error;
- }
- }
- g_list_free (comps);
-
- /* Merge the iCalendar components with our existing VCALENDAR,
- resolving any conflicting TZIDs. */
- icalcomponent_merge_component (priv->icalcomp, toplevel_comp);
-
- save (cbfile);
-
- error:
- g_hash_table_destroy (tzdata.zones);
-
- return status;
-}
-
-static CalBackendSyncStatus
-cal_backend_file_send_objects (CalBackendSync *backend, Cal *cal, const char *calobj)
-{
- /* FIXME Put in a util routine to send stuff via email */
-
- return GNOME_Evolution_Calendar_Success;
-}
-
-static icaltimezone *
-cal_backend_file_internal_get_default_timezone (CalBackend *backend)
-{
- CalBackendFile *cbfile;
- CalBackendFilePrivate *priv;
-
- cbfile = CAL_BACKEND_FILE (backend);
- priv = cbfile->priv;
-
- g_return_val_if_fail (priv->icalcomp != NULL, NULL);
-
- return priv->default_zone;
-}
-
-static icaltimezone *
-cal_backend_file_internal_get_timezone (CalBackend *backend, const char *tzid)
-{
- CalBackendFile *cbfile;
- CalBackendFilePrivate *priv;
- icaltimezone *zone;
-
- cbfile = CAL_BACKEND_FILE (backend);
- priv = cbfile->priv;
-
- g_return_val_if_fail (priv->icalcomp != NULL, NULL);
-
- if (!strcmp (tzid, "UTC"))
- zone = icaltimezone_get_utc_timezone ();
- else {
- zone = icalcomponent_get_timezone (priv->icalcomp, tzid);
- if (!zone)
- zone = icaltimezone_get_builtin_timezone_from_tzid (tzid);
- }
-
- return zone;
-}
-
-/* Object initialization function for the file backend */
-static void
-cal_backend_file_init (CalBackendFile *cbfile, CalBackendFileClass *class)
-{
- CalBackendFilePrivate *priv;
-
- priv = g_new0 (CalBackendFilePrivate, 1);
- cbfile->priv = priv;
-
- priv->uri = NULL;
- priv->file_name = g_strdup ("calendar.ics");
- priv->read_only = FALSE;
- priv->icalcomp = NULL;
- priv->comp_uid_hash = NULL;
- priv->comp = NULL;
-
- /* The timezone defaults to UTC. */
- priv->default_zone = icaltimezone_get_utc_timezone ();
-
- priv->config_listener = e_config_listener_new ();
-}
-
-/* Class initialization function for the file backend */
-static void
-cal_backend_file_class_init (CalBackendFileClass *class)
-{
- GObjectClass *object_class;
- CalBackendClass *backend_class;
- CalBackendSyncClass *sync_class;
-
- object_class = (GObjectClass *) class;
- backend_class = (CalBackendClass *) class;
- sync_class = (CalBackendSyncClass *) class;
-
- parent_class = (CalBackendSyncClass *) g_type_class_peek_parent (class);
-
- object_class->dispose = cal_backend_file_dispose;
- object_class->finalize = cal_backend_file_finalize;
-
- sync_class->is_read_only_sync = cal_backend_file_is_read_only;
- sync_class->get_cal_address_sync = cal_backend_file_get_cal_address;
- sync_class->get_alarm_email_address_sync = cal_backend_file_get_alarm_email_address;
- sync_class->get_ldap_attribute_sync = cal_backend_file_get_ldap_attribute;
- sync_class->get_static_capabilities_sync = cal_backend_file_get_static_capabilities;
- sync_class->open_sync = cal_backend_file_open;
- sync_class->remove_sync = cal_backend_file_remove;
- sync_class->create_object_sync = cal_backend_file_create_object;
- sync_class->modify_object_sync = cal_backend_file_modify_object;
- sync_class->remove_object_sync = cal_backend_file_remove_object;
- sync_class->discard_alarm_sync = cal_backend_file_discard_alarm;
- sync_class->receive_objects_sync = cal_backend_file_receive_objects;
- sync_class->send_objects_sync = cal_backend_file_send_objects;
- sync_class->get_default_object_sync = cal_backend_file_get_default_object;
- sync_class->get_object_sync = cal_backend_file_get_object;
- sync_class->get_object_list_sync = cal_backend_file_get_object_list;
- sync_class->get_timezone_sync = cal_backend_file_get_timezone;
- sync_class->add_timezone_sync = cal_backend_file_add_timezone;
- sync_class->set_default_timezone_sync = cal_backend_file_set_default_timezone;
- sync_class->get_freebusy_sync = cal_backend_file_get_free_busy;
- sync_class->get_changes_sync = cal_backend_file_get_changes;
-
- backend_class->is_loaded = cal_backend_file_is_loaded;
- backend_class->start_query = cal_backend_file_start_query;
- backend_class->get_mode = cal_backend_file_get_mode;
- backend_class->set_mode = cal_backend_file_set_mode;
-
- backend_class->internal_get_default_timezone = cal_backend_file_internal_get_default_timezone;
- backend_class->internal_get_timezone = cal_backend_file_internal_get_timezone;
-}
-
-
-/**
- * cal_backend_file_get_type:
- * @void:
- *
- * Registers the #CalBackendFile class if necessary, and returns the type ID
- * associated to it.
- *
- * Return value: The type ID of the #CalBackendFile class.
- **/
-GType
-cal_backend_file_get_type (void)
-{
- static GType cal_backend_file_type = 0;
-
- if (!cal_backend_file_type) {
- static GTypeInfo info = {
- sizeof (CalBackendFileClass),
- (GBaseInitFunc) NULL,
- (GBaseFinalizeFunc) NULL,
- (GClassInitFunc) cal_backend_file_class_init,
- NULL, NULL,
- sizeof (CalBackendFile),
- 0,
- (GInstanceInitFunc) cal_backend_file_init
- };
- cal_backend_file_type = g_type_register_static (CAL_TYPE_BACKEND_SYNC,
- "CalBackendFile", &info, 0);
- }
-
- return cal_backend_file_type;
-}
-
-void
-cal_backend_file_set_file_name (CalBackendFile *cbfile, const char *file_name)
-{
- CalBackendFilePrivate *priv;
-
- g_return_if_fail (cbfile != NULL);
- g_return_if_fail (IS_CAL_BACKEND_FILE (cbfile));
- g_return_if_fail (file_name != NULL);
-
- priv = cbfile->priv;
-
- if (priv->file_name)
- g_free (priv->file_name);
-
- priv->file_name = g_strdup (file_name);
-}
-
-const char *
-cal_backend_file_get_file_name (CalBackendFile *cbfile)
-{
- CalBackendFilePrivate *priv;
-
- g_return_val_if_fail (cbfile != NULL, NULL);
- g_return_val_if_fail (IS_CAL_BACKEND_FILE (cbfile), NULL);
-
- priv = cbfile->priv;
-
- return priv->file_name;
-}