aboutsummaryrefslogtreecommitdiffstats
path: root/calendar/pcs
diff options
context:
space:
mode:
authorFederico Mena Quintero <federico@helixcode.com>2000-05-09 00:58:27 +0800
committerFederico Mena Quintero <federico@src.gnome.org>2000-05-09 00:58:27 +0800
commit8160d7388e27c6f97e3ed96bc5d61fbf20ff2d16 (patch)
treeff1ff2df49f02deccc5424fdf6004f1b90e05553 /calendar/pcs
parentc2dde9ab64a79b483804cddbd9622827b4b2baf2 (diff)
downloadgsoc2013-evolution-8160d7388e27c6f97e3ed96bc5d61fbf20ff2d16.tar
gsoc2013-evolution-8160d7388e27c6f97e3ed96bc5d61fbf20ff2d16.tar.gz
gsoc2013-evolution-8160d7388e27c6f97e3ed96bc5d61fbf20ff2d16.tar.bz2
gsoc2013-evolution-8160d7388e27c6f97e3ed96bc5d61fbf20ff2d16.tar.lz
gsoc2013-evolution-8160d7388e27c6f97e3ed96bc5d61fbf20ff2d16.tar.xz
gsoc2013-evolution-8160d7388e27c6f97e3ed96bc5d61fbf20ff2d16.tar.zst
gsoc2013-evolution-8160d7388e27c6f97e3ed96bc5d61fbf20ff2d16.zip
CalBackendClass now is just an interface for calendar backends; this is an
2000-05-08 Federico Mena Quintero <federico@helixcode.com> * pcs/cal-backend.h (CalBackendClass): CalBackendClass now is just an interface for calendar backends; this is an abstract class. Put in the vtable for the backend methods. * pcs/cal-backend.c (cal_backend_new): Removed function, since CalBackend is not just an abstract class. Removed implementation-specific functions and made public functions call the virtual methods instead. * pcs/cal-backend-imc.[ch]: New files with the CalBackendIMC implementation; this implements a backend for iCalendar and vCalendar files. Moved the implementation-specific stuff from cal-backend.[ch] to here. * pcs/cal-backend-imc.c (CalendarFormat): Moved enumeration to here. Added a CAL_UNKNOWN value for when the backend is not loaded yet. (cal_backend_imc_init): Initialize priv->format as CAL_UNKNOWN. (save_to_vcal): Use the same VCProdIdProp value as in cal-util/calobj.c. Use "1.0" as the VCVersionProp as per the vCalendar spec. (ensure_uid): Return nothing, since the result value need not be used anymore. (add_object): Since we mark the calendar as dirty anyways, we do not need to check the result value of ensure_uid() anymore. (remove_object): Asssert that we know how to handle the object's type. We do this in add_object() anyways. * pcs/Makefile.am (libpcs_a_SOURCES): Added cal-backend-imc.[ch]. * gui/gnome-cal.c: Replaced debugging printf()s with g_message() so that we can see the line number where they occur. * gui/gnome-cal.c (gnome_calendar_load_cb): Sort of handle the LOAD_METHOD_NOT_SUPPORTED result code, and added a default for the switch. * cal-client/cal-listener.h (CalListenerLoadStatus): Removed enumeration; it is stupid to translate all values for the CalClient when it is going to translate them again. (CalListenerClass::cal_loaded): This signal now passes the LoadStatus directly from the CORBA side. * cal-client/cal-listener.c (Listener_cal_loaded): Do not translate the status value. * cal-client/cal-client.h (CalClientLoadStatus): Added the CAL_CLIENT_LOAD_METHOD_NOT_SUPPORTED error code. * cal-client/cal-client.c (cal_loaded_cb): Translate the CORBA version of the LoadStatus result code. * pcs/cal-factory.c (CalFactoryPrivate): New methods field for the hash table from method strings to the GtkTypes for backend class types. (cal_factory_init): Create the priv->methods hash table. (cal_factory_destroy): Free the priv->methods hash table. (cal_factory_register_method): New function to register a backend class for a particular URI method. (launch_backend_for_uri): New function to launch a backend for a particular URI's method. (load_backend): Use launch_backend_for_uri(). Move the error notification code from load_fn() to here. (create_backend): Use launch_backend_for_uri(). Move the error notification code form create_fn() to here; it is #ifdefed out since currently cal_backend_create() does not have any error reporting capabilities. * idl/evolution-calendar.idl (Listener::LoadStatus): Added a PROTOCOL_NOT_SUPPORTED error code. * pcs/cal-factory.c (cal_factory_load cal_factory_create): Removed functions, since they were supposed to be internal only. (CalFactory_load): Call queue_load_create_job() directly. (CalFactory_create): Likewise. svn path=/trunk/; revision=2921
Diffstat (limited to 'calendar/pcs')
-rw-r--r--calendar/pcs/Makefile.am2
-rw-r--r--calendar/pcs/cal-backend-imc.c1068
-rw-r--r--calendar/pcs/cal-backend-imc.h60
-rw-r--r--calendar/pcs/cal-backend.c933
-rw-r--r--calendar/pcs/cal-backend.h23
-rw-r--r--calendar/pcs/cal-factory.c422
-rw-r--r--calendar/pcs/cal-factory.h3
7 files changed, 1443 insertions, 1068 deletions
diff --git a/calendar/pcs/Makefile.am b/calendar/pcs/Makefile.am
index b9ea5fecd0..b496659f03 100644
--- a/calendar/pcs/Makefile.am
+++ b/calendar/pcs/Makefile.am
@@ -28,6 +28,8 @@ libpcs_a_SOURCES = \
cal.h \
cal-backend.c \
cal-backend.h \
+ cal-backend-imc.c \
+ cal-backend-imc.h \
cal-common.h \
cal-factory.c \
cal-factory.h \
diff --git a/calendar/pcs/cal-backend-imc.c b/calendar/pcs/cal-backend-imc.c
new file mode 100644
index 0000000000..29c806a89f
--- /dev/null
+++ b/calendar/pcs/cal-backend-imc.c
@@ -0,0 +1,1068 @@
+/* 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>
+ *
+ * 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 "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 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 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 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_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->update_object = cal_backend_imc_update_object;
+ backend_class->remove_object = cal_backend_imc_remove_object;
+
+ 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_destroy (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:
+ 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_destroy (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;
+
+ 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;
+
+ 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 */
+
+ gnome_vfs_uri_ref (uri);
+
+ priv->uri = uri;
+ priv->loaded = TRUE;
+
+ save (cbimc);
+}
+
+/* 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;
+ else
+ store = (c->type & CALOBJ_TYPE_OTHER) ? 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);
+
+ /* We go through the hash table instead of the lists of particular
+ * object types so that we can pick up CALOBJ_TYPE_OTHER objects.
+ */
+ c.type = type;
+ c.uid_list = NULL;
+ g_hash_table_foreach (priv->object_hash, build_uids_list, &c);
+
+ return c.uid_list;
+}
+
+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 = g_new (CalObjInstance, 1);
+
+ g_assert (ico->uid != NULL);
+ icoi->uid = g_strdup (ico->uid);
+ icoi->start = start;
+ icoi->end = 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)
+{
+ struct build_event_list_closure c;
+ GList *l;
+
+ CalBackendIMC *cbimc;
+ IMCPrivate *priv;
+
+ 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;
+}
+
+/* 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);
+ 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
new file mode 100644
index 0000000000..b0fa93611e
--- /dev/null
+++ b/calendar/pcs/cal-backend-imc.h
@@ -0,0 +1,60 @@
+/* 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>
+ *
+ * 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 3aed2a41fa..27cc3e53ce 100644
--- a/calendar/pcs/cal-backend.c
+++ b/calendar/pcs/cal-backend.c
@@ -1,5 +1,5 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/* Evolution calendar backend
+/* Evolution calendar - generic backend class
*
* Copyright (C) 2000 Helix Code, Inc.
*
@@ -25,39 +25,6 @@
#include <cal-util/calobj.h>
#include "cal-backend.h"
#include "libversit/vcc.h"
-#include "icalendar.h"
-
-
-
-
-/* Private part of the CalBackend structure */
-typedef struct {
- /* URI where the calendar data is stored */
- GnomeVFSURI *uri;
-
- /* format of this calendar (ical or vcal) */
- 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;
-} CalBackendPrivate;
@@ -68,13 +35,13 @@ enum {
};
static void cal_backend_class_init (CalBackendClass *class);
-static void cal_backend_init (CalBackend *backend);
-static void cal_backend_destroy (GtkObject *object);
static GtkObjectClass *parent_class;
static guint cal_backend_signals[LAST_SIGNAL];
+#define CLASS(backend) (CAL_BACKEND_CLASS (GTK_OBJECT (backend)->klass))
+
/**
@@ -97,7 +64,7 @@ cal_backend_get_type (void)
sizeof (CalBackend),
sizeof (CalBackendClass),
(GtkClassInitFunc) cal_backend_class_init,
- (GtkObjectInitFunc) cal_backend_init,
+ (GtkObjectInitFunc) NULL,
NULL, /* reserved_1 */
NULL, /* reserved_2 */
(GtkClassInitFunc) NULL
@@ -129,391 +96,11 @@ cal_backend_class_init (CalBackendClass *class)
GTK_TYPE_NONE, 0);
gtk_object_class_add_signals (object_class, cal_backend_signals, LAST_SIGNAL);
-
- object_class->destroy = cal_backend_destroy;
-}
-
-/* Object initialization function for the calendar backend */
-static void
-cal_backend_init (CalBackend *backend)
-{
- CalBackendPrivate *priv;
-
- priv = g_new0 (CalBackendPrivate, 1);
- backend->priv = priv;
-
- /* FIXME can be CAL_VCAL or CAL_ICAL */
- priv->format = CAL_VCAL;
-}
-
-static void
-save_to_vcal (CalBackend *backend, char *fname)
-{
- FILE *fp;
- CalBackendPrivate *priv = backend->priv;
- VObject *vcal;
- GList *l;
-
- if (g_file_exists (fname)){
- char *backup_name = g_strconcat (fname, "~", NULL);
-
- if (g_file_exists (backup_name)){
- unlink (backup_name);
- }
- rename (fname, backup_name);
- g_free (backup_name);
- }
-
- vcal = newVObject (VCCalProp);
- addPropValue (vcal, VCProdIdProp,
- "-//GNOME//NONSGML GnomeCalendar//EN");
- addPropValue (vcal, VCVersionProp, VERSION);
-
- 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 (CalBackend *backend)
-{
- char *str_uri;
- CalBackendPrivate *priv = backend->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_VCAL:
- save_to_vcal (backend, str_uri);
- break;
- case CAL_ICAL:
- /*icalendar_calendar_save (backend, str_uri);*/
- /* FIX ME */
- break;
- default:
- /* FIX ME log */
- break;
- }
-
- printf ("cal-backend: '%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_destroy (ico);
-}
-
-/* Destroys a backend's data */
-static void
-destroy (CalBackend *backend)
-{
- CalBackendPrivate *priv;
-
- priv = backend->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;
-}
-
-/* Destroy handler for the calendar backend */
-static void
-cal_backend_destroy (GtkObject *object)
-{
- CalBackend *backend;
- CalBackendPrivate *priv;
-
- g_return_if_fail (object != NULL);
- g_return_if_fail (IS_CAL_BACKEND (object));
-
- backend = CAL_BACKEND (object);
- priv = backend->priv;
-
- /*
- if (priv->loaded)
- save (backend);
- */
-
- destroy (backend);
-
- g_free (priv);
-
- 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 (CalBackend *backend, const char *uid)
-{
- CalBackendPrivate *priv;
- iCalObject *ico;
-
- priv = backend->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. Returns whether an UID was created or not.
- */
-static gboolean
-ensure_uid (iCalObject *ico)
-{
- char *buf;
- gulong str_time;
- static guint seqno = 0;
-
- if (ico->uid){
- return FALSE;
- }
-
- str_time = (gulong) time (NULL);
-
- /* Is this good enough? */
-
- buf = g_strdup_printf ("Evolution-Tlacuache-%d-%ld-%u",
- (int) getpid(), str_time, seqno++);
- ico->uid = buf;
- return TRUE;
-}
-
-/* Adds an object to the calendar backend. Does *not* perform notification to
- * calendar clients.
- */
-static void
-add_object (CalBackend *backend, iCalObject *ico)
-{
- CalBackendPrivate *priv;
-
- g_assert (ico != NULL);
- priv = backend->priv;
-
-#if 0
- /* FIXME: gnomecal old code */
- ico->new = 0;
-#endif
-
- if (ensure_uid (ico))
- /* FIXME: mark the calendar as dirty so that we can re-save it
- * with the object's new UID.
- */
- ;
-
- 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 (CalBackend *backend, iCalObject *ico)
-{
- CalBackendPrivate *priv;
- GList **list, *l;
-
- priv = backend->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:
- list = NULL;
- }
-
- if (!list){
- return;
- }
-
- l = g_list_find (*list, ico);
- g_assert (l != NULL);
-
- *list = g_list_remove_link (*list, l);
- g_list_free_1 (l);
-
- ical_object_destroy (ico);
-}
-
-/* Load a calendar from a VObject */
-static void
-load_from_vobject (CalBackend *backend, VObject *vobject)
-{
- CalBackendPrivate *priv;
- VObjectIterator i;
-
- priv = backend->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 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 (backend, ical);
- }
}
/**
- * cal_backend_new:
- * @void:
- *
- * Creates a new empty calendar backend. A calendar must then be loaded or
- * created before the backend can be used.
- *
- * Return value: A newly-created calendar backend.
- **/
-CalBackend *
-cal_backend_new (void)
-{
- return CAL_BACKEND (gtk_type_new (CAL_BACKEND_TYPE));
-}
-
-/**
* cal_backend_get_uri:
* @backend: A calendar backend.
*
@@ -525,54 +112,11 @@ cal_backend_new (void)
GnomeVFSURI *
cal_backend_get_uri (CalBackend *backend)
{
- CalBackendPrivate *priv;
-
g_return_val_if_fail (backend != NULL, NULL);
g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL);
- priv = backend->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;
- CalBackend *backend;
- CalBackendPrivate *priv;
- GList *l;
-
- cal = CAL (object);
-
- backend = CAL_BACKEND (data);
- priv = backend->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)
- gtk_signal_emit (GTK_OBJECT (backend), cal_backend_signals[LAST_CLIENT_GONE]);
+ g_assert (CLASS (backend)->get_uri != NULL);
+ return (* CLASS (backend)->get_uri) (backend);
}
/**
@@ -586,143 +130,13 @@ cal_destroy_cb (GtkObject *object, gpointer data)
void
cal_backend_add_cal (CalBackend *backend, Cal *cal)
{
- CalBackendPrivate *priv;
-
g_return_if_fail (backend != NULL);
g_return_if_fail (IS_CAL_BACKEND (backend));
- priv = backend->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;
- gchar* str;
- struct stat st;
- int n;
-
- fp = fopen (fname, "r");
- if (!fp) {
- g_warning ("Cannot open open calendar file.");
- return NULL;
- }
-
- stat (fname, &st);
-
- str = g_malloc (st.st_size + 2);
-
- n = fread ((gchar*) str, 1, st.st_size, fp);
- if (n != st.st_size) {
- g_warning ("Read error.");
- }
- str[n] = '\0';
-
- fclose (fp);
-
- comp = icalparser_parse_string (str);
- g_free (str);
-
- return comp;
-}
-
-
-static void
-icalendar_calendar_load (CalBackend * cal, char* fname)
-{
- CalBackendPrivate *priv;
- icalcomponent *comp;
- icalcomponent *subcomp;
- iCalObject *ical;
-
- g_assert (cal);
-
- priv = cal->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_warning ("Skipping unsupported iCalendar component.");
- } else
- add_object (cal, ical);
- subcomp = icalcomponent_get_next_component (comp,
- ICAL_ANY_COMPONENT);
- }
+ g_assert (CLASS (backend)->add_cal != NULL);
+ return (* CLASS (backend)->add_cal) (backend, cal);
}
-
-/*
-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.
-*/
-
-static CalendarFormat
-cal_get_type_from_filename (char *str_uri)
-{
- int len;
-
- if (str_uri == NULL)
- return CAL_VCAL;
-
- len = strlen (str_uri);
- if (len < 4)
- return CAL_VCAL;
-
- if (str_uri[ len-4 ] == '.' && str_uri[ len-3 ] == 'i' &&
- str_uri[ len-2 ] == 'c' && str_uri[ len-1 ] == 's')
- return CAL_ICAL;
-
- if (str_uri[ len-4 ] == '.' && str_uri[ len-3 ] == 'i' &&
- str_uri[ len-2 ] == 'f' && str_uri[ len-1 ] == 'b')
- return CAL_ICAL;
-
- if (str_uri[ len-4 ] == '.' && str_uri[ len-3 ] == 'i' &&
- str_uri[ len-2 ] == 'c' && str_uri[ len-1 ] == 's')
- return CAL_ICAL;
-
- if (len < 5)
- return CAL_VCAL;
-
- 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_ICAL;
-
- return CAL_VCAL;
-}
-
-
/**
* cal_backend_load:
* @backend: A calendar backend.
@@ -736,66 +150,12 @@ cal_get_type_from_filename (char *str_uri)
CalBackendLoadStatus
cal_backend_load (CalBackend *backend, GnomeVFSURI *uri)
{
- CalBackendPrivate *priv;
- VObject *vobject;
- char *str_uri;
-
g_return_val_if_fail (backend != NULL, CAL_BACKEND_LOAD_ERROR);
- g_return_val_if_fail (IS_CAL_BACKEND (backend),CAL_BACKEND_LOAD_ERROR);
-
- priv = backend->priv;
- g_return_val_if_fail (!priv->loaded, 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);
- /* 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 ical or vcal file */
-
- priv->format = cal_get_type_from_filename (str_uri);
-
- /* load */
-
- switch (priv->format) {
- case CAL_VCAL:
- vobject = Parse_MIME_FromFileName (str_uri);
-
- if (!vobject){
- g_free (str_uri);
- return CAL_BACKEND_LOAD_ERROR;
- }
-
- load_from_vobject (backend, vobject);
- cleanVObject (vobject);
- cleanStrTbl ();
- break;
- case CAL_ICAL:
- icalendar_calendar_load (backend, 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;
+ g_assert (CLASS (backend)->load != NULL);
+ return (* CLASS (backend)->load) (backend, uri);
}
/**
@@ -808,31 +168,12 @@ cal_backend_load (CalBackend *backend, GnomeVFSURI *uri)
void
cal_backend_create (CalBackend *backend, GnomeVFSURI *uri)
{
- CalBackendPrivate *priv;
-
g_return_if_fail (backend != NULL);
g_return_if_fail (IS_CAL_BACKEND (backend));
-
- priv = backend->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 */
-
- gnome_vfs_uri_ref (uri);
-
- priv->uri = uri;
- priv->loaded = TRUE;
-
- save (backend);
+ g_assert (CLASS (backend)->create != NULL);
+ (* CLASS (backend)->create) (backend, uri);
}
/**
@@ -850,66 +191,12 @@ cal_backend_create (CalBackend *backend, GnomeVFSURI *uri)
char *
cal_backend_get_object (CalBackend *backend, const char *uid)
{
- CalBackendPrivate *priv;
- iCalObject *ico;
- char *buf;
-
g_return_val_if_fail (backend != NULL, NULL);
g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL);
-
- priv = backend->priv;
- g_return_val_if_fail (priv->loaded, NULL);
-
g_return_val_if_fail (uid != NULL, NULL);
- g_assert (priv->object_hash != NULL);
-
- ico = lookup_object (backend, 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 (c->type & CALOBJ_TYPE_ANY)
- store = TRUE;
- else */
- 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;
- else
- store = (c->type & CALOBJ_TYPE_OTHER) ? TRUE : FALSE;
-
- if (store)
- c->uid_list = g_list_prepend (c->uid_list, g_strdup (ico->uid));
+ g_assert (CLASS (backend)->get_object != NULL);
+ return (* CLASS (backend)->get_object) (backend, uid);
}
/**
@@ -925,68 +212,11 @@ build_uids_list (gpointer key, gpointer value, gpointer data)
GList *
cal_backend_get_uids (CalBackend *backend, CalObjType type)
{
- CalBackendPrivate *priv;
- struct get_uids_closure c;
-
g_return_val_if_fail (backend != NULL, NULL);
g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL);
- priv = backend->priv;
- g_return_val_if_fail (priv->loaded, NULL);
-
- /* We go through the hash table instead of the lists of particular
- * object types so that we can pick up CALOBJ_TYPE_OTHER objects.
- */
-
- c.type = type;
- c.uid_list = NULL;
- g_hash_table_foreach (priv->object_hash, build_uids_list, &c);
-
- return c.uid_list;
-}
-
-struct build_event_list_closure {
- CalBackend *backend;
- 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 = g_new (CalObjInstance, 1);
-
- g_assert (ico->uid != NULL);
- icoi->uid = g_strdup (ico->uid);
- icoi->start = start;
- icoi->end = 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;
+ g_assert (CLASS (backend)->get_uids != NULL);
+ return (* CLASS (backend)->get_uids) (backend, type);
}
/**
@@ -1005,67 +235,13 @@ compare_instance_func (gconstpointer a, gconstpointer b)
GList *
cal_backend_get_events_in_range (CalBackend *backend, time_t start, time_t end)
{
- CalBackendPrivate *priv;
- struct build_event_list_closure c;
- GList *l;
-
g_return_val_if_fail (backend != NULL, NULL);
g_return_val_if_fail (IS_CAL_BACKEND (backend), NULL);
-
- priv = backend->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.backend = backend;
- 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;
-}
-
-/* Notifies a backend's clients that an object was updated */
-static void
-notify_update (CalBackend *backend, const char *uid)
-{
- CalBackendPrivate *priv;
- GList *l;
-
- priv = backend->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 (CalBackend *backend, const char *uid)
-{
- CalBackendPrivate *priv;
- GList *l;
-
- priv = backend->priv;
-
- for (l = priv->clients; l; l = l->next) {
- Cal *cal;
-
- cal = CAL (l->data);
- cal_notify_remove (cal, uid);
- }
+ g_assert (CLASS (backend)->get_events_in_range != NULL);
+ return (* CLASS (backend)->get_events_in_range) (backend, start, end);
}
/**
@@ -1081,45 +257,15 @@ notify_remove (CalBackend *backend, const char *uid)
* Return value: TRUE on success, FALSE on being passed an invalid object.
**/
gboolean
-cal_backend_update_object (CalBackend *backend, const char *uid,
- const char *calobj)
+cal_backend_update_object (CalBackend *backend, const char *uid, const char *calobj)
{
- CalBackendPrivate *priv;
- iCalObject *ico, *new_ico;
- CalObjFindStatus status;
-
g_return_val_if_fail (backend != NULL, FALSE);
g_return_val_if_fail (IS_CAL_BACKEND (backend), FALSE);
-
- priv = backend->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 (backend, uid);
-
- if (ico)
- remove_object (backend, ico);
-
- add_object (backend, new_ico);
- save (backend);
-
- /* FIXME: do the notification asynchronously */
-
- notify_update (backend, new_ico->uid);
-
- return TRUE;
+ g_assert (CLASS (backend)->update_object != NULL);
+ return (* CLASS (backend)->update_object) (backend, uid, calobj);
}
/**
@@ -1136,29 +282,26 @@ cal_backend_update_object (CalBackend *backend, const char *uid,
gboolean
cal_backend_remove_object (CalBackend *backend, const char *uid)
{
- CalBackendPrivate *priv;
- iCalObject *ico;
-
g_return_val_if_fail (backend != NULL, FALSE);
g_return_val_if_fail (IS_CAL_BACKEND (backend), FALSE);
-
- priv = backend->priv;
- g_return_val_if_fail (priv->loaded, FALSE);
-
g_return_val_if_fail (uid != NULL, FALSE);
- ico = lookup_object (backend, uid);
- if (!ico){
- return FALSE;
- }
-
- remove_object (backend, ico);
-
- priv->dirty = TRUE;
- save (backend);
+ g_assert (CLASS (backend)->remove_object != NULL);
+ return (* CLASS (backend)->remove_object) (backend, uid);
+}
- /* FIXME: do the notification asynchronously */
- notify_remove (backend, uid);
+/**
+ * cal_backend_last_client_gone:
+ * @backend: A calendar backend.
+ *
+ * Emits the "last_client_gone" signal of a calendar backend. This function is
+ * to be used only by backend implementations.
+ **/
+void
+cal_backend_last_client_gone (CalBackend *backend)
+{
+ g_return_if_fail (backend != NULL);
+ g_return_if_fail (IS_CAL_BACKEND (backend));
- return TRUE;
+ gtk_signal_emit (GTK_OBJECT (backend), cal_backend_signals[LAST_CLIENT_GONE]);
}
diff --git a/calendar/pcs/cal-backend.h b/calendar/pcs/cal-backend.h
index e5102bf8bc..3c9c76009b 100644
--- a/calendar/pcs/cal-backend.h
+++ b/calendar/pcs/cal-backend.h
@@ -1,4 +1,4 @@
-/* Evolution calendar backend
+/* Evolution calendar - generic backend class
*
* Copyright (C) 2000 Helix Code, Inc.
*
@@ -58,21 +58,24 @@ struct _CalBackendClass {
/* Notification signals */
void (* last_client_gone) (CalBackend *backend);
-};
-typedef enum {
- CAL_VCAL,
- CAL_ICAL
-} CalendarFormat;
+ /* Virtual methods */
+ GnomeVFSURI *(* get_uri) (CalBackend *backend);
+ void (* add_cal) (CalBackend *backend, Cal *cal);
+ CalBackendLoadStatus (* load) (CalBackend *backend, GnomeVFSURI *uri);
+ void (* create) (CalBackend *backend, GnomeVFSURI *uri);
+ char *(* get_object) (CalBackend *backend, const char *uid);
+ GList *(* get_uids) (CalBackend *backend, CalObjType type);
+ GList *(* get_events_in_range) (CalBackend *backend, time_t start, time_t end);
+ gboolean (* update_object) (CalBackend *backend, const char *uid, const char *calobj);
+ gboolean (* remove_object) (CalBackend *backend, const char *uid);
+};
GtkType cal_backend_get_type (void);
-CalBackend *cal_backend_new (void);
-
GnomeVFSURI *cal_backend_get_uri (CalBackend *backend);
void cal_backend_add_cal (CalBackend *backend, Cal *cal);
-void cal_backend_remove_cal (CalBackend *backend, Cal *cal);
CalBackendLoadStatus cal_backend_load (CalBackend *backend, GnomeVFSURI *uri);
@@ -88,6 +91,8 @@ gboolean cal_backend_update_object (CalBackend *backend, const char *uid, const
gboolean cal_backend_remove_object (CalBackend *backend, const char *uid);
+void cal_backend_last_client_gone (CalBackend *backend);
+
END_GNOME_DECLS
diff --git a/calendar/pcs/cal-factory.c b/calendar/pcs/cal-factory.c
index 6d6c28b889..1112245184 100644
--- a/calendar/pcs/cal-factory.c
+++ b/calendar/pcs/cal-factory.c
@@ -20,6 +20,7 @@
*/
#include <config.h>
+#include <ctype.h>
#include <gtk/gtksignal.h>
#include "cal.h"
#include "cal-backend.h"
@@ -30,6 +31,9 @@
/* Private part of the CalFactory structure */
typedef struct {
+ /* Hash table from URI method strings to GtkType * for backend class types */
+ GHashTable *methods;
+
/* Hash table from GnomeVFSURI structures to CalBackend objects */
GHashTable *backends;
} CalFactoryPrivate;
@@ -128,9 +132,24 @@ cal_factory_init (CalFactory *factory)
priv = g_new0 (CalFactoryPrivate, 1);
factory->priv = priv;
+ priv->methods = g_hash_table_new (g_str_hash, g_str_equal);
priv->backends = g_hash_table_new (gnome_vfs_uri_hash, gnome_vfs_uri_hequal);
}
+/* Frees a method/GtkType * pair from the methods hash table */
+static void
+free_method (gpointer key, gpointer value, gpointer data)
+{
+ char *method;
+ GtkType *type;
+
+ method = key;
+ type = value;
+
+ g_free (method);
+ g_free (type);
+}
+
/* Frees a uri/backend pair from the backends hash table */
static void
free_backend (gpointer key, gpointer value, gpointer data)
@@ -158,6 +177,10 @@ cal_factory_destroy (GtkObject *object)
factory = CAL_FACTORY (object);
priv = factory->priv;
+ g_hash_table_foreach (priv->methods, free_method, NULL);
+ g_hash_table_destroy (priv->methods);
+ priv->methods = NULL;
+
/* Should we assert that there are no more backends? */
g_hash_table_foreach (priv->backends, free_backend, NULL);
@@ -165,6 +188,7 @@ cal_factory_destroy (GtkObject *object)
priv->backends = NULL;
g_free (priv);
+ factory->priv = NULL;
if (GTK_OBJECT_CLASS (parent_class)->destroy)
(* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
@@ -172,86 +196,57 @@ cal_factory_destroy (GtkObject *object)
-/* CORBA servant implementation */
+/* Loading and creating calendars */
-/* CalFactory::load method */
+/* Job data */
+typedef struct {
+ CalFactory *factory;
+ char *uri;
+ Evolution_Calendar_Listener listener;
+} LoadCreateJobData;
+
+/* Queues a load or create request */
static void
-CalFactory_load (PortableServer_Servant servant,
- const CORBA_char *uri,
- Evolution_Calendar_Listener listener,
- CORBA_Environment *ev)
+queue_load_create_job (CalFactory *factory, const char *uri, Evolution_Calendar_Listener listener,
+ JobFunc func)
{
- CalFactory *factory;
- CalFactoryPrivate *priv;
- CORBA_Environment ev2;
+ LoadCreateJobData *jd;
+ CORBA_Environment ev;
+ Evolution_Calendar_Listener listener_copy;
gboolean result;
- factory = CAL_FACTORY (bonobo_object_from_servant (servant));
- priv = factory->priv;
-
- CORBA_exception_init (&ev2);
- result = CORBA_Object_is_nil (listener, &ev2);
-
- if (ev2._major != CORBA_NO_EXCEPTION || result) {
- CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
- ex_Evolution_Calendar_CalFactory_NilListener,
- NULL);
-
- CORBA_exception_free (&ev2);
+ CORBA_exception_init (&ev);
+ result = CORBA_Object_is_nil (listener, &ev);
+ if (ev._major != CORBA_NO_EXCEPTION) {
+ g_message ("queue_load_create_job(): could not see if the listener was NIL");
+ CORBA_exception_free (&ev);
return;
}
- CORBA_exception_free (&ev2);
-
- cal_factory_load (factory, uri, listener);
-}
+ CORBA_exception_free (&ev);
-/* CalFactory::create method */
-static void
-CalFactory_create (PortableServer_Servant servant,
- const CORBA_char *uri,
- Evolution_Calendar_Listener listener,
- CORBA_Environment *ev)
-{
- CalFactory *factory;
- CalFactoryPrivate *priv;
+ if (result) {
+ g_message ("queue_load_create_job(): cannot operate on a NIL listener!");
+ return;
+ }
- factory = CAL_FACTORY (bonobo_object_from_servant (servant));
- priv = factory->priv;
+ listener_copy = CORBA_Object_duplicate (listener, &ev);
- cal_factory_create (factory, uri, listener);
-}
+ if (ev._major != CORBA_NO_EXCEPTION) {
+ g_message ("queue_load_create_job(): could not duplicate the listener");
+ CORBA_exception_free (&ev);
+ return;
+ }
-/**
- * cal_factory_get_epv:
- * @void:
- *
- * Creates an EPV for the CalFactory CORBA class.
- *
- * Return value: A newly-allocated EPV.
- **/
-POA_Evolution_Calendar_CalFactory__epv *
-cal_factory_get_epv (void)
-{
- POA_Evolution_Calendar_CalFactory__epv *epv;
+ CORBA_exception_free (&ev);
- epv = g_new0 (POA_Evolution_Calendar_CalFactory__epv, 1);
- epv->load = CalFactory_load;
- epv->create = CalFactory_create;
+ jd = g_new (LoadCreateJobData, 1);
+ jd->factory = factory;
+ jd->uri = g_strdup (uri);
+ jd->listener = listener_copy;
- return epv;
+ job_add (func, jd);
}
-
-
-/* Loading and creating calendars */
-
-/* Job data */
-typedef struct {
- CalFactory *factory;
- char *uri;
- Evolution_Calendar_Listener listener;
-} LoadCreateJobData;
-
/* Looks up a calendar backend in a factory's hash table of uri->cal */
static CalBackend *
lookup_backend (CalFactory *factory, GnomeVFSURI *uri)
@@ -316,21 +311,64 @@ add_backend (CalFactory *factory, GnomeVFSURI *uri, CalBackend *backend)
factory);
}
+/* Tries to launch a backend for the method of the specified URI. If there is
+ * no such method registered in the factory, it sends the listener the
+ * MethodNotSupported error code.
+ */
+static CalBackend *
+launch_backend_for_uri (CalFactory *factory, GnomeVFSURI *uri, Evolution_Calendar_Listener listener)
+{
+ CalFactoryPrivate *priv;
+ char *method;
+ GtkType *type;
+ CalBackend *backend;
+
+ priv = factory->priv;
+
+ /* FIXME: add an accessor function to gnome-vfs */
+ method = uri->method_string;
+
+ type = g_hash_table_lookup (priv->methods, method);
+ g_free (method);
+
+ if (!type) {
+ CORBA_Environment ev;
+
+ CORBA_exception_init (&ev);
+ Evolution_Calendar_Listener_cal_loaded (
+ listener,
+ Evolution_Calendar_Listener_METHOD_NOT_SUPPORTED,
+ CORBA_OBJECT_NIL,
+ &ev);
+
+ if (ev._major != CORBA_NO_EXCEPTION)
+ g_message ("launch_backend_for_uri(): could not notify the listener");
+
+ CORBA_exception_free (&ev);
+ return NULL;
+ }
+
+ backend = gtk_type_new (*type);
+ if (!backend)
+ g_message ("launch_backend_for_uri(): could not launch the backend");
+
+ return backend;
+}
+
/* Loads a calendar backend and puts it in the factory's backend hash table */
static CalBackend *
-load_backend (CalFactory *factory, GnomeVFSURI *uri)
+load_backend (CalFactory *factory, GnomeVFSURI *uri, Evolution_Calendar_Listener listener)
{
CalFactoryPrivate *priv;
CalBackend *backend;
CalBackendLoadStatus status;
+ CORBA_Environment ev;
priv = factory->priv;
- backend = cal_backend_new ();
- if (!backend) {
- g_message ("load_backend(): could not create the backend");
+ backend = launch_backend_for_uri (factory, uri, listener);
+ if (!backend)
return NULL;
- }
status = cal_backend_load (backend, uri);
@@ -341,6 +379,17 @@ load_backend (CalFactory *factory, GnomeVFSURI *uri)
case CAL_BACKEND_LOAD_ERROR:
gtk_object_unref (GTK_OBJECT (backend));
+
+ CORBA_exception_init (&ev);
+ Evolution_Calendar_Listener_cal_loaded (listener,
+ Evolution_Calendar_Listener_ERROR,
+ CORBA_OBJECT_NIL,
+ &ev);
+
+ if (ev._major != CORBA_NO_EXCEPTION)
+ g_message ("load_backend(): could not notify the listener");
+
+ CORBA_exception_free (&ev);
return NULL;
default:
@@ -351,20 +400,37 @@ load_backend (CalFactory *factory, GnomeVFSURI *uri)
/* Creates a calendar backend and puts it in the factory's backend hash table */
static CalBackend *
-create_backend (CalFactory *factory, GnomeVFSURI *uri)
+create_backend (CalFactory *factory, GnomeVFSURI *uri, Evolution_Calendar_Listener listener)
{
CalFactoryPrivate *priv;
CalBackend *backend;
priv = factory->priv;
- backend = cal_backend_new ();
- if (!backend) {
- g_message ("create_backend(): could not create the backend");
+ backend = launch_backend_for_uri (factory, uri, listener);
+ if (!backend)
return NULL;
- }
cal_backend_create (backend, uri);
+
+ /* FIXME: add error reporting to cal_backend_create() */
+#if 0
+ {
+ CORBA_Environment ev;
+
+ CORBA_exception_init (&ev);
+ Evolution_Calendar_Listener_cal_loaded (listener,
+ Evolution_Calendar_Listener_ERROR,
+ CORBA_OBJECT_NIL,
+ &ev);
+
+ if (ev._major != CORBA_NO_EXCEPTION)
+ g_message ("create_fn(): could not notify the listener");
+
+ CORBA_exception_free (&ev);
+ }
+#endif
+
add_backend (factory, uri, backend);
return backend;
@@ -438,21 +504,10 @@ load_fn (gpointer data)
backend = lookup_backend (factory, uri);
if (!backend)
- backend = load_backend (factory, uri);
-
- if (!backend) {
- CORBA_exception_init (&ev);
- Evolution_Calendar_Listener_cal_loaded (listener,
- Evolution_Calendar_Listener_ERROR,
- CORBA_OBJECT_NIL,
- &ev);
+ backend = load_backend (factory, uri, listener);
- if (ev._major != CORBA_NO_EXCEPTION)
- g_message ("load_fn(): could not notify the listener");
-
- CORBA_exception_free (&ev);
+ if (!backend)
goto out;
- }
add_calendar_client (factory, backend, listener);
@@ -510,21 +565,10 @@ create_fn (gpointer data)
/* Create the backend */
- backend = create_backend (factory, uri);
+ backend = create_backend (factory, uri, listener);
- if (!backend) {
- CORBA_exception_init (&ev);
- Evolution_Calendar_Listener_cal_loaded (listener,
- Evolution_Calendar_Listener_ERROR,
- CORBA_OBJECT_NIL,
- &ev);
-
- if (ev._major != CORBA_NO_EXCEPTION)
- g_message ("create_fn(): could not notify the listener");
-
- CORBA_exception_free (&ev);
+ if (!backend)
goto out;
- }
add_calendar_client (factory, backend, listener);
@@ -543,6 +587,77 @@ create_fn (gpointer data)
+/* CORBA servant implementation */
+
+/* CalFactory::load method */
+static void
+CalFactory_load (PortableServer_Servant servant,
+ const CORBA_char *uri,
+ Evolution_Calendar_Listener listener,
+ CORBA_Environment *ev)
+{
+ CalFactory *factory;
+ CalFactoryPrivate *priv;
+ CORBA_Environment ev2;
+ gboolean result;
+
+ factory = CAL_FACTORY (bonobo_object_from_servant (servant));
+ priv = factory->priv;
+
+ CORBA_exception_init (&ev2);
+ result = CORBA_Object_is_nil (listener, &ev2);
+
+ if (ev2._major != CORBA_NO_EXCEPTION || result) {
+ CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
+ ex_Evolution_Calendar_CalFactory_NilListener,
+ NULL);
+
+ CORBA_exception_free (&ev2);
+ return;
+ }
+ CORBA_exception_free (&ev2);
+
+ queue_load_create_job (factory, uri, listener, load_fn);
+}
+
+/* CalFactory::create method */
+static void
+CalFactory_create (PortableServer_Servant servant,
+ const CORBA_char *uri,
+ Evolution_Calendar_Listener listener,
+ CORBA_Environment *ev)
+{
+ CalFactory *factory;
+ CalFactoryPrivate *priv;
+
+ factory = CAL_FACTORY (bonobo_object_from_servant (servant));
+ priv = factory->priv;
+
+ queue_load_create_job (factory, uri, listener, create_fn);
+}
+
+/**
+ * cal_factory_get_epv:
+ * @void:
+ *
+ * Creates an EPV for the CalFactory CORBA class.
+ *
+ * Return value: A newly-allocated EPV.
+ **/
+POA_Evolution_Calendar_CalFactory__epv *
+cal_factory_get_epv (void)
+{
+ POA_Evolution_Calendar_CalFactory__epv *epv;
+
+ epv = g_new0 (POA_Evolution_Calendar_CalFactory__epv, 1);
+ epv->load = CalFactory_load;
+ epv->create = CalFactory_create;
+
+ return epv;
+}
+
+
+
/**
* cal_factory_construct:
* @factory: A calendar factory.
@@ -634,78 +749,61 @@ cal_factory_new (void)
return cal_factory_construct (factory, corba_factory);
}
-/* Queues a load or create request */
-static void
-queue_load_create_job (CalFactory *factory, const char *uri, Evolution_Calendar_Listener listener,
- JobFunc func)
+/* Returns the lowercase version of a string */
+static char *
+str_tolower (const char *s)
{
- LoadCreateJobData *jd;
- CORBA_Environment ev;
- Evolution_Calendar_Listener listener_copy;
- gboolean result;
+ char *str;
+ char *p;
- CORBA_exception_init (&ev);
- result = CORBA_Object_is_nil (listener, &ev);
- if (ev._major != CORBA_NO_EXCEPTION) {
- g_message ("queue_load_create_job(): could not see if the listener was NIL");
- CORBA_exception_free (&ev);
- return;
- }
- CORBA_exception_free (&ev);
+ str = g_strdup (s);
+ for (p = str; *p; p++)
+ if (isalpha (*p))
+ *p = tolower (*p);
- if (result) {
- g_message ("queue_load_create_job(): cannot operate on a NIL listener!");
- return;
- }
-
- listener_copy = CORBA_Object_duplicate (listener, &ev);
-
- if (ev._major != CORBA_NO_EXCEPTION) {
- g_message ("queue_load_create_job(): could not duplicate the listener");
- CORBA_exception_free (&ev);
- return;
- }
-
- CORBA_exception_free (&ev);
-
- jd = g_new (LoadCreateJobData, 1);
- jd->factory = factory;
- jd->uri = g_strdup (uri);
- jd->listener = listener_copy;
-
- job_add (func, jd);
-}
-
-/**
- * cal_factory_load:
- * @factory: A calendar factory.
- * @uri: URI of calendar to load.
- * @listener: Listener for notification of the load result.
- *
- * Initiates a load request in a calendar factory. A calendar will be loaded
- * asynchronously and the result code will be reported to the specified
- * listener.
- **/
-void
-cal_factory_load (CalFactory *factory, const char *uri, Evolution_Calendar_Listener listener)
-{
- queue_load_create_job (factory, uri, listener, load_fn);
+ return str;
}
/**
- * cal_factory_create:
+ * cal_factory_register_method:
* @factory: A calendar factory.
- * @uri: URI of calendar to create.
- * @listener: Listener for notification of the create result.
+ * @method: Method for the URI, i.e. "http", "file", etc.
+ * @backend_type: Class type of the backend to create for this @method.
*
- * Initiates a create request in a calendar factory. A calendar will be created
- * asynchronously and the result code will be reported to the specified
- * listener.
+ * Registers the type of a #CalBackend subclass that will be used to handle URIs
+ * with a particular method. When the factory is asked to load a particular
+ * URI, it will look in its list of registered methods and create a backend of
+ * the appropriate type.
**/
void
-cal_factory_create (CalFactory *factory, const char *uri, Evolution_Calendar_Listener listener)
+cal_factory_register_method (CalFactory *factory, const char *method, GtkType backend_type)
{
- queue_load_create_job (factory, uri, listener, create_fn);
+ CalFactoryPrivate *priv;
+ GtkType *type;
+ char *method_str;
+
+ g_return_if_fail (factory != NULL);
+ g_return_if_fail (IS_CAL_FACTORY (factory));
+ g_return_if_fail (method != NULL);
+ g_return_if_fail (backend_type != 0);
+ g_return_if_fail (gtk_type_is_a (backend_type, CAL_BACKEND_TYPE));
+
+ priv = factory->priv;
+
+ method_str = str_tolower (method);
+
+ type = g_hash_table_lookup (priv->methods, method_str);
+ if (type) {
+ g_message ("cal_factory_register_method(): Method `%s' already registered!",
+ method_str);
+ g_free (method_str);
+ return;
+ }
+
+ type = g_new (GtkType, 1);
+ *type = backend_type;
+
+ g_hash_table_insert (priv->methods, method_str, type);
}
/**
diff --git a/calendar/pcs/cal-factory.h b/calendar/pcs/cal-factory.h
index 03b2cc8dc3..f96ba4ba92 100644
--- a/calendar/pcs/cal-factory.h
+++ b/calendar/pcs/cal-factory.h
@@ -62,8 +62,7 @@ Evolution_Calendar_CalFactory cal_factory_corba_object_create (BonoboObject *obj
CalFactory *cal_factory_new (void);
-void cal_factory_load (CalFactory *factory, const char *uri, Evolution_Calendar_Listener listener);
-void cal_factory_create (CalFactory *factory, const char *uri, Evolution_Calendar_Listener listener);
+void cal_factory_register_method (CalFactory *factory, const char *method, GtkType backend_type);
int cal_factory_get_n_backends (CalFactory *factory);