diff options
author | JP Rosevear <jpr@helixcode.com> | 2000-09-20 06:48:47 +0800 |
---|---|---|
committer | JP Rosevear <jpr@src.gnome.org> | 2000-09-20 06:48:47 +0800 |
commit | 58b5fd92fc9f5419beabe82d38622aba064cc56e (patch) | |
tree | a8219b9cc9b1311466f9854b0fa673045250edb1 /calendar | |
parent | 6820bb50e53b479997ae5a9616186301c333fad8 (diff) | |
download | gsoc2013-evolution-58b5fd92fc9f5419beabe82d38622aba064cc56e.tar.gz gsoc2013-evolution-58b5fd92fc9f5419beabe82d38622aba064cc56e.tar.zst gsoc2013-evolution-58b5fd92fc9f5419beabe82d38622aba064cc56e.zip |
Add some other cases where a slow sync is in order (pre_sync): Pre load
2000-09-19 JP Rosevear <jpr@helixcode.com>
* 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
Diffstat (limited to 'calendar')
-rw-r--r-- | calendar/ChangeLog | 78 | ||||
-rw-r--r-- | calendar/cal-client/cal-client.c | 70 | ||||
-rw-r--r-- | calendar/cal-client/cal-client.h | 1 | ||||
-rw-r--r-- | calendar/cal-util/cal-util.c | 25 | ||||
-rw-r--r-- | calendar/cal-util/cal-util.h | 14 | ||||
-rw-r--r-- | calendar/conduits/todo/Makefile.am | 6 | ||||
-rw-r--r-- | calendar/conduits/todo/e-todo.conduit.in | 4 | ||||
-rw-r--r-- | calendar/conduits/todo/todo-conduit-config.h | 12 | ||||
-rw-r--r-- | calendar/conduits/todo/todo-conduit.c | 964 | ||||
-rw-r--r-- | calendar/conduits/todo/todo-conduit.h | 18 | ||||
-rw-r--r-- | calendar/idl/evolution-calendar.idl | 16 | ||||
-rw-r--r-- | calendar/pcs/cal-backend-file.c | 30 | ||||
-rw-r--r-- | calendar/pcs/cal-backend-imc.c | 1421 | ||||
-rw-r--r-- | calendar/pcs/cal-backend-imc.h | 61 | ||||
-rw-r--r-- | calendar/pcs/cal-backend.c | 380 | ||||
-rw-r--r-- | calendar/pcs/cal-backend.h | 8 | ||||
-rw-r--r-- | calendar/pcs/cal.c | 58 |
17 files changed, 1170 insertions, 1996 deletions
diff --git a/calendar/ChangeLog b/calendar/ChangeLog index 3838986f93..5dd236f207 100644 --- a/calendar/ChangeLog +++ b/calendar/ChangeLog @@ -1,3 +1,81 @@ +2000-09-19 JP Rosevear <jpr@helixcode.com> + + * 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. + 2000-09-18 Christopher James Lahey <clahey@helixcode.com> * gui/Makefile.am: Added $(EXTRA_GNOME_CFLAGS) and diff --git a/calendar/cal-client/cal-client.c b/calendar/cal-client/cal-client.c index 65c0c4aea4..7b5f248d85 100644 --- a/calendar/cal-client/cal-client.c +++ b/calendar/cal-client/cal-client.c @@ -1,3 +1,4 @@ + /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* Evolution calendar client * @@ -800,6 +801,75 @@ cal_client_get_uids (CalClient *client, CalObjType type) return uids; } +/* Builds a GList of CalObjChange structures from the CORBA sequence */ +static GList * +build_change_list (Evolution_Calendar_CalObjChangeSeq *seq) +{ + GList *list; + int i; + + /* Create the list in reverse order */ + list = NULL; + for (i = 0; i < seq->_length; i++) { + Evolution_Calendar_CalObjChange *corba_coc; + CalObjChange *coc; + + corba_coc = &seq->_buffer[i]; + coc = g_new (CalObjChange, 1); + + coc->uid = g_strdup (corba_coc->uid); + coc->type = corba_coc->type; + + list = g_list_prepend (list, coc); + } + + list = g_list_reverse (list); + return list; +} + +/** + * cal_client_get_changed_uids: + * @client: A calendar client. + * @type: Bitmask with types of objects to return. + * + * Queries a calendar for a list of unique identifiers corresponding to calendar + * objects whose type matches one of the types specified in the @type flags. + * + * Return value: A list of strings that are the sought UIDs. + **/ +GList * +cal_client_get_changed_uids (CalClient *client, CalObjType type, time_t since) +{ + CalClientPrivate *priv; + CORBA_Environment ev; + Evolution_Calendar_CalObjChangeSeq *seq; + int t; + GList *changes; + + g_return_val_if_fail (client != NULL, NULL); + g_return_val_if_fail (IS_CAL_CLIENT (client), NULL); + + priv = client->priv; + g_return_val_if_fail (priv->load_state == LOAD_STATE_LOADED, NULL); + + t = corba_obj_type (type); + CORBA_exception_init (&ev); + + seq = Evolution_Calendar_Cal_get_changed_uids (priv->cal, t, since, &ev); + if (ev._major != CORBA_NO_EXCEPTION) { + g_message ("cal_client_get_changed_uids(): could not get the list of changes"); + CORBA_exception_free (&ev); + return NULL; + } + + CORBA_exception_free (&ev); + + changes = build_change_list (seq); + CORBA_free (seq); + + return changes; +} + /* FIXME: Not used? */ #if 0 /* Builds a GList of CalObjInstance structures from the CORBA sequence */ diff --git a/calendar/cal-client/cal-client.h b/calendar/cal-client/cal-client.h index 6747c7488e..9853c63e2c 100644 --- a/calendar/cal-client/cal-client.h +++ b/calendar/cal-client/cal-client.h @@ -101,6 +101,7 @@ void cal_client_update_pilot_id (CalClient *client, char *uid, unsigned long pilot_status); GList *cal_client_get_uids (CalClient *client, CalObjType type); +GList *cal_client_get_changed_uids (CalClient *client, CalObjType type, time_t since); GList *cal_client_get_objects_in_range (CalClient *client, CalObjType type, time_t start, time_t end); diff --git a/calendar/cal-util/cal-util.c b/calendar/cal-util/cal-util.c index 092fd79889..bfb9c88fff 100644 --- a/calendar/cal-util/cal-util.c +++ b/calendar/cal-util/cal-util.c @@ -51,6 +51,31 @@ cal_obj_instance_list_free (GList *list) } /** + * cal_obj_change_list_free: + * @list: List of #CalObjChange structures. + * + * Frees a list of #CalObjChange structures. + **/ +void +cal_obj_change_list_free (GList *list) +{ + CalObjChange *c; + GList *l; + + for (l = list; l; l = l->next) { + c = l->data; + + g_assert (c != NULL); + g_assert (c->uid != NULL); + + g_free (c->uid); + g_free (c); + } + + g_list_free (list); +} + +/** * cal_alarm_instance_list_free: * @list: List of #CalAlarmInstance structures. * diff --git a/calendar/cal-util/cal-util.h b/calendar/cal-util/cal-util.h index 154f4c2ad5..243cc34105 100644 --- a/calendar/cal-util/cal-util.h +++ b/calendar/cal-util/cal-util.h @@ -41,6 +41,19 @@ typedef struct { void cal_obj_instance_list_free (GList *list); +typedef enum { + CALOBJ_UPDATED = 1 << 0, + CALOBJ_REMOVED = 1 << 1 +} CalObjChangeType; + +typedef struct +{ + char *uid; + CalObjChangeType type; +} CalObjChange; + +void cal_obj_change_list_free (GList *list); + /* Instance of an alarm trigger */ typedef struct { char *uid; /* UID of object */ @@ -66,3 +79,4 @@ void cal_obj_uid_list_free (GList *list); END_GNOME_DECLS #endif + diff --git a/calendar/conduits/todo/Makefile.am b/calendar/conduits/todo/Makefile.am index 3bbfc3f418..94eb5251b5 100644 --- a/calendar/conduits/todo/Makefile.am +++ b/calendar/conduits/todo/Makefile.am @@ -3,7 +3,7 @@ INCLUDES = \ -I$(top_srcdir)/calendar \ -I$(top_srcdir)/libical/src/libical \ -I$(top_builddir)/libical/src/libical \ - $(BONOBO_GNOME_CFLAGS) \ + $(BONOBO_VFS_GNOME_CFLAGS) \ $(GNOME_PILOT_CFLAGS) # ToDo Capplet @@ -30,9 +30,6 @@ e_todo_conduits_LTLIBRARIES = libetodo_conduit.la libetodo_conduit_la_SOURCES = todo-conduit.c -libetodo_conduit_la_LDFLAGS = \ - -rpath $(libdir) - libetodo_conduit_la_LIBADD = \ $(top_builddir)/calendar/cal-client/libcal-client-static.la \ $(top_builddir)/calendar/cal-util/libcal-util-static.la \ @@ -40,6 +37,7 @@ libetodo_conduit_la_LIBADD = \ $(top_builddir)/libical/src/libical/libical-static.la \ $(BONOBO_VFS_GNOME_LIBS) \ $(PISOCK_LIBDIR) $(PISOCK_LIBS) \ + $(UNICODE_LIBS) \ $(GNOME_LIBDIR) \ $(GNOME_LIBS) diff --git a/calendar/conduits/todo/e-todo.conduit.in b/calendar/conduits/todo/e-todo.conduit.in index 42691745a6..40e6fd620c 100644 --- a/calendar/conduits/todo/e-todo.conduit.in +++ b/calendar/conduits/todo/e-todo.conduit.in @@ -1,6 +1,6 @@ <gnome-pilot-conduit version="1.0"> -<conduit id="todo_conduit" type="shlib" location="@prefix@/lib/gnome-pilot/conduits/libetodo_conduit.so"/> -<name value="e-todo"/> +<conduit id="e_todo_conduit" type="shlib" location="@prefix@/lib/gnome-pilot/conduits/libetodo_conduit.so"/> +<name value="EToDo"/> <conduit-attribute name="description" value="Synchronizes ToDo List with Evolution"/> <conduit-attribute name="default-synctype" value="synchronize"/> <conduit-attribute name="icon" value="@prefix@/share/pixmaps/gnome-calendar-conduit.png"/> diff --git a/calendar/conduits/todo/todo-conduit-config.h b/calendar/conduits/todo/todo-conduit-config.h index 18bb353b08..38f3cf8e39 100644 --- a/calendar/conduits/todo/todo-conduit-config.h +++ b/calendar/conduits/todo/todo-conduit-config.h @@ -33,16 +33,16 @@ typedef struct _EToDoConduitCfg EToDoConduitCfg; struct _EToDoConduitCfg { gboolean open_secret; - guint32 pilotId; + guint32 pilot_id; GnomePilotConduitSyncType sync_type; /* only used by capplet */ }; static void -todoconduit_load_configuration (EToDoConduitCfg **c, guint32 pilotId) +todoconduit_load_configuration (EToDoConduitCfg **c, guint32 pilot_id) { gchar prefix[256]; g_snprintf (prefix, 255, "/gnome-pilot.d/e-todo-conduit/Pilot_%u/", - pilotId); + pilot_id); *c = g_new0 (EToDoConduitCfg,1); g_assert (*c != NULL); @@ -54,7 +54,7 @@ todoconduit_load_configuration (EToDoConduitCfg **c, guint32 pilotId) (*c)->sync_type = GnomePilotConduitSyncTypeCustom; gnome_config_pop_prefix (); - (*c)->pilotId = pilotId; + (*c)->pilot_id = pilot_id; } /* Saves the configuration data. */ @@ -64,7 +64,7 @@ todoconduit_save_configuration (EToDoConduitCfg *c) gchar prefix[256]; g_snprintf (prefix, 255, "/gnome-pilot.d/e-todo-conduit/Pilot_%u/", - c->pilotId); + c->pilot_id); gnome_config_push_prefix (prefix); gnome_config_set_bool ("open_secret", c->open_secret); @@ -85,7 +85,7 @@ todoconduit_dupe_configuration (EToDoConduitCfg *c) retval = g_new0 (EToDoConduitCfg, 1); retval->sync_type = c->sync_type; retval->open_secret = c->open_secret; - retval->pilotId = c->pilotId; + retval->pilot_id = c->pilot_id; return retval; } diff --git a/calendar/conduits/todo/todo-conduit.c b/calendar/conduits/todo/todo-conduit.c index f1f0e11e28..6b9659f70f 100644 --- a/calendar/conduits/todo/todo-conduit.c +++ b/calendar/conduits/todo/todo-conduit.c @@ -48,7 +48,6 @@ GnomePilotConduit * conduit_get_gpilot_conduit (guint32); void conduit_destroy_gpilot_conduit (GnomePilotConduit*); -void local_record_from_compobject (EToDoLocalRecord *local, CalComponent *comp); #define CONDUIT_VERSION "0.8.11" #ifdef G_LOG_DOMAIN @@ -60,15 +59,13 @@ void local_record_from_compobject (EToDoLocalRecord *local, CalComponent *comp); /* #undef DEBUG_CALCONDUIT */ #ifdef DEBUG_CALCONDUIT -#define show_exception(e) g_warning ("Exception: %s\n", CORBA_exception_id (e)) -#define LOG(e...) g_log(G_LOG_DOMAIN,G_LOG_LEVEL_MESSAGE, e) +#define LOG(e...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, e) #else -#define show_exception(e) #define LOG(e...) #endif -#define WARN(e...) g_log(G_LOG_DOMAIN,G_LOG_LEVEL_WARNING, e) -#define INFO(e...) g_log(G_LOG_DOMAIN,G_LOG_LEVEL_MESSAGE, e) +#define WARN(e...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_WARNING, e) +#define INFO(e...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, e) /* debug spew DELETE ME */ static char *print_local (EToDoLocalRecord *local) @@ -120,19 +117,16 @@ static char *print_remote (PilotRecord *remote) return buff; } -/* Given a GCalConduitContxt*, allocates the structure */ +/* Context Routines */ static void -e_todo_context_new (EToDoConduitContext **ctxt, guint32 pilotId) +e_todo_context_new (EToDoConduitContext **ctxt, guint32 pilot_id) { *ctxt = g_new0 (EToDoConduitContext,1); g_assert (ctxt!=NULL); - todoconduit_load_configuration (&(*ctxt)->cfg, pilotId); + todoconduit_load_configuration (&(*ctxt)->cfg, pilot_id); } - -/* Destroys any data allocated by gcalconduit_new_context - and deallocates its data. */ static void e_todo_context_destroy (EToDoConduitContext **ctxt) { @@ -149,15 +143,135 @@ e_todo_context_destroy (EToDoConduitContext **ctxt) *ctxt = NULL; } +/* Map routines */ +static char * +map_name (EToDoConduitContext *ctxt) +{ + char *filename; + + filename = g_strdup_printf ("%s/evolution/local/Calendar/pilot-map-%d.xml", g_get_home_dir (), ctxt->cfg->pilot_id); + + return filename; +} + +static void +map_sax_start_element (void *data, const xmlChar *name, + const xmlChar **attrs) +{ + EToDoConduitContext *ctxt = (EToDoConduitContext *)data; + + if (!strcmp (name, "map")) { + char *uid = NULL; + guint32 *pid = g_new (guint32, 1); + + *pid = 0; + + while (*attrs != NULL) { + const xmlChar **val = attrs; + + val++; + if (!strcmp (*attrs, "uid")) + uid = g_strdup (*val); + + if (!strcmp (*attrs, "pilotid")) + *pid = strtoul (*val, NULL, 0); + + attrs = ++val; + } + + if (uid && *pid != 0) + g_hash_table_insert (ctxt->map, pid, uid); + else + g_free (pid); + } +} + +static int +map_sax_parse (xmlSAXHandler *handler, EToDoConduitContext *ctxt, const char *filename) +{ + int ret = 0; + xmlParserCtxtPtr xc; + + if (!g_file_exists (filename)) + return 0; + + xc = xmlCreateFileParserCtxt (filename); + if (xc == NULL) + return -1; + + xc->sax = handler; + xc->userData = (void *)ctxt; + + xmlParseDocument (xc); + + if (xc->wellFormed) + ret = 0; + else + ret = -1; + + if (handler != NULL) + xc->sax = NULL; + xmlFreeParserCtxt(xc); + + return ret; +} static void -gnome_calendar_load_cb (GtkWidget *cal_client, - CalClientLoadStatus status, - EToDoConduitContext *ctxt) +map_write_foreach (gpointer key, gpointer value, gpointer data) +{ + xmlNodePtr root = data; + xmlNodePtr mnode; + unsigned long *pid = key; + const char *uid = value; + char *pidstr; + + mnode = xmlNewChild (root, NULL, "map", NULL); + xmlSetProp (mnode, "uid", uid); + pidstr = g_strdup_printf ("%lu", *pid); + xmlSetProp (mnode, "pilot_id", pidstr); + g_free (pidstr); +} + +static int +map_write (EToDoConduitContext *ctxt, char *filename) +{ + xmlDocPtr doc; + int ret; + + if (ctxt->map == NULL) + return 0; + + doc = xmlNewDoc ("1.0"); + if (doc == NULL) { + WARN ("Pilot map file could not be created\n"); + return -1; + } + doc->root = xmlNewDocNode(doc, NULL, "PilotMap", NULL); + + g_hash_table_foreach (ctxt->map, map_write_foreach, doc->root); + + /* Write the file */ + xmlSetDocCompressMode (doc, 0); + ret = xmlSaveFile (filename, doc); + if (ret < 0) { + g_warning ("Pilot map file '%s' could not be saved\n", filename); + return -1; + } + + xmlFreeDoc (doc); + + return 0; +} + +/* Calendar Server routines */ +static void +start_calendar_server_cb (GtkWidget *cal_client, + CalClientLoadStatus status, + EToDoConduitContext *ctxt) { CalClient *client = CAL_CLIENT (cal_client); - LOG (" todo-conduit entering gnome_calendar_load_cb, tried=%d\n", + LOG (" entering start_calendar_server_load_cb, tried=%d\n", ctxt->calendar_load_tried); if (status == CAL_CLIENT_LOAD_SUCCESS) { @@ -172,21 +286,15 @@ gnome_calendar_load_cb (GtkWidget *cal_client, } cal_client_create_calendar (client, ctxt->calendar_file); - ctxt->calendar_load_tried = 1; + ctxt->calendar_load_tried = TRUE; } } - - - - static int -start_calendar_server (GnomePilotConduitStandardAbs *conduit, - EToDoConduitContext *ctxt) +start_calendar_server (EToDoConduitContext *ctxt) { - g_return_val_if_fail(conduit!=NULL,-2); - g_return_val_if_fail(ctxt!=NULL,-2); + g_return_val_if_fail (ctxt != NULL, -2); ctxt->client = cal_client_new (); @@ -195,7 +303,7 @@ start_calendar_server (GnomePilotConduitStandardAbs *conduit, "evolution/local/Calendar/calendar.ics"); gtk_signal_connect (GTK_OBJECT (ctxt->client), "cal_loaded", - gnome_calendar_load_cb, ctxt); + start_calendar_server_cb, ctxt); LOG (" calling cal_client_load_calendar\n"); cal_client_load_calendar (ctxt->client, ctxt->calendar_file); @@ -210,59 +318,9 @@ start_calendar_server (GnomePilotConduitStandardAbs *conduit, return -1; } - -static GSList * -get_calendar_objects(GnomePilotConduitStandardAbs *conduit, - gboolean *status, - EToDoConduitContext *ctxt) -{ - GList *uids; - GSList *result = NULL; - - g_return_val_if_fail (conduit != NULL, NULL); - g_return_val_if_fail (ctxt != NULL, NULL); - - uids = cal_client_get_uids (ctxt->client, CALOBJ_TYPE_TODO); - - LOG ("got %d todo entries from cal server\n", g_list_length (uids)); - - if (status != NULL) - (*status) = TRUE; - - if (! uids) - INFO ("No entries found"); - else { - GList *c; - for (c=uids; c; c=c->next) - result = g_slist_prepend (result, (gchar *) c->data); - /* FIX ME free uids */ - } - - return result; -} - - -static void -local_record_from_comp_uid (EToDoLocalRecord *local, - char *uid, - EToDoConduitContext *ctxt) -{ - CalComponent *comp; - CalClientGetStatus status; - - g_assert(local!=NULL); - - status = cal_client_get_object (ctxt->client, uid, &comp); - - if (status == CAL_CLIENT_GET_SUCCESS) - local_record_from_compobject (local, comp); - else - INFO ("Object did not exist"); -} - - - -static const char *gnome_pilot_status_to_string (gint status) +/* Utility routines */ +static const char * +status_to_string (gint status) { switch(status) { case GnomePilotRecordPending: return "GnomePilotRecordPending"; @@ -275,14 +333,37 @@ static const char *gnome_pilot_status_to_string (gint status) return "Unknown"; } +static PilotRecord * +local_record_to_pilot_record (EToDoLocalRecord *local, + EToDoConduitContext *ctxt) +{ + PilotRecord *p = NULL; + + g_return_val_if_fail (local != NULL, NULL); + g_assert (local->comp != NULL); + g_assert (local->todo != NULL ); + + LOG ("local_record_to_remote_record\n"); + + p = g_new0 (PilotRecord, 1); + p->ID = local->local.ID; + p->attr = local->local.attr; + p->archived = local->local.archived; + p->secret = local->local.secret; + + /* Generate pilot record structure */ + p->record = g_new0 (char,0xffff); + p->length = pack_ToDo (local->todo, p->record, 0xffff); + + return p; +} /* * converts a CalComponent object to a EToDoLocalRecord */ -void -local_record_from_compobject(EToDoLocalRecord *local, - CalComponent *comp) +static void +local_record_from_comp (EToDoLocalRecord *local, CalComponent *comp) { int *priority; struct icaltimetype *completed; @@ -295,7 +376,7 @@ local_record_from_compobject(EToDoLocalRecord *local, unsigned long *pilot_id; unsigned long *pilot_status; - LOG ("local_record_from_compobject\n"); + LOG ("local_record_from_comp\n"); g_return_if_fail (local != NULL); g_return_if_fail (comp != NULL); @@ -364,68 +445,23 @@ local_record_from_compobject(EToDoLocalRecord *local, local->local.archived = 0; } - -/* - * Given a PilotRecord, find the matching record in - * the calendar repository. If no match, return NULL - */ -static EToDoLocalRecord * -find_record_in_repository(GnomePilotConduitStandardAbs *conduit, - PilotRecord *remote, - EToDoConduitContext *ctxt) +static void +local_record_from_uid (EToDoLocalRecord *local, + char *uid, + EToDoConduitContext *ctxt) { - char *uid = NULL; - EToDoLocalRecord *loc; - CalClientGetStatus status; CalComponent *comp; - - g_return_val_if_fail(conduit!=NULL,NULL); - g_return_val_if_fail(remote!=NULL,NULL); - - LOG ("find_record_in_repository: remote=%s... ", - print_remote (remote)); + CalClientGetStatus status; - LOG ("requesting %ld", remote->ID); + g_assert(local!=NULL); - status = cal_client_get_uid_by_pilot_id (ctxt->client, remote->ID, &uid); + status = cal_client_get_object (ctxt->client, uid, &comp); if (status == CAL_CLIENT_GET_SUCCESS) { - status = cal_client_get_object (ctxt->client, uid, &comp); - if (status == CAL_CLIENT_GET_SUCCESS) { - LOG ("found %s\n", cal_component_get_as_string (comp)); - loc = g_new0(EToDoLocalRecord,1); - /* memory allocated in new_from_string is freed in free_match */ - local_record_from_compobject (loc, comp); - return loc; - } - LOG ("Pilot ID found, but comp for uid %s was not\n", uid); - } - - INFO ("Object did not exist"); - return NULL; -} - - -/* - * updates an given CalComponent in the repository - */ -static void -update_calendar_entry_in_repository(GnomePilotConduitStandardAbs *conduit, - CalComponent *comp, - EToDoConduitContext *ctxt) -{ - gboolean success; - - g_return_if_fail (conduit != NULL); - g_return_if_fail (comp != NULL); - - LOG (" update_calendar_entry_in_repository " - "saving to desktop\n%s", cal_component_get_as_string (comp)); - - success = cal_client_update_object (ctxt->client, comp); - - if (!success) - WARN (_("Error while communicating with calendar server")); + local_record_from_comp (local, comp); + } else { + INFO ("Object did not exist"); + } } @@ -505,90 +541,34 @@ comp_from_remote_record (GnomePilotConduitStandardAbs *conduit, return comp; } - -/* Code blatantly stolen from - * calendar-pilot-sync.c: - * - * (C) 1999 International GNOME Support - * - * Author: - * Miguel de Icaza (miguel@gnome-support.com) - * - * store a copy of a pilot record in the desktop database - * - */ -static gint -update_record (GnomePilotConduitStandardAbs *conduit, - PilotRecord *remote, - EToDoConduitContext *ctxt) +static void +update_comp (GnomePilotConduitStandardAbs *conduit, CalComponent *comp, + EToDoConduitContext *ctxt) { - CalComponent *comp; - CalClientGetStatus status; - struct ToDo todo; - unsigned long pilot_status = GnomePilotRecordNothing; - char *uid; - - g_return_val_if_fail (remote!=NULL,-1); - - memset (&todo, 0, sizeof (struct ToDo)); - unpack_ToDo (&todo, remote->record, remote->length); - - LOG (" cal_client_get_uid_by_pilot_id... "); - - status = cal_client_get_uid_by_pilot_id (ctxt->client, - remote->ID, &uid); - if (status == CAL_CLIENT_GET_SUCCESS) { - LOG (" succeeded with '%s'\n", uid); - LOG (" cal_client_get_object... "); - status = cal_client_get_object (ctxt->client, uid, &comp); - } - - if (status != CAL_CLIENT_GET_SUCCESS) { - comp = comp_from_remote_record (conduit, remote, NULL); - } else { - CalComponent *new_comp; - - LOG ("succeeded %s\n", cal_component_get_as_string (comp)); - - new_comp = comp_from_remote_record (conduit, remote, comp); - gtk_object_unref (GTK_OBJECT (comp)); - comp = new_comp; - } + gboolean success; - /* update record on server */ - { - const char *uid; - unsigned long *pilot_id; + g_return_if_fail (conduit != NULL); + g_return_if_fail (comp != NULL); - cal_component_get_uid (comp, &uid); - cal_component_get_pilot_id (comp, &pilot_id); - - update_calendar_entry_in_repository (conduit, comp, ctxt); - cal_client_update_pilot_id (ctxt->client, (char *) uid, - *pilot_id, pilot_status); - } + LOG ("update_comp: saving to desktop\n%s\n", + cal_component_get_as_string (comp)); - /* - * Shutdown - */ - gtk_object_unref (GTK_OBJECT (comp)); - free_ToDo(&todo); + success = cal_client_update_object (ctxt->client, comp); - return 0; + if (!success) + WARN (_("Error while communicating with calendar server")); } static void check_for_slow_setting (GnomePilotConduit *c, EToDoConduitContext *ctxt) { - GList *uids; - unsigned long int entry_number; - - uids = cal_client_get_uids (ctxt->client, CALOBJ_TYPE_TODO); - - entry_number = g_list_length (uids); + int count, map_count; - /* If the local base is empty, do a slow sync */ - if (entry_number == 0) { + count = g_list_length (ctxt->uids); + map_count = g_hash_table_size (ctxt->map); + + /* If there are no objects or objects but no log */ + if ((count == 0) || (count > 0 && map_count == 0)) { GnomePilotConduitStandard *conduit; LOG (" doing slow sync\n"); conduit = GNOME_PILOT_CONDUIT_STANDARD (c); @@ -598,24 +578,21 @@ check_for_slow_setting (GnomePilotConduit *c, EToDoConduitContext *ctxt) } } +/* Pilot syncing callbacks */ static gint -pre_sync (GnomePilotConduit *c, +pre_sync (GnomePilotConduit *conduit, GnomePilotDBInfo *dbi, EToDoConduitContext *ctxt) { - int l; + GnomePilotConduitStandardAbs *abs_conduit; + int len, ret; unsigned char *buf; - GnomePilotConduitStandardAbs *conduit; + char *filename; + xmlSAXHandler handler; + GList *changes, *l; gint num_records; - /* - g_log_set_always_fatal (G_LOG_LEVEL_ERROR | - G_LOG_LEVEL_CRITICAL | - G_LOG_LEVEL_WARNING); - */ - - - conduit = GNOME_PILOT_CONDUIT_STANDARD_ABS(c); + abs_conduit = GNOME_PILOT_CONDUIT_STANDARD_ABS (conduit); LOG ("---------------------------------------------------------\n"); LOG ("pre_sync: ToDo Conduit v.%s", CONDUIT_VERSION); @@ -623,102 +600,174 @@ pre_sync (GnomePilotConduit *c, ctxt->client = NULL; - if (start_calendar_server (GNOME_PILOT_CONDUIT_STANDARD_ABS(c), ctxt) != 0) { - WARN(_("Could not start gnomecal server")); - gnome_pilot_conduit_error(GNOME_PILOT_CONDUIT(c), - _("Could not start gnomecal server")); + if (start_calendar_server (ctxt) != 0) { + WARN(_("Could not start wombat server")); + gnome_pilot_conduit_error (conduit, _("Could not start wombat")); return -1; } - + /* Get the local database */ + ctxt->uids = cal_client_get_uids (ctxt->client, CALOBJ_TYPE_TODO); + + /* Load the uid <--> pilot id mapping */ + ctxt->map = g_hash_table_new (g_int_hash, g_int_equal); + memset (&handler, 0, sizeof (xmlSAXHandler)); + handler.startElement = map_sax_start_element; + + filename = map_name (ctxt); + ret = map_sax_parse (&handler, ctxt, filename); + if (ret < 0) + return ret; + + g_free (filename); + + /* Find the added, modified and deleted items */ + changes = cal_client_get_changed_uids (ctxt->client, CALOBJ_TYPE_TODO, 0); + for (l = changes; l != NULL; l = l->next) { + CalObjChange *coc = l->data; + + switch (coc->type) { + case CALOBJ_UPDATED: + if (g_hash_table_lookup (ctxt->map, coc->uid)) + ctxt->modified = g_list_prepend (ctxt->modified, coc); + else + ctxt->added = g_list_prepend (ctxt->added, coc); + break; + case CALOBJ_REMOVED: + ctxt->deleted = g_list_prepend (ctxt->deleted, coc); + break; + } + } + g_list_free (changes); + + /* Set the count information */ num_records = cal_client_get_n_objects (ctxt->client, CALOBJ_TYPE_TODO); - gnome_pilot_conduit_standard_abs_set_num_local_records(GNOME_PILOT_CONDUIT_STANDARD_ABS(c), num_records); + gnome_pilot_conduit_standard_abs_set_num_local_records(abs_conduit, num_records); + num_records = g_list_length (ctxt->added); + gnome_pilot_conduit_standard_abs_set_num_new_local_records (abs_conduit, num_records); + num_records = g_list_length (ctxt->modified); + gnome_pilot_conduit_standard_abs_set_num_updated_local_records (abs_conduit, num_records); + num_records = g_list_length (ctxt->deleted); + gnome_pilot_conduit_standard_abs_set_num_deleted_local_records(abs_conduit, num_records); - /* FIX ME How are we going to fill in these fields? */ - num_records = 0; - gnome_pilot_conduit_standard_abs_set_num_updated_local_records(GNOME_PILOT_CONDUIT_STANDARD_ABS(c), num_records); - gnome_pilot_conduit_standard_abs_set_num_new_local_records(GNOME_PILOT_CONDUIT_STANDARD_ABS(c), num_records); - gnome_pilot_conduit_standard_abs_set_num_deleted_local_records(GNOME_PILOT_CONDUIT_STANDARD_ABS(c), num_records); + gtk_object_set_data (GTK_OBJECT (conduit), "dbinfo", dbi); - gtk_object_set_data (GTK_OBJECT(c), "dbinfo", dbi); - buf = (unsigned char*)g_malloc (0xffff); - l = dlp_ReadAppBlock (dbi->pilot_socket, dbi->db_handle, 0, + len = dlp_ReadAppBlock (dbi->pilot_socket, dbi->db_handle, 0, (unsigned char *)buf, 0xffff); - if (l < 0) { - WARN(_("Could not read pilot's ToDo application block")); - WARN("dlp_ReadAppBlock(...) = %d",l); - gnome_pilot_conduit_error(GNOME_PILOT_CONDUIT(c), - _("Could not read pilot's ToDo application block")); + if (len < 0) { + WARN (_("Could not read pilot's ToDo application block")); + WARN ("dlp_ReadAppBlock(...) = %d", len); + gnome_pilot_conduit_error (conduit, + _("Could not read pilot's ToDo application block")); return -1; } - unpack_ToDoAppInfo (&(ctxt->ai), buf, l); + unpack_ToDoAppInfo (&(ctxt->ai), buf, len); g_free (buf); - check_for_slow_setting (c, ctxt); + check_for_slow_setting (conduit, ctxt); return 0; } -/** - * Find (if possible) the local record which matches - * the given PilotRecord. - * if successfull, return non-zero and set *local to - * a non-null value (the located local record), - * otherwise return 0 and set *local = NULL; - */ +static gint +update_record (GnomePilotConduitStandardAbs *conduit, + PilotRecord *remote, + EToDoConduitContext *ctxt) +{ + CalComponent *comp; + CalClientGetStatus status; + struct ToDo todo; + const char *uid; + + LOG ("update_record\n"); + + g_return_val_if_fail (remote != NULL, -1); + + memset (&todo, 0, sizeof (struct ToDo)); + unpack_ToDo (&todo, remote->record, remote->length); + + uid = g_hash_table_lookup (ctxt->map, &remote->ID); + + if (uid) + status = cal_client_get_object (ctxt->client, uid, &comp); + else + status = CAL_CLIENT_LOAD_ERROR; + + if (status != CAL_CLIENT_GET_SUCCESS) { + comp = comp_from_remote_record (conduit, remote, NULL); + } else { + CalComponent *new_comp; + + LOG ("succeeded %s\n", cal_component_get_as_string (comp)); + + new_comp = comp_from_remote_record (conduit, remote, comp); + gtk_object_unref (GTK_OBJECT (comp)); + comp = new_comp; + } + + update_comp (conduit, comp, ctxt); + + if (!uid) { + guint32 *pid = g_new (guint32, 1); + + *pid = remote->ID; + cal_component_get_uid (comp, &uid); + g_hash_table_insert (ctxt->map, pid, g_strdup (uid)); + } + + gtk_object_unref (GTK_OBJECT (comp)); + free_ToDo(&todo); + + return 0; +} static gint -match_record (GnomePilotConduitStandardAbs *conduit, - EToDoLocalRecord **local, - PilotRecord *remote, - EToDoConduitContext *ctxt) +match_record (GnomePilotConduitStandardAbs *conduit, + EToDoLocalRecord **local, + PilotRecord *remote, + EToDoConduitContext *ctxt) { + char *uid; + LOG ("match_record: looking for local copy of %s\n", - print_remote (remote)); - + print_remote (remote)); + g_return_val_if_fail (local != NULL, -1); g_return_val_if_fail (remote != NULL, -1); - *local = find_record_in_repository (conduit, remote, ctxt); + uid = g_hash_table_lookup (ctxt->map, &remote->ID); + + if (!uid) + return -1; + *local = g_new0 (EToDoLocalRecord, 1); + local_record_from_uid (*local, uid, ctxt); + if (*local == NULL) - LOG (" match_record: not found.\n"); - else - LOG (" match_record: found, %s\n", - print_local (*local)); - - if (*local == NULL) return -1; - + return 0; } -/** - * Free the data allocated by a previous match_record call. - * If successfull, return non-zero and ser *local=NULL, otherwise - * return 0. - */ static gint -free_match (GnomePilotConduitStandardAbs *conduit, - EToDoLocalRecord **local, - EToDoConduitContext *ctxt) +free_match (GnomePilotConduitStandardAbs *conduit, + EToDoLocalRecord **local, + EToDoConduitContext *ctxt) { LOG ("free_match: %s\n", print_local (*local)); g_return_val_if_fail (local != NULL, -1); g_return_val_if_fail (*local != NULL, -1); + gtk_object_unref (GTK_OBJECT ((*local)->comp)); g_free (*local); *local = NULL; return 0; } -/* - Move to archive and set status to Nothing - */ static gint archive_local (GnomePilotConduitStandardAbs *conduit, EToDoLocalRecord *local, @@ -731,9 +780,6 @@ archive_local (GnomePilotConduitStandardAbs *conduit, return -1; } -/* - Store in archive and set status to Nothing - */ static gint archive_remote (GnomePilotConduitStandardAbs *conduit, EToDoLocalRecord *local, @@ -741,30 +787,29 @@ archive_remote (GnomePilotConduitStandardAbs *conduit, EToDoConduitContext *ctxt) { LOG ("archive_remote: doing nothing with %s\n", - print_local (local)); - -/* g_return_val_if_fail(remote!=NULL,-1); */ -/* g_return_val_if_fail(local!=NULL,-1); */ - + print_local (local)); + + g_return_val_if_fail (remote != NULL, -1); + g_return_val_if_fail (local != NULL, -1); + return -1; } -/* - Store and set status to Nothing - */ static gint store_remote (GnomePilotConduitStandardAbs *conduit, PilotRecord *remote, EToDoConduitContext *ctxt) { + int ret; + g_return_val_if_fail (remote != NULL, -1); LOG ("store_remote: copying pilot record %s to desktop\n", print_remote (remote)); - remote->attr = GnomePilotRecordNothing; + ret = update_record (conduit, remote, ctxt); - return update_record (conduit, remote, ctxt); + return ret; } static gint @@ -784,59 +829,48 @@ iterate (GnomePilotConduitStandardAbs *conduit, EToDoLocalRecord **local, EToDoConduitContext *ctxt) { - static GSList *events,*iterator; - static int hest; + static GList *uids, *iterator; + static int count; g_return_val_if_fail (local != NULL, -1); if (*local == NULL) { LOG ("beginning iteration"); - events = get_calendar_objects (conduit, NULL, ctxt); - hest = 0; + uids = ctxt->uids; + count = 0; - if (events != NULL) { - LOG ("iterating over %d records", g_slist_length (events)); + if (uids != NULL) { + LOG ("iterating over %d records", g_list_length (uids)); + *local = g_new0 (EToDoLocalRecord, 1); + local_record_from_uid (*local, uids->data, ctxt); - local_record_from_comp_uid (*local, - (gchar*)events->data, - ctxt); - iterator = events; + iterator = uids; } else { LOG ("no events"); (*local) = NULL; + return -1; } } else { - LOG ("continuing iteration\n"); - hest++; - if (g_slist_next (iterator) == NULL) { - GSList *l; + count++; + if (g_list_next (iterator)) { + iterator = g_list_next (iterator); - LOG ("ending"); - /** free stuff allocated for iteration */ - g_free((*local)); - - LOG ("iterated over %d records", hest); - for (l=events; l; l = l->next) - g_free (l->data); + *local = g_new0 (EToDoLocalRecord, 1); + local_record_from_uid (*local, iterator->data, ctxt); + } else { + LOG ("iteration ending"); - g_slist_free (events); + /* Tell the pilot the iteration is over */ + *local = NULL; - /* ends iteration */ - (*local) = NULL; return 0; - } else { - iterator = g_slist_next (iterator); - local_record_from_comp_uid(*local, - (gchar*)(iterator->data), - ctxt); } } return 1; } - static gint iterate_specific (GnomePilotConduitStandardAbs *conduit, EToDoLocalRecord **local, @@ -844,44 +878,88 @@ iterate_specific (GnomePilotConduitStandardAbs *conduit, gint archived, EToDoConduitContext *ctxt) { - (*local) = NULL; /* ??? */ + static GList *changes, *iterator; + static int count; - /* debugging */ - { - const char *tmp = gnome_pilot_status_to_string (flag); - LOG ("\niterate_specific: (flag = %s)... ", tmp); - } + g_return_val_if_fail (local != NULL, 0); - g_return_val_if_fail (local != NULL, -1); + /* FIX ME Hack - gnome-pilot does not recognize iterate_specific err values */ + if (*local == NULL) { + LOG ("beginning iteration for %s\n", status_to_string (flag)); - /* iterate until a record meets the criteria */ - while (gnome_pilot_conduit_standard_abs_iterate (conduit, - (LocalRecord**)local)) { - if ((*local) == NULL) + switch (flag) { + case GnomePilotRecordNew: + changes = ctxt->added; break; - if (archived && ((*local)->local.archived == archived)) + case GnomePilotRecordModified: + changes = ctxt->modified; break; - if (((*local)->local.attr == flag)) + case GnomePilotRecordDeleted: + changes = ctxt->deleted; break; - } + } + + count = 0; + + if (changes != NULL) { + CalObjChange *coc = changes->data; + + LOG ("iterating over %d records", g_list_length (changes)); + + *local = g_new0 (EToDoLocalRecord, 1); + local_record_from_uid (*local, coc->uid, ctxt); - if ((*local)) - LOG (" found %s\n", print_local (*local)); - else - LOG (" no more found.\n"); + iterator = changes; + } else { + LOG ("no events"); + (*local) = NULL; + return 0; + } + } else { + count++; + if (g_list_next (iterator)) { + CalObjChange *coc; + + iterator = g_list_next (iterator); + coc = iterator->data; + + *local = g_new0 (EToDoLocalRecord, 1); + local_record_from_uid (*local, coc->uid, ctxt); + } else { + LOG ("iteration ending"); - return (*local) == NULL ? 0 : 1; + /* Tell the pilot the iteration is over */ + (*local) = NULL; + + return 0; + } + } + + return 1; } static gint purge (GnomePilotConduitStandardAbs *conduit, EToDoConduitContext *ctxt) { - LOG ("purge: doing nothing\n"); + GList *l; + char *filename; + int ret = 0; + + LOG ("purge\n"); + + /* FIX ME report an error */ + for (l = ctxt->deleted; l != NULL; l = l->next) { + CalObjChange *coc = l->data; + + cal_client_remove_object (ctxt->client, coc->uid); + } - /* HEST, gem posterne her */ + filename = map_name (ctxt); + ret = map_write (ctxt, filename); + g_free (filename); - return -1; + return ret; } @@ -891,37 +969,28 @@ set_status (GnomePilotConduitStandardAbs *conduit, gint status, EToDoConduitContext *ctxt) { - gboolean success; - - LOG ("set_status: %s status is now '%s' for %s\n", - print_local (local), - gnome_pilot_status_to_string (status), - cal_component_get_as_string (local->comp)); + CalObjChange *coc; g_return_val_if_fail (local != NULL, -1); g_assert (local->comp != NULL); - - local->local.attr = status; - if (status == GnomePilotRecordDeleted) { - const char *uid; - cal_component_get_uid (local->comp, &uid); - success = cal_client_remove_object (ctxt->client, uid); - } else { - const char *uid; - unsigned long *pilot_id; - cal_component_get_uid (local->comp, &uid); - cal_component_get_pilot_id (local->comp, &pilot_id); + LOG ("set_status: %s status is now '%s' for %s\n", + print_local (local), + status_to_string (status), + cal_component_get_as_string (local->comp)); - success = cal_client_update_object (ctxt->client, local->comp); - cal_client_update_pilot_id (ctxt->client, (char *) uid, - *pilot_id, status); + /* FIX ME New and modified? */ + switch (status) { + case GnomePilotRecordNew: + break; + case GnomePilotRecordModified: + break; + case GnomePilotRecordDeleted: + coc = g_new0 (CalObjChange, 1); + ctxt->deleted = g_list_prepend (ctxt->deleted, coc); + break; } - if (!success) { - WARN (_("Error while communicating with calendar server")); - } - return 0; } @@ -938,10 +1007,12 @@ set_archived (GnomePilotConduitStandardAbs *conduit, g_assert(local->comp!=NULL); local->local.archived = archived; - update_calendar_entry_in_repository(conduit,local->comp,ctxt); + update_comp (conduit, local->comp, ctxt); + /* FIXME: This should move the entry into a speciel calendar file, eg. Archive, or (by config option), simply delete it */ + return 0; } @@ -952,24 +1023,11 @@ set_pilot_id (GnomePilotConduitStandardAbs *conduit, EToDoConduitContext *ctxt) { const char *uid; - unsigned long *pilot_status; - - LOG ("set_pilot_id: %s pilot ID is now '%d'\n", - print_local (local), ID); - - g_return_val_if_fail(local!=NULL,-1); - g_assert(local->comp!=NULL); - - local->local.ID = ID; - cal_component_set_pilot_id (local->comp, (unsigned long *)&ID); - + guint32 *pid = g_new (guint32, 1); + cal_component_get_uid (local->comp, &uid); - cal_component_get_pilot_status (local->comp, &pilot_status); - - cal_client_update_pilot_id (ctxt->client, - (char *) uid, - local->local.ID, - *pilot_status); + *pid = ID; + g_hash_table_insert (ctxt->map, pid, g_strdup (uid)); return 0; } @@ -980,80 +1038,13 @@ transmit (GnomePilotConduitStandardAbs *conduit, PilotRecord **remote, EToDoConduitContext *ctxt) { - PilotRecord *p; - int *priority; - struct icaltimetype *completed; - CalComponentText summary; - GSList *d_list = NULL; - CalComponentText *description; - CalComponentDateTime due; - time_t due_time; - CalComponentClassification classif; - LOG ("transmit: encoding local %s\n", print_local (local)); - g_return_val_if_fail (local != NULL,-1); - g_return_val_if_fail (remote != NULL,-1); - g_assert (local->comp != NULL); - - p = g_new0 (PilotRecord,1); - - p->ID = local->local.ID; - p->attr = local->local.attr; - p->archived = local->local.archived; - p->secret = local->local.secret; - - local->todo = g_new0 (struct ToDo,1); - - /* STOP: don't replace these with g_strdup, since free_ToDo - uses free to deallocate */ - cal_component_get_summary (local->comp, &summary); - if (summary.value) - local->todo->description = strdup ((char *) summary.value); - - cal_component_get_description_list (local->comp, &d_list); - if (d_list) { - description = (CalComponentText *) d_list->data; - if (description && description->value) - local->todo->note = strdup (description->value); - else - local->todo->note = NULL; - } else { - local->todo->note = NULL; - } - - cal_component_get_due (local->comp, &due); - if (due.value) { - due_time = icaltime_as_timet (*due.value); - - local->todo->due = *localtime (&due_time); - local->todo->indefinite = 0; - } else { - local->todo->indefinite = 1; - } - - cal_component_get_completed (local->comp, &completed); - if (completed) { - local->todo->complete = 1; - cal_component_free_icaltimetype (completed); - } - - cal_component_get_priority (local->comp, &priority); - if (priority) { - local->todo->priority = *priority; - cal_component_free_priority (priority); - } - - cal_component_get_classification (local->comp, &classif); - if (classif == CAL_COMPONENT_CLASS_PRIVATE) - p->attr = p->attr & dlpRecAttrSecret; - - /* Generate pilot record structure */ - p->record = g_new0 (char,0xffff); - p->length = pack_ToDo (local->todo, p->record, 0xffff); - - *remote = p; + *remote = local_record_to_pilot_record (local, ctxt); + if (!*remote) + return -1; + return 0; } @@ -1063,14 +1054,12 @@ free_transmit (GnomePilotConduitStandardAbs *conduit, PilotRecord **remote, EToDoConduitContext *ctxt) { - LOG ("free_transmit: freeing %s\n", - print_local (local)); + LOG ("free_transmit: freeing %s\n", print_local (local)); g_return_val_if_fail (local != NULL, -1); g_return_val_if_fail (remote != NULL, -1); - /* free_ToDo(local->todo); */ /* FIX ME is this needed? */ - g_free ((*remote)->record); + g_free (*remote); *remote = NULL; return 0; @@ -1084,9 +1073,8 @@ compare (GnomePilotConduitStandardAbs *conduit, EToDoConduitContext *ctxt) { /* used by the quick compare */ - PilotRecord *remoteOfLocal; - int err; - int retval; + PilotRecord *local_pilot; + int retval = 0; LOG ("compare: local=%s remote=%s...\n", print_local (local), print_remote (remote)); @@ -1094,31 +1082,21 @@ compare (GnomePilotConduitStandardAbs *conduit, g_return_val_if_fail (local!=NULL,-1); g_return_val_if_fail (remote!=NULL,-1); - err = transmit(conduit,local,&remoteOfLocal,ctxt); - if (err != 0) return err; + local_pilot = local_record_to_pilot_record (local, ctxt); + if (!local_pilot) + return -1; - retval = 0; - if (remote->length == remoteOfLocal->length) { - if (memcmp (remoteOfLocal->record, - remote->record, remote->length)!=0) { - LOG (" compare failed on contents\n"); - retval = 1; - } - } else { - LOG(" compare failed on length\n"); + if (remote->length != local_pilot->length + || memcmp (local_pilot->record, remote->record, remote->length)) retval = 1; - } - - if (retval == 0) { + if (retval == 0) LOG (" match.\n"); - } else { - /* debug spew */ - LOG (" local:%s\n", print_remote (remoteOfLocal)); - LOG (" remote:%s\n", print_remote (remote)); - } - - free_transmit(conduit,local,&remoteOfLocal,ctxt); + else + LOG (" did not match"); + + g_free (local_pilot); + return retval; } @@ -1134,6 +1112,8 @@ compare_backup (GnomePilotConduitStandardAbs *conduit, g_return_val_if_fail(local!=NULL,-1); g_return_val_if_fail(remote!=NULL,-1); + /* FIX ME - What the hell? */ + return -1; } @@ -1142,25 +1122,21 @@ static gint delete_all (GnomePilotConduitStandardAbs *conduit, EToDoConduitContext *ctxt) { - GSList *events,*it; - gboolean error; + GList *uids, *it; gboolean success; - events = get_calendar_objects(conduit,&error,ctxt); - LOG ("delete_all: deleting all objects from desktop\n"); - if (error == FALSE) return -1; - for (it=events; it; it = g_slist_next (it)) { + uids = cal_client_get_uids (ctxt->client, CALOBJ_TYPE_TODO); + + for (it = uids; it != NULL; it = g_list_next (it)) { success = cal_client_remove_object (ctxt->client, it->data); if (!success) INFO ("Object did not exist"); - - g_free (it->data); } + cal_obj_uid_list_free (uids); - g_slist_free (events); return 0; } @@ -1176,7 +1152,7 @@ accept_all_cookies (CORBA_unsigned_long request_id, GnomePilotConduit * -conduit_get_gpilot_conduit (guint32 pilotId) +conduit_get_gpilot_conduit (guint32 pilot_id) { GtkObject *retval; EToDoConduitContext *ctxt; @@ -1202,9 +1178,9 @@ conduit_get_gpilot_conduit (guint32 pilotId) g_assert (retval != NULL); gnome_pilot_conduit_construct (GNOME_PILOT_CONDUIT (retval), - "ToDoConduit"); + "e_todo_conduit"); - e_todo_context_new (&ctxt, pilotId); + e_todo_context_new (&ctxt, pilot_id); gtk_object_set_data (GTK_OBJECT (retval), "todoconduit_context", ctxt); gtk_signal_connect (retval, "match_record", (GtkSignalFunc) match_record, ctxt); diff --git a/calendar/conduits/todo/todo-conduit.h b/calendar/conduits/todo/todo-conduit.h index ee2576ddb7..9e9a02e6db 100644 --- a/calendar/conduits/todo/todo-conduit.h +++ b/calendar/conduits/todo/todo-conduit.h @@ -54,16 +54,28 @@ struct _EToDoLocalRecord { /* This is the context for all the GnomeCal conduit methods. */ typedef struct _EToDoConduitContext EToDoConduitContext; struct _EToDoConduitContext { - struct ToDoAppInfo ai; EToDoConduitCfg *cfg; - CalClient *client; + struct ToDoAppInfo ai; + + CalClient *client; + char *calendar_file; gboolean calendar_load_tried; gboolean calendar_load_success; - char *calendar_file; + GList *uids; + + GList *added; + GList *modified; + GList *deleted; + + GHashTable *map; }; #endif __TODO_CONDUIT_H__ + + + + diff --git a/calendar/idl/evolution-calendar.idl b/calendar/idl/evolution-calendar.idl index 4b9b9a7b34..27c7971057 100644 --- a/calendar/idl/evolution-calendar.idl +++ b/calendar/idl/evolution-calendar.idl @@ -33,6 +33,11 @@ module Calendar { const CalObjType TYPE_JOURNAL = 1 << 2; const CalObjType TYPE_ANY = 0x07; + /* Types of object changes made */ + typedef long CalObjChangeType; + const CalObjChangeType UPDATED = 1 << 0; + const CalObjChangeType REMOVED = 1 << 1; + /* Types of alarms */ enum AlarmType { MAIL, @@ -61,6 +66,12 @@ module Calendar { typedef sequence<CalObjInstance> CalObjInstanceSeq; + /* An object change */ + struct CalObjChange { + CalObjUID uid; + CalObjChangeType type; + }; + /* An alarm trigger instance */ struct CalAlarmInstance { CalObjUID uid; @@ -71,6 +82,8 @@ module Calendar { typedef sequence<CalAlarmInstance> CalAlarmInstanceSeq; + typedef sequence<CalObjChange> CalObjChangeSeq; + interface Listener; /* Calendar client interface */ @@ -92,6 +105,9 @@ module Calendar { /* Gets a list of UIDs based on object type */ CalObjUIDSeq get_uids (in CalObjType type); + /* Gets a list of UIDs that changed based on object type */ + CalObjChangeSeq get_changed_uids (in CalObjType type, in Time_t since); + /* Gets a list of objects that occur or recur in the specified time range */ CalObjUIDSeq get_objects_in_range (in CalObjType type, in Time_t start, in Time_t end) 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 <federico@helixcode.com> - * Seth Alves <alves@helixcode.com> - * Miguel de Icaza <miguel@helixcode.com> - * - * 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 <config.h> -#include <gtk/gtksignal.h> -#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 <federico@helixcode.com> - * Seth Alves <alves@helixcode.com> - * Miguel de Icaza <miguel@helixcode.com> - * - * 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 <libgnome/gnome-defs.h> -#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 <config.h> -#include <gtk/gtksignal.h> +#include <gtk/gtk.h> +#include <gnome-xml/parser.h> +#include <gnome-xml/parserInternals.h> +#include <gnome-xml/xmlmemory.h> #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 <libgnome/gnome-defs.h> #include <libgnomevfs/gnome-vfs.h> #include <cal-util/cal-util.h> +#include <cal-util/cal-component.h> #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; |