aboutsummaryrefslogtreecommitdiffstats
path: root/calendar/pcs/cal-backend.c
diff options
context:
space:
mode:
authorJP Rosevear <jpr@helixcode.com>2000-09-20 06:48:47 +0800
committerJP Rosevear <jpr@src.gnome.org>2000-09-20 06:48:47 +0800
commit58b5fd92fc9f5419beabe82d38622aba064cc56e (patch)
treea8219b9cc9b1311466f9854b0fa673045250edb1 /calendar/pcs/cal-backend.c
parent6820bb50e53b479997ae5a9616186301c333fad8 (diff)
downloadgsoc2013-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/pcs/cal-backend.c')
-rw-r--r--calendar/pcs/cal-backend.c380
1 files changed, 375 insertions, 5 deletions
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);
}
+
+
+
+