From 58b5fd92fc9f5419beabe82d38622aba064cc56e Mon Sep 17 00:00:00 2001 From: JP Rosevear Date: Tue, 19 Sep 2000 22:48:47 +0000 Subject: Add some other cases where a slow sync is in order (pre_sync): Pre load 2000-09-19 JP Rosevear * conduits/todo/todo-conduit.c (check_for_slow_setting): Add some other cases where a slow sync is in order (pre_sync): Pre load the uids, the map and the add/mod/del lists (match_record): Use the map hash to match records (iterate): Iterate using the pre-loaded uid list (iterate_specific): Iterate using the add/mod/del lists (purge): Delete all entries in the del list (set_status): Set status by adding to an appropriate list (set_pilot_id): Set pilot_id by updating map hash * conduits/todo/todo-conduit.h: Add lists for added, modified and deleted objects * conduits/todo/todo-conduit.c (map_name): Get the pilot_id->uid map file name (map_sax_start_element): SAX handler to extract a pilot_id->uid mapping (map_sax_parse): Parse the given file and build a pilot_id->uid hash (map_write_foreach): Write out individual mapping elements (map_write): Write out the pilot_id->uid mapping (start_calendar_server_cb): Rename from gnome_calendar_load_cb * conduits/todo/todo-conduit-config.h: Rename pilotID to pilot_id * conduits/todo/e-todo.conduit.in: A little renaming * conduits/todo/Makefile.am: Fix build slightly * pcs/cal.c (build_change_seq): Build a corba sequence out of a list of CalObjChanges (Cal_get_objects_in_range): Implement new corba function * pcs/cal-backend.c (cal_backend_init): Intiliaze to NULL (cal_backend_load): Track the uri so we can write the log file to the same place (cal_backend_log_name): Figure out the log filename/path based on the calendar uri (cal_backend_set_node_timet): Set an xml node property value from a time_t (cal_backend_log_entry): Adds a log entry to list waiting to be written out (cal_backend_log_sync): Syncs the log entries to disk (cal_backend_log_sax_start_element): SAX callback for reading in log entries (cal_backend_log_sax_end_element): ditto (cal_backend_log_sax_parse): Main SAX parser call to parse the log file looking for particular log entries and creating a CalObjChange hash with the last change for each object (cal_backend_get_log_entries): Returns a hash of objects of a given type changed since the given time (cal_backend_update_object): Add appropriate log entries (cal_backend_remove_object): ditto (cal_backend_get_changed_uids): Implement new idl interface call (cal_backend_foreach_changed): Convert CalObjChange hash into a list * pcs/cal-backend-imc.[hc]: Remove crufty files * pcs/cal-backend-file.c (cal_backend_file_get_type_by_uid): New function that returns the CalObjType for a uid. * cal-client/cal-client.h: Update prototypes. * cal-client/cal-client.c (build_change_list): Build a list of CalObjChange items from a corba sequence. (cal_client_get_changed_uids): New accessor method for the similarly named addition to the idl file. * cal-util/cal-util.h: Update prototypes and add CalObjChangeType enum. * cal-util/cal-util.c (cal_obj_change_list_free): New utility method to free a list of CalObjChange objects. * idl/evolution-calendar.idl: Add get_changed_uids method and associated types. svn path=/trunk/; revision=5512 --- calendar/pcs/cal-backend-file.c | 30 + calendar/pcs/cal-backend-imc.c | 1421 --------------------------------------- calendar/pcs/cal-backend-imc.h | 61 -- calendar/pcs/cal-backend.c | 380 ++++++++++- calendar/pcs/cal-backend.h | 8 + calendar/pcs/cal.c | 58 ++ 6 files changed, 471 insertions(+), 1487 deletions(-) delete mode 100644 calendar/pcs/cal-backend-imc.c delete mode 100644 calendar/pcs/cal-backend-imc.h (limited to 'calendar/pcs') diff --git a/calendar/pcs/cal-backend-file.c b/calendar/pcs/cal-backend-file.c index 06b75d52a6..c4a047a262 100644 --- a/calendar/pcs/cal-backend-file.c +++ b/calendar/pcs/cal-backend-file.c @@ -77,6 +77,7 @@ static void cal_backend_file_create (CalBackend *backend, GnomeVFSURI *uri); static int cal_backend_file_get_n_objects (CalBackend *backend, CalObjType type); static char *cal_backend_file_get_object (CalBackend *backend, const char *uid); +static CalObjType cal_backend_file_get_type_by_uid (CalBackend *backend, const char *uid); static GList *cal_backend_file_get_uids (CalBackend *backend, CalObjType type); static GList *cal_backend_file_get_objects_in_range (CalBackend *backend, CalObjType type, time_t start, time_t end); @@ -150,6 +151,7 @@ cal_backend_file_class_init (CalBackendFileClass *class) backend_class->create = cal_backend_file_create; backend_class->get_n_objects = cal_backend_file_get_n_objects; backend_class->get_object = cal_backend_file_get_object; + backend_class->get_type_by_uid = cal_backend_file_get_type_by_uid; backend_class->get_uids = cal_backend_file_get_uids; backend_class->get_objects_in_range = cal_backend_file_get_objects_in_range; backend_class->get_alarms_in_range = cal_backend_file_get_alarms_in_range; @@ -791,6 +793,34 @@ cal_backend_file_get_object (CalBackend *backend, const char *uid) return cal_component_get_as_string (comp); } +static CalObjType +cal_backend_file_get_type_by_uid (CalBackend *backend, const char *uid) +{ + CalBackendFile *cbfile; + CalBackendFilePrivate *priv; + CalComponent *comp; + CalComponentVType type; + + cbfile = CAL_BACKEND_FILE (backend); + priv = cbfile->priv; + + comp = lookup_component (cbfile, uid); + if (!comp) + return CAL_COMPONENT_NO_TYPE; + + type = cal_component_get_vtype (comp); + switch (type) { + case CAL_COMPONENT_EVENT: + return CALOBJ_TYPE_EVENT; + case CAL_COMPONENT_TODO: + return CALOBJ_TYPE_TODO; + case CAL_COMPONENT_JOURNAL: + return CALOBJ_TYPE_JOURNAL; + default: + return CAL_COMPONENT_NO_TYPE; + } +} + /* Builds a list of UIDs from a list of CalComponent objects */ static void build_uids_list (GList **list, GList *components) diff --git a/calendar/pcs/cal-backend-imc.c b/calendar/pcs/cal-backend-imc.c deleted file mode 100644 index d50fc0d347..0000000000 --- a/calendar/pcs/cal-backend-imc.c +++ /dev/null @@ -1,1421 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ -/* Evolution calendar - Internet Mail Consortium formats backend - * - * Copyright (C) 2000 Helix Code, Inc. - * - * Authors: Federico Mena-Quintero - * Seth Alves - * Miguel de Icaza - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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 -#include -#include "cal-backend-imc.h" -#include "cal-util/icalendar.h" - - - -/* Supported calendar formats from the IMC */ -typedef enum { - CAL_FORMAT_UNKNOWN, - CAL_FORMAT_VCALENDAR, - CAL_FORMAT_ICALENDAR -} CalendarFormat; - -/* Private part of the CalBackendIMC structure */ -typedef struct { - /* URI where the calendar data is stored */ - GnomeVFSURI *uri; - - /* Format of this calendar (iCalendar or vCalendar) */ - CalendarFormat format; - - /* List of Cal objects with their listeners */ - GList *clients; - - /* All the iCalObject structures in the calendar, hashed by UID. The - * hash key *is* icalobj->uid; it is not copied, so don't free it when - * you remove an object from the hash table. - */ - GHashTable *object_hash; - - /* All events, TODOs, and journals in the calendar */ - GList *events; - GList *todos; - GList *journals; - - /* Whether a calendar has been loaded */ - guint loaded : 1; - - /* Do we need to sync to permanent storage? */ - gboolean dirty : 1; -} IMCPrivate; - - - -static void cal_backend_imc_class_init (CalBackendIMCClass *class); -static void cal_backend_imc_init (CalBackendIMC *bimc); -static void cal_backend_imc_destroy (GtkObject *object); - -static GnomeVFSURI *cal_backend_imc_get_uri (CalBackend *backend); -static void cal_backend_imc_add_cal (CalBackend *backend, Cal *cal); -static CalBackendLoadStatus cal_backend_imc_load (CalBackend *backend, GnomeVFSURI *uri); -static void cal_backend_imc_create (CalBackend *backend, GnomeVFSURI *uri); - -static int cal_backend_imc_get_n_objects (CalBackend *backend, CalObjType type); -static char *cal_backend_imc_get_object (CalBackend *backend, const char *uid); -static GList *cal_backend_imc_get_uids (CalBackend *backend, CalObjType type); -static GList *cal_backend_imc_get_events_in_range (CalBackend *backend, time_t start, time_t end); -static GList *cal_backend_imc_get_alarms_in_range (CalBackend *backend, time_t start, time_t end); -static gboolean cal_backend_imc_get_alarms_for_object (CalBackend *backend, const char *uid, - time_t start, time_t end, - GList **alarms); -static gboolean cal_backend_imc_update_object (CalBackend *backend, const char *uid, - const char *calobj); -static gboolean cal_backend_imc_remove_object (CalBackend *backend, const char *uid); -static char *cal_backend_imc_get_uid_by_pilot_id (CalBackend *backend, unsigned long int pilot_id); -static void cal_backend_imc_update_pilot_id (CalBackend *backend, - const char *uid, - unsigned long int pilot_id, - unsigned long int pilot_status); - - - -static void notify_update (CalBackendIMC *cbimc, const char *uid); - -static CalBackendClass *parent_class; - - - -/** - * cal_backend_imc_get_type: - * @void: - * - * Registers the #CalBackendIMC class if necessary, and returns the type ID - * associated to it. - * - * Return value: The type ID of the #CalBackendIMC class. - **/ -GtkType -cal_backend_imc_get_type (void) -{ - static GtkType cal_backend_imc_type = 0; - - if (!cal_backend_imc_type) { - static const GtkTypeInfo cal_backend_imc_info = { - "CalBackendIMC", - sizeof (CalBackendIMC), - sizeof (CalBackendIMCClass), - (GtkClassInitFunc) cal_backend_imc_class_init, - (GtkObjectInitFunc) cal_backend_imc_init, - NULL, /* reserved_1 */ - NULL, /* reserved_2 */ - (GtkClassInitFunc) NULL - }; - - cal_backend_imc_type = gtk_type_unique (CAL_BACKEND_TYPE, &cal_backend_imc_info); - } - - return cal_backend_imc_type; -} - -/* Class initialization function for the IMC backend */ -static void -cal_backend_imc_class_init (CalBackendIMCClass *class) -{ - GtkObjectClass *object_class; - CalBackendClass *backend_class; - - object_class = (GtkObjectClass *) class; - backend_class = (CalBackendClass *) class; - - parent_class = gtk_type_class (CAL_BACKEND_TYPE); - - backend_class->get_uri = cal_backend_imc_get_uri; - backend_class->add_cal = cal_backend_imc_add_cal; - backend_class->load = cal_backend_imc_load; - backend_class->create = cal_backend_imc_create; - backend_class->get_n_objects = cal_backend_imc_get_n_objects; - backend_class->get_object = cal_backend_imc_get_object; - backend_class->get_uids = cal_backend_imc_get_uids; - backend_class->get_events_in_range = cal_backend_imc_get_events_in_range; - backend_class->get_alarms_in_range = cal_backend_imc_get_alarms_in_range; - backend_class->get_alarms_for_object = cal_backend_imc_get_alarms_for_object; - backend_class->update_object = cal_backend_imc_update_object; - backend_class->remove_object = cal_backend_imc_remove_object; - backend_class->get_uid_by_pilot_id = cal_backend_imc_get_uid_by_pilot_id; - backend_class->update_pilot_id = cal_backend_imc_update_pilot_id; - - object_class->destroy = cal_backend_imc_destroy; -} - -/* Object initialization function for the IMC backend */ -static void -cal_backend_imc_init (CalBackendIMC *cbimc) -{ - IMCPrivate *priv; - - priv = g_new0 (IMCPrivate, 1); - cbimc->priv = priv; - - priv->format = CAL_FORMAT_UNKNOWN; -} - -static void -save_to_vcal (CalBackendIMC *cbimc, char *fname) -{ - FILE *fp; - IMCPrivate *priv; - VObject *vcal; - GList *l; - - priv = cbimc->priv; - - if (g_file_exists (fname)) { - char *backup_name = g_strconcat (fname, "~", NULL); - - /* FIXME: do error checking on system calls!!!! */ - - if (g_file_exists (backup_name)) - unlink (backup_name); - - rename (fname, backup_name); - g_free (backup_name); - } - - vcal = newVObject (VCCalProp); - addPropValue (vcal, VCProdIdProp, - "-//Helix Code//NONSGML Evolution Calendar//EN"); - - /* Per the vCalendar spec, this must be "1.0" */ - addPropValue (vcal, VCVersionProp, "1.0"); - - /* FIXME: this should really iterate over the object hash table instead - * of the lists; that way we won't lose objects if they are of a type - * that we don't support but are in the calendar anyways. - */ - - for (l = priv->events; l; l = l->next) { - iCalObject *ical = l->data; - VObject *vobject = ical_object_to_vobject (ical); - addVObjectProp (vcal, vobject); - } - - for (l = priv->todos; l; l = l->next) { - iCalObject *ical = l->data; - VObject *vobject = ical_object_to_vobject (ical); - addVObjectProp (vcal, vobject); - } - - for (l = priv->journals; l; l = l->next) { - iCalObject *ical = l->data; - VObject *vobject = ical_object_to_vobject (ical); - addVObjectProp (vcal, vobject); - } - - fp = fopen(fname,"w"); - if (fp) { - writeVObject(fp, vcal); - fclose(fp); - } - cleanVObject (vcal); - cleanStrTbl (); -} - -/* Saves a calendar */ -static void -save (CalBackendIMC *cbimc) -{ - char *str_uri; - IMCPrivate *priv = cbimc->priv; - - str_uri = gnome_vfs_uri_to_string (priv->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)); - - if (!priv->dirty) - return; - - switch (priv->format) { - case CAL_FORMAT_VCALENDAR: - save_to_vcal (cbimc, str_uri); - break; - - case CAL_FORMAT_ICALENDAR: - /*icalendar_calendar_save (cbimc, str_uri);*/ - /* FIX ME */ - break; - - default: - g_message ("save(): Attempt to save a calendar with an unknown format!"); - break; - } - - printf ("cal-backend-imc: '%s' saved\n", str_uri); - - g_free (str_uri); -} - -/* g_hash_table_foreach() callback to destroy an iCalObject */ -static void -free_ical_object (gpointer key, gpointer value, gpointer data) -{ - iCalObject *ico; - - ico = value; - ical_object_unref (ico); -} - -/* Destroys an IMC backend's data */ -static void -destroy (CalBackendIMC *cbimc) -{ - IMCPrivate *priv; - - priv = cbimc->priv; - - if (priv->uri) { - gnome_vfs_uri_unref (priv->uri); - priv->uri = NULL; - } - - g_assert (priv->clients == NULL); - - if (priv->object_hash) { - g_hash_table_foreach (priv->object_hash, free_ical_object, NULL); - g_hash_table_destroy (priv->object_hash); - priv->object_hash = NULL; - } - - g_list_free (priv->events); - g_list_free (priv->todos); - g_list_free (priv->journals); - - priv->events = NULL; - priv->todos = NULL; - priv->journals = NULL; - - priv->loaded = FALSE; - priv->format = CAL_FORMAT_UNKNOWN; -} - -/* Destroy handler for the IMC backend */ -static void -cal_backend_imc_destroy (GtkObject *object) -{ - CalBackendIMC *cbimc; - IMCPrivate *priv; - - g_return_if_fail (object != NULL); - g_return_if_fail (IS_CAL_BACKEND_IMC (object)); - - cbimc = CAL_BACKEND_IMC (object); - priv = cbimc->priv; - - /* - if (priv->loaded) - save (cbimc); - */ - - destroy (cbimc); - - g_free (priv); - cbimc->priv = NULL; - - if (GTK_OBJECT_CLASS (parent_class)->destroy) - (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); -} - - - -/* iCalObject manipulation functions */ - -/* Looks up an object by its UID in the backend's object hash table */ -static iCalObject * -lookup_object (CalBackendIMC *cbimc, const char *uid) -{ - IMCPrivate *priv; - iCalObject *ico; - - priv = cbimc->priv; - ico = g_hash_table_lookup (priv->object_hash, uid); - - return ico; -} - -/* Ensures that an iCalObject has a unique identifier. If it doesn't have one, - * it will create one for it. - */ -static void -ensure_uid (iCalObject *ico) -{ - char *buf; - gulong str_time; - static guint seqno = 0; - - if (ico->uid) - return; - - str_time = (gulong) time (NULL); - - /* Is this good enough? */ - - buf = g_strdup_printf ("Evolution-Calendar-%d-%ld-%u", - (int) getpid(), str_time, seqno++); - ico->uid = buf; -} - -/* Adds an object to the calendar backend. Does *not* perform notification to - * calendar clients. - */ -static void -add_object (CalBackendIMC *cbimc, iCalObject *ico) -{ - IMCPrivate *priv; - - g_assert (ico != NULL); - - priv = cbimc->priv; - -#if 0 - /* FIXME: gnomecal old code */ - ico->new = 0; -#endif - - ensure_uid (ico); - g_hash_table_insert (priv->object_hash, ico->uid, ico); - - priv->dirty = TRUE; - - switch (ico->type) { - case ICAL_EVENT: - priv->events = g_list_prepend (priv->events, ico); -#if 0 - /* FIXME: gnomecal old code */ - ical_object_try_alarms (ico); -# ifdef DEBUGGING_MAIL_ALARM - ico->malarm.trigger = 0; - calendar_notify (0, ico); -# endif -#endif - break; - - case ICAL_TODO: - priv->todos = g_list_prepend (priv->todos, ico); - break; - - case ICAL_JOURNAL: - priv->journals = g_list_prepend (priv->journals, ico); - break; - - default: - g_assert_not_reached (); - } - -#if 0 - /* FIXME: gnomecal old code */ - ico->last_mod = time (NULL); -#endif -} - -/* Removes an object from the backend's hash and lists. Does not perform - * notification on the clients. - */ -static void -remove_object (CalBackendIMC *cbimc, iCalObject *ico) -{ - IMCPrivate *priv; - GList **list, *l; - - priv = cbimc->priv; - - g_assert (ico->uid != NULL); - g_hash_table_remove (priv->object_hash, ico->uid); - - priv->dirty = TRUE; - - switch (ico->type) { - case ICAL_EVENT: - list = &priv->events; - break; - - case ICAL_TODO: - list = &priv->todos; - break; - - case ICAL_JOURNAL: - list = &priv->journals; - break; - - default: - /* Make the compiler shut up. */ - list = NULL; - g_assert_not_reached (); - } - - l = g_list_find (*list, ico); - g_assert (l != NULL); - - *list = g_list_remove_link (*list, l); - g_list_free_1 (l); - - ical_object_unref (ico); -} - -/* Load a calendar from a VObject */ -static void -load_from_vobject (CalBackendIMC *cbimc, VObject *vobject) -{ - IMCPrivate *priv; - VObjectIterator i; - - priv = cbimc->priv; - - g_assert (!priv->loaded); - g_assert (priv->object_hash == NULL); - priv->object_hash = g_hash_table_new (g_str_hash, g_str_equal); - - initPropIterator (&i, vobject); - - while (moreIteration (&i)) { - VObject *this; - iCalObject *ical; - const char *object_name; - - this = nextVObject (&i); - object_name = vObjectName (this); -#if 0 - /* FIXME? What is this used for in gnomecal? */ - if (strcmp (object_name, VCDCreatedProp) == 0) { - cal->created = time_from_isodate (str_val (this)); - continue; - } -#endif - if (strcmp (object_name, VCLocationProp) == 0) - continue; /* FIXME: imlement */ - - if (strcmp (object_name, VCProdIdProp) == 0) - continue; /* FIXME: implement */ - - if (strcmp (object_name, VCVersionProp) == 0) - continue; /* FIXME: implement */ - - if (strcmp (object_name, VCTimeZoneProp) == 0) - continue; /* FIXME: implement */ - - ical = ical_object_create_from_vobject (this, object_name); - - /* FIXME: some broken files (ahem, old KOrganizer files) may - * have duplicated UIDs. This is Bad(tm). Deal with it by - * creating new UIDs for them and spitting some messages to the - * console. - */ - - if (ical) - add_object (cbimc, ical); - } -} - - - -/* Calendar backend methods */ - -/* Get_uri handler for the IMC backend */ -static GnomeVFSURI * -cal_backend_imc_get_uri (CalBackend *backend) -{ - CalBackendIMC *cbimc; - IMCPrivate *priv; - - cbimc = CAL_BACKEND_IMC (backend); - priv = cbimc->priv; - - g_return_val_if_fail (priv->loaded, NULL); - g_assert (priv->uri != NULL); - - return priv->uri; -} - -/* Callback used when a Cal is destroyed */ -static void -cal_destroy_cb (GtkObject *object, gpointer data) -{ - Cal *cal; - Cal *lcal; - CalBackendIMC *cbimc; - IMCPrivate *priv; - GList *l; - - fprintf (stderr, "cal_destroy_cb(): A Cal was destroyed!\n"); - - cal = CAL (object); - - cbimc = CAL_BACKEND_IMC (data); - priv = cbimc->priv; - - /* Find the cal in the list of clients */ - - for (l = priv->clients; l; l = l->next) { - lcal = CAL (l->data); - - if (lcal == cal) - break; - } - - g_assert (l != NULL); - - /* Disconnect */ - - priv->clients = g_list_remove_link (priv->clients, l); - g_list_free_1 (l); - - /* When all clients go away, notify the parent factory about it so that - * it may decide whether to kill the backend or not. - */ - if (!priv->clients) - cal_backend_last_client_gone (CAL_BACKEND (cbimc)); -} - -/* Add_cal handler for the IMC backend */ -static void -cal_backend_imc_add_cal (CalBackend *backend, Cal *cal) -{ - CalBackendIMC *cbimc; - IMCPrivate *priv; - - cbimc = CAL_BACKEND_IMC (backend); - priv = cbimc->priv; - - g_return_if_fail (priv->loaded); - g_return_if_fail (cal != NULL); - g_return_if_fail (IS_CAL (cal)); - - /* We do not keep a reference to the Cal since the calendar user agent - * owns it. - */ - - gtk_signal_connect (GTK_OBJECT (cal), "destroy", - GTK_SIGNAL_FUNC (cal_destroy_cb), - backend); - - priv->clients = g_list_prepend (priv->clients, cal); -} - -static icalcomponent * -icalendar_parse_file (char *fname) -{ - FILE *fp; - icalcomponent *comp = NULL; - char *str; - struct stat st; - int n; - - fp = fopen (fname, "r"); - if (!fp) { - /* FIXME: remove message */ - g_message ("icalendar_parse_file(): Cannot open open calendar file."); - return NULL; - } - - stat (fname, &st); - - str = g_malloc (st.st_size + 2); - - n = fread (str, 1, st.st_size, fp); - if (n != st.st_size) { - /* FIXME: remove message, return error code instead */ - g_message ("icalendar_parse_file(): Read error."); - } - str[n] = '\0'; - - fclose (fp); - - comp = icalparser_parse_string (str); - g_free (str); - - return comp; -} - -static void -icalendar_calendar_load (CalBackendIMC *cbimc, char *fname) -{ - IMCPrivate *priv; - icalcomponent *comp; - icalcomponent *subcomp; - iCalObject *ical; - - priv = cbimc->priv; - - g_assert (!priv->loaded); - g_assert (priv->object_hash == NULL); - - priv->object_hash = g_hash_table_new (g_str_hash, g_str_equal); - - comp = icalendar_parse_file (fname); - subcomp = icalcomponent_get_first_component (comp, - ICAL_ANY_COMPONENT); - while (subcomp) { - ical = ical_object_create_from_icalcomponent (subcomp); - if (ical->type != ICAL_EVENT && - ical->type != ICAL_TODO && - ical->type != ICAL_JOURNAL) { - g_message ("icalendar_calendar_load(): Skipping unsupported " - "iCalendar component."); - } else - add_object (cbimc, ical); - - subcomp = icalcomponent_get_next_component (comp, - ICAL_ANY_COMPONENT); - } -} - -/* ics is to be used to designate a file containing (an arbitrary set of) - * calendaring and scheduling information. - * - * ifb is to be used to designate a file containing free or busy time - * information. - * - * anything else is assumed to be a vcal file. - * - * FIXME: should we return UNKNOWN at some point? - */ -static CalendarFormat -cal_get_type_from_filename (char *str_uri) -{ - int len; - - if (str_uri == NULL) - return CAL_FORMAT_VCALENDAR; - - len = strlen (str_uri); - if (len < 4) - return CAL_FORMAT_VCALENDAR; - - if (str_uri[len - 4] == '.' && str_uri[len - 3] == 'i' && - str_uri[len - 2] == 'c' && str_uri[len - 1] == 's') - return CAL_FORMAT_ICALENDAR; - - if (str_uri[len - 4] == '.' && str_uri[len - 3] == 'i' && - str_uri[len - 2] == 'f' && str_uri[len - 1] == 'b') - return CAL_FORMAT_ICALENDAR; - - if (str_uri[len - 4] == '.' && str_uri[len - 3] == 'i' && - str_uri[len - 2] == 'c' && str_uri[len - 1] == 's') - return CAL_FORMAT_ICALENDAR; - - if (len < 5) - return CAL_FORMAT_VCALENDAR; - - if (str_uri[len - 5] == '.' && str_uri[len - 4] == 'i' && - str_uri[len - 3] == 'c' && str_uri[len - 2] == 'a' && - str_uri[len - 1] == 'l') - return CAL_FORMAT_ICALENDAR; - - return CAL_FORMAT_VCALENDAR; -} - -/* Load handler for the IMC backend */ -static CalBackendLoadStatus -cal_backend_imc_load (CalBackend *backend, GnomeVFSURI *uri) -{ - CalBackendIMC *cbimc; - IMCPrivate *priv; - VObject *vobject; - char *str_uri; - - cbimc = CAL_BACKEND_IMC (backend); - priv = cbimc->priv; - - g_return_val_if_fail (!priv->loaded, CAL_BACKEND_LOAD_ERROR); - g_return_val_if_fail (uri != NULL, CAL_BACKEND_LOAD_ERROR); - - /* FIXME: this looks rather bad; maybe we should check for local files - * and fail if they are remote. - */ - - 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)); - - /* look at the extension on the filename and decide if this is a - * iCalendar or vCalendar file. - */ - priv->format = cal_get_type_from_filename (str_uri); - - /* load */ - - switch (priv->format) { - case CAL_FORMAT_VCALENDAR: - vobject = Parse_MIME_FromFileName (str_uri); - - if (!vobject){ - g_free (str_uri); - return CAL_BACKEND_LOAD_ERROR; - } - - load_from_vobject (cbimc, vobject); - cleanVObject (vobject); - cleanStrTbl (); - break; - - case CAL_FORMAT_ICALENDAR: - icalendar_calendar_load (cbimc, str_uri); - break; - - default: - g_free (str_uri); - return CAL_BACKEND_LOAD_ERROR; - } - - g_free (str_uri); - - gnome_vfs_uri_ref (uri); - - priv->uri = uri; - priv->loaded = TRUE; - - return CAL_BACKEND_LOAD_SUCCESS; -} - -/* Create handler for the IMC backend */ -static void -cal_backend_imc_create (CalBackend *backend, GnomeVFSURI *uri) -{ - CalBackendIMC *cbimc; - IMCPrivate *priv; - char *str_uri; - - cbimc = CAL_BACKEND_IMC (backend); - priv = cbimc->priv; - - g_return_if_fail (!priv->loaded); - g_return_if_fail (uri != NULL); - - /* Create the new calendar information */ - - g_assert (priv->object_hash == NULL); - priv->object_hash = g_hash_table_new (g_str_hash, g_str_equal); - - priv->dirty = TRUE; - - /* Done */ - - /* FIXME: this looks rather bad; maybe we should check for local files - * and fail if they are remote. - */ - - 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)); - - /* look at the extension on the filename and decide if this is a - * iCalendar or vCalendar file. - */ - priv->format = cal_get_type_from_filename (str_uri); - - g_free (str_uri); - - gnome_vfs_uri_ref (uri); - - priv->uri = uri; - priv->loaded = TRUE; - - save (cbimc); -} - -struct get_n_objects_closure { - CalObjType type; - int n; -}; - -/* Counts the number of objects of the specified type. Called from - * g_hash_table_foreach(). - */ -static void -count_objects (gpointer key, gpointer value, gpointer data) -{ - iCalObject *ico; - struct get_n_objects_closure *c; - gboolean store; - - ico = value; - c = data; - - store = FALSE; - - if (ico->type == ICAL_EVENT) - store = (c->type & CALOBJ_TYPE_EVENT) != 0; - else if (ico->type == ICAL_TODO) - store = (c->type & CALOBJ_TYPE_TODO) != 0; - else if (ico->type == ICAL_JOURNAL) - store = (c->type & CALOBJ_TYPE_JOURNAL) != 0; - - if (store) - c->n++; -} - -/* Get_n_objects handler for the IMC backend */ -static int -cal_backend_imc_get_n_objects (CalBackend *backend, CalObjType type) -{ - CalBackendIMC *cbimc; - IMCPrivate *priv; - struct get_n_objects_closure c; - - cbimc = CAL_BACKEND_IMC (backend); - priv = cbimc->priv; - - g_return_val_if_fail (priv->loaded, -1); - - c.type = type; - c.n = 0; - - g_hash_table_foreach (priv->object_hash, count_objects, &c); - - return c.n; -} - -/* Get_object handler for the IMC backend */ -static char * -cal_backend_imc_get_object (CalBackend *backend, const char *uid) -{ - CalBackendIMC *cbimc; - IMCPrivate *priv; - iCalObject *ico; - char *buf; - - cbimc = CAL_BACKEND_IMC (backend); - priv = cbimc->priv; - - g_return_val_if_fail (uid != NULL, NULL); - - g_return_val_if_fail (priv->loaded, NULL); - g_assert (priv->object_hash != NULL); - - ico = lookup_object (cbimc, uid); - - if (!ico) - return NULL; - - buf = ical_object_to_string (ico); - - return buf; -} - -struct get_uids_closure { - CalObjType type; - GList *uid_list; -}; - -/* Builds a list of UIDs for objects that match the sought type. Called from - * g_hash_table_foreach(). - */ -static void -build_uids_list (gpointer key, gpointer value, gpointer data) -{ - iCalObject *ico; - struct get_uids_closure *c; - gboolean store; - - ico = value; - c = data; - - store = FALSE; - - if (ico->type == ICAL_EVENT) - store = (c->type & CALOBJ_TYPE_EVENT) ? TRUE : FALSE; - else if (ico->type == ICAL_TODO) - store = (c->type & CALOBJ_TYPE_TODO) ? TRUE : FALSE; - else if (ico->type == ICAL_JOURNAL) - store = (c->type & CALOBJ_TYPE_JOURNAL) ? TRUE : FALSE; - - if (store) - c->uid_list = g_list_prepend (c->uid_list, g_strdup (ico->uid)); -} - -/* Get_uids handler for the IMC backend */ -static GList * -cal_backend_imc_get_uids (CalBackend *backend, CalObjType type) -{ - CalBackendIMC *cbimc; - IMCPrivate *priv; - struct get_uids_closure c; - - cbimc = CAL_BACKEND_IMC (backend); - priv = cbimc->priv; - - g_return_val_if_fail (priv->loaded, NULL); - - c.type = type; - c.uid_list = NULL; - g_hash_table_foreach (priv->object_hash, build_uids_list, &c); - - return c.uid_list; -} - - - -static char * -cal_backend_imc_get_uid_by_pilot_id (CalBackend *backend, - unsigned long int pilot_id) -{ - CalBackendIMC *cbimc; - IMCPrivate *priv; - GList *l; - iCalObject *obj = NULL; - - g_return_val_if_fail (backend != NULL, NULL); - cbimc = CAL_BACKEND_IMC (backend); - priv = cbimc->priv; - g_return_val_if_fail (priv->loaded, NULL); - - for (l = priv->events; l; l = l->next){ - obj = l->data; - if (obj->pilot_id == pilot_id) - goto done; - } - - for (l = priv->todos; l; l = l->next){ - obj = l->data; - if (obj->pilot_id == pilot_id) - goto done; - } - - done: - if (!obj || obj->pilot_id != pilot_id) - return NULL; - - return g_strdup (obj->uid); -} - - -void -cal_backend_imc_update_pilot_id (CalBackend *backend, - const char *uid, - unsigned long int pilot_id, - unsigned long int pilot_status) -{ - CalBackendIMC *cbimc; - IMCPrivate *priv; - iCalObject *obj; - - g_return_if_fail (backend != NULL); - cbimc = CAL_BACKEND_IMC (backend); - priv = cbimc->priv; - g_return_if_fail (priv->loaded); - - obj = lookup_object (cbimc, uid); - - obj->pilot_id = pilot_id; - obj->pilot_status = pilot_status; - - save (cbimc); - - notify_update (cbimc, uid); -} - - - -/* Allocates and fills in a new CalObjInstance structure */ -static CalObjInstance * -build_cal_obj_instance (iCalObject *ico, time_t start, time_t end) -{ - CalObjInstance *icoi; - - g_assert (ico->uid != NULL); - - icoi = g_new (CalObjInstance, 1); - icoi->uid = g_strdup (ico->uid); - icoi->start = start; - icoi->end = end; - - return icoi; -} - -struct build_event_list_closure { - CalBackendIMC *cbimc; - GList *event_list; -}; - -/* Builds a sorted list of event object instances. Used as a callback from - * ical_object_generate_events(). - */ -static int -build_event_list (iCalObject *ico, time_t start, time_t end, void *data) -{ - CalObjInstance *icoi; - struct build_event_list_closure *c; - - c = data; - - icoi = build_cal_obj_instance (ico, start, end); - c->event_list = g_list_prepend (c->event_list, icoi); - - return TRUE; -} - -/* Compares two CalObjInstance structures by their start times. Called from - * g_list_sort(). - */ -static gint -compare_instance_func (gconstpointer a, gconstpointer b) -{ - const CalObjInstance *ca, *cb; - time_t diff; - - ca = a; - cb = b; - - diff = ca->start - cb->start; - return (diff < 0) ? -1 : (diff > 0) ? 1 : 0; -} - -/* Get_events_in_range handler for the IMC backend */ -static GList * -cal_backend_imc_get_events_in_range (CalBackend *backend, time_t start, time_t end) -{ - CalBackendIMC *cbimc; - IMCPrivate *priv; - struct build_event_list_closure c; - GList *l; - - cbimc = CAL_BACKEND_IMC (backend); - priv = cbimc->priv; - - g_return_val_if_fail (priv->loaded, NULL); - - g_return_val_if_fail (start != -1 && end != -1, NULL); - g_return_val_if_fail (start <= end, NULL); - - c.cbimc = cbimc; - c.event_list = NULL; - - for (l = priv->events; l; l = l->next) { - iCalObject *ico; - - ico = l->data; - ical_object_generate_events (ico, start, end, - build_event_list, &c); - } - - c.event_list = g_list_sort (c.event_list, compare_instance_func); - return c.event_list; -} - -struct build_alarm_list_closure { - time_t start; - time_t end; - GList *alarms; -}; - -/* Computes the offset in minutes from an alarm trigger to the actual event */ -static int -compute_alarm_offset (CalendarAlarm *a) -{ - int ofs; - - if (!a->enabled) - return -1; - - switch (a->units) { - case ALARM_MINUTES: - ofs = a->count * 60; - break; - - case ALARM_HOURS: - ofs = a->count * 3600; - break; - - case ALARM_DAYS: - ofs = a->count * 24 * 3600; - break; - - default: - ofs = -1; - g_assert_not_reached (); - } - - return ofs; -} - -/* Allocates and fills in a new CalAlarmInstance structure */ -static CalAlarmInstance * -build_cal_alarm_instance (iCalObject *ico, enum AlarmType type, time_t trigger, time_t occur) -{ - CalAlarmInstance *ai; - - g_assert (ico->uid != NULL); - - ai = g_new (CalAlarmInstance, 1); - ai->uid = g_strdup (ico->uid); - ai->type = type; - ai->trigger = trigger; - ai->occur = occur; - - return ai; -} - -/* Adds the specified alarm to the list if its trigger time falls within the - * requested range. - */ -static void -try_add_alarm (time_t occur_start, iCalObject *ico, CalendarAlarm *alarm, - struct build_alarm_list_closure *c) -{ - int ofs; - time_t trigger; - CalAlarmInstance *ai; - - if (!alarm->enabled) - return; - - ofs = compute_alarm_offset (alarm); - g_assert (ofs != -1); - - trigger = occur_start - ofs; - - if (trigger < c->start || trigger > c->end) - return; - - ai = build_cal_alarm_instance (ico, alarm->type, trigger, occur_start); - c->alarms = g_list_prepend (c->alarms, ai); -} - -/* Builds a list of alarm instances. Used as a callback from - * ical_object_generate_events(). - */ -static int -build_alarm_list (iCalObject *ico, time_t start, time_t end, void *data) -{ - struct build_alarm_list_closure *c; - - c = data; - - try_add_alarm (start, ico, &ico->dalarm, c); - try_add_alarm (start, ico, &ico->aalarm, c); - try_add_alarm (start, ico, &ico->palarm, c); - try_add_alarm (start, ico, &ico->malarm, c); - - return TRUE; -} - -/* Adds all the alarm triggers that occur within the specified time range */ -static GList * -add_alarms_for_object (GList *alarms, iCalObject *ico, time_t start, time_t end) -{ - struct build_alarm_list_closure c; - int dofs, aofs, pofs, mofs; - int max_ofs; - - dofs = compute_alarm_offset (&ico->dalarm); - aofs = compute_alarm_offset (&ico->aalarm); - pofs = compute_alarm_offset (&ico->palarm); - mofs = compute_alarm_offset (&ico->malarm); - - max_ofs = MAX (dofs, MAX (aofs, MAX (pofs, mofs))); - if (max_ofs == -1) - return alarms; - - c.start = start; - c.end = end; - c.alarms = alarms; - - ical_object_generate_events (ico, start, end, build_alarm_list, &c); - return c.alarms; -} - -/* Get_alarms_in_range handler for the IMC backend */ -static GList * -cal_backend_imc_get_alarms_in_range (CalBackend *backend, time_t start, time_t end) -{ - CalBackendIMC *cbimc; - IMCPrivate *priv; - GList *l; - GList *alarms; - - cbimc = CAL_BACKEND_IMC (backend); - priv = cbimc->priv; - - g_return_val_if_fail (priv->loaded, NULL); - - g_return_val_if_fail (start != -1 && end != -1, NULL); - g_return_val_if_fail (start <= end, NULL); - - /* Only VEVENT and VTODO components can have alarms */ - - alarms = NULL; - - for (l = priv->events; l; l = l->next) - alarms = add_alarms_for_object (alarms, (iCalObject *) l->data, start, end); - - for (l = priv->todos; l; l = l->next) - alarms = add_alarms_for_object (alarms, (iCalObject *) l->data, start, end); - - alarms = g_list_sort (alarms, compare_instance_func); - return alarms; -} - -/* Get_alarms_for_object handler for the IMC backend */ -static gboolean -cal_backend_imc_get_alarms_for_object (CalBackend *backend, const char *uid, - time_t start, time_t end, - GList **alarms) -{ - CalBackendIMC *cbimc; - IMCPrivate *priv; - iCalObject *ico; - - cbimc = CAL_BACKEND_IMC (backend); - priv = cbimc->priv; - - g_return_val_if_fail (priv->loaded, FALSE); - g_return_val_if_fail (uid != NULL, FALSE); - g_return_val_if_fail (start != -1 && end != -1, FALSE); - g_return_val_if_fail (start <= end, FALSE); - g_return_val_if_fail (alarms != NULL, FALSE); - - *alarms = NULL; - - ico = lookup_object (cbimc, uid); - if (!ico) - return FALSE; - - /* Only VEVENT and VTODO components can have alarms */ - - if (ico->type != ICAL_EVENT && ico->type != ICAL_TODO) - return TRUE; - - *alarms = add_alarms_for_object (*alarms, ico, start, end); - *alarms = g_list_sort (*alarms, compare_instance_func); - - return TRUE; -} - -/* Notifies a backend's clients that an object was updated */ -static void -notify_update (CalBackendIMC *cbimc, const char *uid) -{ - IMCPrivate *priv; - GList *l; - - priv = cbimc->priv; - - for (l = priv->clients; l; l = l->next) { - Cal *cal; - - cal = CAL (l->data); - cal_notify_update (cal, uid); - } -} - -/* Notifies a backend's clients that an object was removed */ -static void -notify_remove (CalBackendIMC *cbimc, const char *uid) -{ - IMCPrivate *priv; - GList *l; - - priv = cbimc->priv; - - for (l = priv->clients; l; l = l->next) { - Cal *cal; - - cal = CAL (l->data); - cal_notify_remove (cal, uid); - } -} - -/* Update_object handler for the IMC backend */ -static gboolean -cal_backend_imc_update_object (CalBackend *backend, const char *uid, const char *calobj) -{ - CalBackendIMC *cbimc; - IMCPrivate *priv; - iCalObject *ico, *new_ico; - CalObjFindStatus status; - - cbimc = CAL_BACKEND_IMC (backend); - priv = cbimc->priv; - - g_return_val_if_fail (priv->loaded, FALSE); - - g_return_val_if_fail (uid != NULL, FALSE); - g_return_val_if_fail (calobj != NULL, FALSE); - - /* Pull the object from the string */ - - status = ical_object_find_in_string (uid, calobj, &new_ico); - - if (status != CAL_OBJ_FIND_SUCCESS) - return FALSE; - - /* Update the object */ - - ico = lookup_object (cbimc, uid); - - if (ico) - remove_object (cbimc, ico); - - add_object (cbimc, new_ico); - new_ico->pilot_status = ICAL_PILOT_SYNC_MOD; - save (cbimc); - - /* FIXME: do the notification asynchronously */ - - notify_update (cbimc, new_ico->uid); - - return TRUE; -} - -/* Remove_object handler for the IMC backend */ -static gboolean -cal_backend_imc_remove_object (CalBackend *backend, const char *uid) -{ - CalBackendIMC *cbimc; - IMCPrivate *priv; - iCalObject *ico; - - cbimc = CAL_BACKEND_IMC (backend); - priv = cbimc->priv; - - g_return_val_if_fail (priv->loaded, FALSE); - - g_return_val_if_fail (uid != NULL, FALSE); - - ico = lookup_object (cbimc, uid); - if (!ico) - return FALSE; - - remove_object (cbimc, ico); - - priv->dirty = TRUE; - save (cbimc); - - /* FIXME: do the notification asynchronously */ - notify_remove (cbimc, uid); - - return TRUE; -} diff --git a/calendar/pcs/cal-backend-imc.h b/calendar/pcs/cal-backend-imc.h deleted file mode 100644 index 954bbc52cc..0000000000 --- a/calendar/pcs/cal-backend-imc.h +++ /dev/null @@ -1,61 +0,0 @@ -/* Evolution calendar - Internet Mail Consortium formats backend - * - * Copyright (C) 2000 Helix Code, Inc. - * - * Authors: Federico Mena-Quintero - * Seth Alves - * Miguel de Icaza - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * 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. - */ - -#ifndef CAL_BACKEND_IMC_H -#define CAL_BACKEND_IMC_H - -#include -#include "cal-backend.h" - -BEGIN_GNOME_DECLS - - - -#define CAL_BACKEND_IMC_TYPE (cal_backend_imc_get_type ()) -#define CAL_BACKEND_IMC(obj) (GTK_CHECK_CAST ((obj), CAL_BACKEND_IMC_TYPE, CalBackendIMC)) -#define CAL_BACKEND_IMC_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), CAL_BACKEND_IMC_TYPE, \ - CalBackendIMCClass)) -#define IS_CAL_BACKEND_IMC(obj) (GTK_CHECK_TYPE ((obj), CAL_BACKEND_IMC_TYPE)) -#define IS_CAL_BACKEND_IMC_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), CAL_BACKEND_IMC_TYPE)) - -typedef struct _CalBackendIMC CalBackendIMC; -typedef struct _CalBackendIMCClass CalBackendIMCClass; - -struct _CalBackendIMC { - CalBackend backend; - - /* Private data */ - gpointer priv; -}; - -struct _CalBackendIMCClass { - CalBackendClass parent_class; -}; - -GtkType cal_backend_imc_get_type (void); - - - -END_GNOME_DECLS - -#endif diff --git a/calendar/pcs/cal-backend.c b/calendar/pcs/cal-backend.c index ee2b38a52c..3c7698a4d5 100644 --- a/calendar/pcs/cal-backend.c +++ b/calendar/pcs/cal-backend.c @@ -21,7 +21,10 @@ */ #include -#include +#include +#include +#include +#include #include "cal-backend.h" #include "libversit/vcc.h" @@ -35,6 +38,11 @@ enum { }; static void cal_backend_class_init (CalBackendClass *class); +static void cal_backend_init (CalBackend *backend); +static gboolean cal_backend_log_sync (CalBackend *backend); +static GHashTable *cal_backend_get_log_entries (CalBackend *backend, + time_t since, + CalObjType type); static GtkObjectClass *parent_class; @@ -64,7 +72,7 @@ cal_backend_get_type (void) sizeof (CalBackend), sizeof (CalBackendClass), (GtkClassInitFunc) cal_backend_class_init, - (GtkObjectInitFunc) NULL, + (GtkObjectInitFunc) cal_backend_init, NULL, /* reserved_1 */ NULL, /* reserved_2 */ (GtkClassInitFunc) NULL @@ -98,6 +106,14 @@ cal_backend_class_init (CalBackendClass *class) gtk_object_class_add_signals (object_class, cal_backend_signals, LAST_SIGNAL); } +/* Per instance initialization function */ +static void +cal_backend_init (CalBackend *backend) +{ + backend->uri = NULL; + backend->entries = NULL; +} + /** @@ -150,12 +166,32 @@ cal_backend_add_cal (CalBackend *backend, Cal *cal) CalBackendLoadStatus cal_backend_load (CalBackend *backend, GnomeVFSURI *uri) { + CalBackendLoadStatus result; + g_return_val_if_fail (backend != NULL, CAL_BACKEND_LOAD_ERROR); g_return_val_if_fail (IS_CAL_BACKEND (backend), CAL_BACKEND_LOAD_ERROR); g_return_val_if_fail (uri != NULL, CAL_BACKEND_LOAD_ERROR); g_assert (CLASS (backend)->load != NULL); - return (* CLASS (backend)->load) (backend, uri); + result = (* CLASS (backend)->load) (backend, uri); + + /* Remember the URI for saving the log file in the same dir and add + * a timeout handler so for saving pending entries sometimes */ + if (backend->uri) + gnome_vfs_uri_unref (backend->uri); + + if (backend->timer) + gtk_timeout_remove (backend->timer); + + if (result == CAL_BACKEND_LOAD_SUCCESS) { + backend->uri = uri; + gnome_vfs_uri_ref (uri); + backend->timer = gtk_timeout_add (60000, + (GtkFunction)cal_backend_log_sync, + backend); + } + + return result; } /** @@ -239,6 +275,43 @@ cal_backend_get_uids (CalBackend *backend, CalObjType type) return (* CLASS (backend)->get_uids) (backend, type); } + +static void +cal_backend_foreach_changed (gpointer key, gpointer value, gpointer data) +{ + GList **list = data; + + *list = g_list_append (*list, value); +} + +/** + * cal_backend_get_changed_uids: + * @backend: + * @type: + * @since: + * + * + * + * Return value: + **/ +GList * +cal_backend_get_changed_uids (CalBackend *backend, CalObjType type, time_t since) +{ + GHashTable *hash; + GList *uids = NULL; + + g_return_val_if_fail (backend != NULL, NULL); + g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL); + + hash = cal_backend_get_log_entries (backend, type, since); + + if (hash) + g_hash_table_foreach (hash, cal_backend_foreach_changed, &uids); + + return uids; +} + + /** * cal_backend_get_objects_in_range: * @backend: A calendar backend. @@ -337,7 +410,284 @@ void cal_backend_update_pilot_id (CalBackend *backend, const char *uid, pilot_id, pilot_status); } +/* Internal logging stuff */ +typedef enum { + CAL_BACKEND_UPDATED, + CAL_BACKEND_REMOVED +} CalBackendLogEntryType; + +typedef struct { + char *uid; + CalObjType type; + + CalBackendLogEntryType event_type; + + time_t time_stamp; +} CalBackendLogEntry; + +typedef struct { + CalObjType type; + time_t since; + + gboolean in_valid_timestamp; + + GHashTable *hash; +} CalBackendParseState; + +static gchar * +cal_backend_log_name (CalBackend *backend) +{ + gchar *path, *filename; + + path = gnome_vfs_uri_extract_dirname (backend->uri); + filename = g_strdup_printf ("%slog.xml", path); + g_free (path); + + return filename; +} + +static void +cal_backend_set_node_timet (xmlNodePtr node, const char *name, time_t t) +{ + char *tstring; + + tstring = g_strdup_printf ("%ld", t); + xmlSetProp (node, name, tstring); +} + +static void +cal_backend_log_entry (CalBackend *backend, const char *uid, + CalBackendLogEntryType type) +{ + CalBackendLogEntry *entry = g_new0 (CalBackendLogEntry, 1); + CalObjType cot; + + g_assert (CLASS (backend)->get_type_by_uid != NULL); + cot = (* CLASS (backend)->get_type_by_uid) (backend, uid); + + /* Only log todos and events */ + if (cot != CALOBJ_TYPE_EVENT && cot != CALOBJ_TYPE_TODO) + return; + + entry = g_new0 (CalBackendLogEntry, 1); + entry->uid = g_strdup (uid); + entry->type = cot; + entry->event_type = type; + entry->time_stamp = time (NULL); + + /* Append so they get stored in chronological order */ + backend->entries = g_slist_append (backend->entries, entry); +} + +static gboolean +cal_backend_log_sync (CalBackend *backend) +{ + xmlDocPtr doc; + xmlNodePtr tnode; + gchar *filename; + GSList *l; + int ret; + time_t start_time = (time_t) - 1; + + if (backend->entries == NULL) + return TRUE; + + filename = cal_backend_log_name (backend); + + doc = xmlParseFile (filename); + if (doc == NULL) { + /* Create the document */ + doc = xmlNewDoc ("1.0"); + if (doc == NULL) { + g_warning ("Log file could not be created\n"); + return FALSE; + } + + + doc->root = xmlNewDocNode(doc, NULL, "CalendarLog", NULL); + } + + tnode = xmlNewChild (doc->root, NULL, "timestamp", NULL); + for (l = backend->entries; l != NULL; l = l->next) { + xmlNodePtr node; + CalBackendLogEntry *entry; + + entry = (CalBackendLogEntry *)l->data; + node = xmlNewChild (tnode, NULL, "status", NULL); + + xmlSetProp (node, "uid", entry->uid); + + switch (entry->type) { + case CALOBJ_TYPE_EVENT: + xmlSetProp (node, "type", "event"); + break; + case CALOBJ_TYPE_TODO: + xmlSetProp (node, "type", "todo"); + break; + default: + } + + switch (entry->event_type) { + case (CAL_BACKEND_UPDATED): + xmlSetProp (node, "operation", "updated"); + break; + case (CAL_BACKEND_REMOVED): + xmlSetProp (node, "operation", "removed"); + break; + } + + if (start_time == (time_t) - 1 + || entry->time_stamp < start_time) + start_time = entry->time_stamp; + + g_free (entry); + } + cal_backend_set_node_timet (tnode, "start", start_time); + cal_backend_set_node_timet (tnode, "end", time (NULL)); + + g_slist_free (backend->entries); + backend->entries = NULL; + + /* Write the file */ + xmlSetDocCompressMode (doc, 0); + ret = xmlSaveFile (filename, doc); + if (ret < 0) { + g_warning ("Log file could not be saved\n"); + return FALSE; + } + + xmlFreeDoc (doc); + + g_free (filename); + + return TRUE; +} + +static void +cal_backend_log_sax_start_element (void *data, const xmlChar *name, + const xmlChar **attrs) +{ + CalBackendParseState *state = (CalBackendParseState *)data; + + if (!strcmp (name, "timestamp")) { + while (attrs && *attrs != NULL) { + const xmlChar **val = attrs; + + val++; + if (!strcmp (*attrs, "start")) { + time_t start = (time_t)strtoul (*val, NULL, 0); + + if (start >= state->since) + state->in_valid_timestamp = TRUE; + break; + } + attrs = ++val; + } + } + + if (!strcmp (name, "status")) { + CalObjChange *coc = g_new0 (CalObjChange, 1); + CalObjType cot = 0; + + while (attrs && *attrs != NULL) { + const xmlChar **val = attrs; + + + val++; + if (!strcmp (*attrs, "uid")) + coc->uid = g_strdup (*val); + + if (!strcmp (*attrs, "type")) { + if (!strcmp (*val, "event")) + cot = CALOBJ_TYPE_EVENT; + else if (!strcmp (*val, "todo")) + cot = CALOBJ_TYPE_TODO; + } + + if (!strcmp (*attrs, "operation")) + coc->type = atoi (*val); + + attrs = ++val; + } + + if (state->type == CALOBJ_TYPE_ANY || state->type == cot) + g_hash_table_insert (state->hash, coc->uid, coc); + } +} + +static void +cal_backend_log_sax_end_element (void *data, const xmlChar *name) +{ + CalBackendParseState *state = (CalBackendParseState *)data; + + if (!strcmp (name, "timestamp")) { + state->in_valid_timestamp = FALSE; + } +} + +static int +cal_backend_log_sax_parse (CalBackend *backend, xmlSAXHandler *handler, + CalBackendParseState *state) +{ + int ret = 0; + xmlParserCtxtPtr ctxt; + char *filename; + + filename = cal_backend_log_name (backend); + + if (!g_file_exists (filename)) + return 0; + + ctxt = xmlCreateFileParserCtxt (filename); + if (ctxt == NULL) + return -1; + + ctxt->sax = handler; + ctxt->userData = (void *)state; + + xmlParseDocument (ctxt); + + if (ctxt->wellFormed) + ret = 0; + else + ret = -1; + + if (handler != NULL) + ctxt->sax = NULL; + xmlFreeParserCtxt(ctxt); + + return ret; +} + +static GHashTable * +cal_backend_get_log_entries (CalBackend *backend, time_t since, + CalObjType type) +{ + xmlSAXHandler handler; + CalBackendParseState state; + GHashTable *hash; + + g_return_val_if_fail (backend != NULL, NULL); + g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL); + + if (!cal_backend_log_sync (backend)) + return NULL; + + hash = g_hash_table_new (g_str_hash, g_str_equal); + + memset(&handler, 0, sizeof(xmlSAXHandler)); + handler.startElement = cal_backend_log_sax_start_element; + handler.endElement = cal_backend_log_sax_end_element; + state.type = type; + state.since = since; + state.hash = hash; + + if (cal_backend_log_sax_parse (backend, &handler, &state) < 0) + return NULL; + + return hash; +} /** * cal_backend_update_object: @@ -355,13 +705,20 @@ void cal_backend_update_pilot_id (CalBackend *backend, const char *uid, gboolean cal_backend_update_object (CalBackend *backend, const char *uid, const char *calobj) { + gboolean result; + g_return_val_if_fail (backend != NULL, FALSE); g_return_val_if_fail (IS_CAL_BACKEND (backend), FALSE); g_return_val_if_fail (uid != NULL, FALSE); g_return_val_if_fail (calobj != NULL, FALSE); g_assert (CLASS (backend)->update_object != NULL); - return (* CLASS (backend)->update_object) (backend, uid, calobj); + result = (* CLASS (backend)->update_object) (backend, uid, calobj); + + if (result) + cal_backend_log_entry (backend, uid, CAL_BACKEND_UPDATED); + + return result; } /** @@ -378,12 +735,19 @@ cal_backend_update_object (CalBackend *backend, const char *uid, const char *cal gboolean cal_backend_remove_object (CalBackend *backend, const char *uid) { + gboolean result; + g_return_val_if_fail (backend != NULL, FALSE); g_return_val_if_fail (IS_CAL_BACKEND (backend), FALSE); g_return_val_if_fail (uid != NULL, FALSE); g_assert (CLASS (backend)->remove_object != NULL); - return (* CLASS (backend)->remove_object) (backend, uid); + result = (* CLASS (backend)->remove_object) (backend, uid); + + if (result) + cal_backend_log_entry (backend, uid, CAL_BACKEND_REMOVED); + + return result; } /** @@ -400,4 +764,10 @@ cal_backend_last_client_gone (CalBackend *backend) g_return_if_fail (IS_CAL_BACKEND (backend)); gtk_signal_emit (GTK_OBJECT (backend), cal_backend_signals[LAST_CLIENT_GONE]); + + cal_backend_log_sync (backend); } + + + + diff --git a/calendar/pcs/cal-backend.h b/calendar/pcs/cal-backend.h index cfc4cb8a99..77bba93835 100644 --- a/calendar/pcs/cal-backend.h +++ b/calendar/pcs/cal-backend.h @@ -26,6 +26,7 @@ #include #include #include +#include #include "calendar/pcs/evolution-calendar.h" #include "cal-common.h" #include "cal.h" @@ -49,6 +50,10 @@ typedef enum { struct _CalBackend { GtkObject object; + + GnomeVFSURI *uri; + GSList *entries; + guint timer; }; struct _CalBackendClass { @@ -65,6 +70,7 @@ struct _CalBackendClass { int (* get_n_objects) (CalBackend *backend, CalObjType type); char *(* get_object) (CalBackend *backend, const char *uid); + CalObjType(* get_type_by_uid) (CalBackend *backend, const char *uid); GList *(* get_uids) (CalBackend *backend, CalObjType type); GList *(* get_objects_in_range) (CalBackend *backend, CalObjType type, time_t start, time_t end); @@ -95,6 +101,8 @@ char *cal_backend_get_object (CalBackend *backend, const char *uid); GList *cal_backend_get_uids (CalBackend *backend, CalObjType type); +GList *cal_backend_get_changed_uids (CalBackend *backend, CalObjType type, time_t since); + GList *cal_backend_get_objects_in_range (CalBackend *backend, CalObjType type, time_t start, time_t end); diff --git a/calendar/pcs/cal.c b/calendar/pcs/cal.c index 64eb29b023..cb302cf9be 100644 --- a/calendar/pcs/cal.c +++ b/calendar/pcs/cal.c @@ -278,6 +278,63 @@ Cal_get_uids (PortableServer_Servant servant, return seq; } +static Evolution_Calendar_CalObjChangeSeq * +build_change_seq (GList *changes) +{ + GList *l; + int n, i; + Evolution_Calendar_CalObjChangeSeq *seq; + + n = g_list_length (changes); + + seq = Evolution_Calendar_CalObjChangeSeq__alloc (); + CORBA_sequence_set_release (seq, TRUE); + seq->_length = n; + seq->_buffer = CORBA_sequence_Evolution_Calendar_CalObjChange_allocbuf (n); + + /* Fill the sequence */ + for (i = 0, l = changes; l; i++, l = l->next) { + CalObjChange *c; + Evolution_Calendar_CalObjChange *corba_c; + + c = l->data; + corba_c = &seq->_buffer[i]; + + corba_c->uid = CORBA_string_dup (c->uid); + corba_c->type = c->type; + } + + return seq; +} + +/* Cal::get_changed_uids method */ +static Evolution_Calendar_CalObjChangeSeq * +Cal_get_changed_uids (PortableServer_Servant servant, + Evolution_Calendar_CalObjType type, + Evolution_Calendar_Time_t since, + CORBA_Environment *ev) +{ + Cal *cal; + CalPrivate *priv; + GList *changes; + Evolution_Calendar_CalObjChangeSeq *seq; + int t; + time_t s; + + cal = CAL (bonobo_object_from_servant (servant)); + priv = cal->priv; + + t = uncorba_obj_type (type); + s = (time_t) since; + + changes = cal_backend_get_changed_uids (priv->backend, t, s); + seq = build_change_seq (changes); + + cal_obj_change_list_free (changes); + + return seq; +} + /* Cal::get_objects_in_range method */ static Evolution_Calendar_CalObjUIDSeq * Cal_get_objects_in_range (PortableServer_Servant servant, @@ -558,6 +615,7 @@ cal_get_epv (void) epv->get_n_objects = Cal_get_n_objects; epv->get_object = Cal_get_object; epv->get_uids = Cal_get_uids; + epv->get_changed_uids = Cal_get_changed_uids; epv->get_objects_in_range = Cal_get_objects_in_range; epv->get_alarms_in_range = Cal_get_alarms_in_range; epv->get_alarms_for_object = Cal_get_alarms_for_object; -- cgit v1.2.3