[evolution-couchdb] Add tasks backend



commit 7422295edf7a8ab4c9794bf6cd43c299a774c2b2
Author: Miguel Ã?ngel Rodelas Delgado <miguel rodelas gmail com>
Date:   Mon Jul 5 13:22:05 2010 +0200

    Add tasks backend

 calendar/Makefile.am                     |   17 +
 calendar/e-cal-backend-couchdb-factory.c |  170 ++++++
 calendar/e-cal-backend-couchdb-factory.h |   37 ++
 calendar/e-cal-backend-couchdb.c         |  876 ++++++++++++++++++++++++++++++
 calendar/e-cal-backend-couchdb.h         |   58 ++
 5 files changed, 1158 insertions(+), 0 deletions(-)
---
diff --git a/calendar/Makefile.am b/calendar/Makefile.am
new file mode 100644
index 0000000..f988591
--- /dev/null
+++ b/calendar/Makefile.am
@@ -0,0 +1,17 @@
+INCLUDES =						\
+	$(EVOLUTION_CFLAGS)				\
+	-I$(top_srcdir)
+
+extensiondir = $(EDS_EXTENSION_DIR)
+extension_LTLIBRARIES = libecalbackendcouchdb.la
+
+libecalbackendcouchdb_la_SOURCES =		\
+	e-cal-backend-couchdb-factory.h	\
+	e-cal-backend-couchdb-factory.c	\
+	e-cal-backend-couchdb.c		\
+	e-cal-backend-couchdb.h
+
+libecalbackendcouchdb_la_LIBADD =		\
+	$(EVOLUTION_LIBS)
+
+libecalbackendcouchdb_la_LDFLAGS = -module -avoid-version
diff --git a/calendar/e-cal-backend-couchdb-factory.c b/calendar/e-cal-backend-couchdb-factory.c
new file mode 100644
index 0000000..daf1fd6
--- /dev/null
+++ b/calendar/e-cal-backend-couchdb-factory.c
@@ -0,0 +1,170 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* e-cal-backend-couchdb-factory.c - Couchdb calendar backend factory.
+ *
+ * Copyright (C) 2009 Canonical, Ltd. (www.canonical.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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Miguel Angel Rodelas Delgado <miguel rodelas gmail com>
+ */
+
+#ifdef CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include "e-cal-backend-couchdb-factory.h"
+
+#include <libebackend/e-data-server-module.h>
+#include <libedata-cal/e-cal-backend-factory.h>
+#include "e-cal-backend-couchdb.h"
+
+typedef struct {
+	ECalBackendFactory parent_object;
+}ECalBackendCouchDBFactory;
+
+typedef struct {
+	ECalBackendFactoryClass parent_class;
+}ECalBackendCouchDBFactoryClass;
+
+static void
+e_cal_backend_couchdb_factory_instance_init (ECalBackendCouchDBFactory *factory)
+{
+
+}
+
+static const gchar *
+get_protocol (ECalBackendFactory *factory)
+{
+	return "couchdb";
+}
+
+static ECalBackend *
+todos_new_backend (ECalBackendFactory *factory, ESource *source)
+{
+	return g_object_new (e_cal_backend_couchdb_get_type (),
+			     "source", source,
+			     "kind", ICAL_VTODO_COMPONENT,
+			     NULL);
+
+}
+
+static icalcomponent_kind
+todos_get_kind (ECalBackendFactory *factory)
+{
+	return ICAL_VTODO_COMPONENT;
+}
+
+static ECalBackend*
+events_new_backend (ECalBackendFactory *factory, ESource *source)
+{
+	return g_object_new (e_cal_backend_couchdb_get_type (),
+			     "source", source,
+			     "kind", ICAL_VEVENT_COMPONENT,
+			     NULL);
+}
+
+static icalcomponent_kind
+events_get_kind (ECalBackendFactory *factory)
+{
+	return ICAL_VEVENT_COMPONENT;
+}
+
+static void
+todos_backend_factory_class_init (ECalBackendCouchDBFactoryClass *klass)
+{
+	E_CAL_BACKEND_FACTORY_CLASS (klass)->get_protocol = get_protocol;
+	E_CAL_BACKEND_FACTORY_CLASS (klass)->get_kind     = todos_get_kind;
+	E_CAL_BACKEND_FACTORY_CLASS (klass)->new_backend  = todos_new_backend;
+}
+
+static void
+events_backend_factory_class_init (ECalBackendCouchDBFactoryClass *klass)
+{
+	E_CAL_BACKEND_FACTORY_CLASS (klass)->get_protocol = get_protocol;
+	E_CAL_BACKEND_FACTORY_CLASS (klass)->get_kind     = events_get_kind;
+	E_CAL_BACKEND_FACTORY_CLASS (klass)->new_backend  = events_new_backend;
+}
+
+static GType
+events_backend_factory_get_type (GTypeModule *module)
+{
+	GType type;
+
+	GTypeInfo info = {
+		sizeof (ECalBackendCouchDBFactoryClass),
+		NULL, /* base_class_init */
+		NULL, /* base_class_finalize */
+		(GClassInitFunc)  events_backend_factory_class_init,
+		NULL, /* class_finalize */
+		NULL, /* class_data */
+		sizeof (ECalBackend),
+		0,    /* n_preallocs */
+		(GInstanceInitFunc) e_cal_backend_couchdb_factory_instance_init
+	};
+
+	type = g_type_module_register_type (module,
+					    E_TYPE_CAL_BACKEND_FACTORY,
+					    "ECalBackendCouchDBEventsFactory",
+					    &info, 0);
+
+	return type;
+}
+
+static GType
+todos_backend_factory_get_type (GTypeModule *module)
+{
+	GType type;
+
+	GTypeInfo info = {
+		sizeof (ECalBackendCouchDBFactoryClass),
+		NULL, /* base_class_init */
+		NULL, /* base_class_finalize */
+		(GClassInitFunc)  todos_backend_factory_class_init,
+		NULL, /* class_finalize */
+		NULL, /* class_data */
+		sizeof (ECalBackend),
+		0,    /* n_preallocs */
+		(GInstanceInitFunc) e_cal_backend_couchdb_factory_instance_init
+	};
+
+	type = g_type_module_register_type (module,
+					    E_TYPE_CAL_BACKEND_FACTORY,
+					    "ECalBackendCouchDBTodosFactory",
+					    &info, 0);
+
+	return type;
+}
+
+static GType couchdb_types[2];
+
+void
+eds_module_initialize (GTypeModule *module)
+{
+	couchdb_types[0] = todos_backend_factory_get_type (module);
+	couchdb_types[1] = events_backend_factory_get_type (module);
+}
+
+void
+eds_module_shutdown (void)
+{
+}
+
+void
+eds_module_list_types (const GType **types, gint *num_types)
+{
+	*types = couchdb_types;
+	*num_types = 2;
+}
diff --git a/calendar/e-cal-backend-couchdb-factory.h b/calendar/e-cal-backend-couchdb-factory.h
new file mode 100644
index 0000000..026bf65
--- /dev/null
+++ b/calendar/e-cal-backend-couchdb-factory.h
@@ -0,0 +1,37 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* e-cal-backend-couchdb-factory.h - Couchdb calendar backend factory.
+ *
+ * Copyright (C) 2009 Canonical, Ltd. (www.canonical.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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Miguel Angel Rodelas Delgado <miguel rodelas gmail com>
+ */
+
+#ifndef _E_CAL_BACKEND_COUCHDB_FACTORY_H
+#define _E_CAL_BACKEND_COUCHDB_FACTORY_H
+
+#include<glib.h>
+#include "libedata-cal/e-cal-backend-factory.h"
+
+G_BEGIN_DECLS
+
+void eds_module_initialize (GTypeModule *module);
+void eds_module_shutdown (void);
+void eds_module_list_types (const GType **types, gint *num_types);
+
+G_END_DECLS
+
+#endif
+
diff --git a/calendar/e-cal-backend-couchdb.c b/calendar/e-cal-backend-couchdb.c
new file mode 100644
index 0000000..f3497d5
--- /dev/null
+++ b/calendar/e-cal-backend-couchdb.c
@@ -0,0 +1,876 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* e-cal-backend-couchdb.c - CouchDB calendar backend
+ *
+ * Copyright (C) 2009 Canonical, Ltd. (www.canonical.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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Miguel Angel Rodelas Delgado <miguel rodelas gmail com>
+ */
+
+#include <string.h>
+#include "e-cal-backend-couchdb.h"
+#include <libedata-cal/e-cal-backend-sexp.h>
+#include <libedata-cal/e-data-cal.h>
+#include <libedata-cal/e-data-cal-view.h>
+#include <dbus/dbus-glib.h>
+#include <gnome-keyring.h>
+
+#define COUCHDB_REVISION_PROP                "X-COUCHDB-REVISION"
+#define COUCHDB_UUID_PROP                    "X-COUCHDB-UUID"
+#define COUCHDB_APPLICATION_ANNOTATIONS_PROP "X-COUCHDB-APPLICATION-ANNOTATIONS"
+
+G_DEFINE_TYPE (ECalBackendCouchDB, e_cal_backend_couchdb, E_TYPE_CAL_BACKEND);
+
+
+/*********************** Auxiliar methods ********************************/
+
+
+static ECalComponent *
+task_from_couch_document (CouchdbDocument *document)
+{
+	ECalComponent *task;
+	ECalComponentText summary;
+	CouchdbStructField *app_annotations;
+	const char *uid;
+
+	if (!desktopcouch_document_is_task (document))
+		return NULL;
+
+	/* Check if the task is marked for deletion */
+	if ((app_annotations = desktopcouch_document_get_application_annotations (document))) {
+		CouchdbStructField *u1_annotations;
+
+		u1_annotations = couchdb_struct_field_get_struct_field (
+			app_annotations, "Ubuntu One");
+		if (u1_annotations != NULL) {
+			CouchdbStructField *private_annotations;
+
+			private_annotations = couchdb_struct_field_get_struct_field (
+				u1_annotations, "private_application_annotations");
+			if (private_annotations != NULL) {
+				if (couchdb_struct_field_has_field (private_annotations, "deleted")
+				    && couchdb_struct_field_get_boolean_field (private_annotations, "deleted"))
+					couchdb_struct_field_unref (app_annotations);
+					return NULL;
+			}
+		}
+	}
+
+	// Fill in the ECalComponent with the data from the CouchDBDocument
+	task = e_cal_component_new ();
+	e_cal_component_set_new_vtype (task, E_CAL_COMPONENT_TODO);
+	summary.value = (const gchar *)desktopcouch_document_task_get_summary (document);
+	summary.altrep = NULL;
+	uid = couchdb_document_get_id (document);
+	
+	e_cal_component_set_summary (task, &summary);
+	e_cal_component_set_uid (task, uid);
+	
+	return task;
+}
+
+static CouchdbDocument *
+couch_document_from_task (ECalBackendCouchDB *couchdb_backend, ECalComponent *task)
+{
+	CouchdbDocument *document;
+	ECalComponentText summary;
+	const char *uid;
+
+	// create the CouchDBDocument to put on the database
+	document = desktopcouch_document_task_new (couchdb_backend->couchdb);
+
+	e_cal_component_get_summary (task, &summary);
+	e_cal_component_get_uid (task, &uid);
+
+	summary.altrep = NULL;
+
+	desktopcouch_document_task_set_summary (document, (const char *)summary.value);
+	if (uid)
+		couchdb_document_set_id (document, uid);
+	
+	return document;
+}
+
+static void
+document_updated_cb (CouchdbSession *couchdb, const char *dbname, CouchdbDocument *document, gpointer user_data)
+{
+
+	ECalComponent *task;
+	ECalBackendCouchDB *couchdb_backend = E_CAL_BACKEND_COUCHDB (user_data);
+	const gchar *uid, *task_string;
+
+	if (g_strcmp0 (dbname, couchdb_backend->dbname) != 0)
+		return;
+
+	task = task_from_couch_document (document);
+	if (!task)
+		return;
+
+	e_cal_component_get_uid (task, &uid);
+	e_cal_component_commit_sequence (task);
+	task_string = e_cal_component_get_as_string(task);
+	
+	if (e_cal_backend_cache_get_component(couchdb_backend->cache, uid, NULL) != NULL) {
+		g_warning ("In _document_updated_cb: objeto modificado!");
+		e_cal_backend_notify_object_modified (E_CAL_BACKEND (couchdb_backend), task_string, task_string);
+	} else {
+		g_warning ("In _document_updated_cb: objeto creado!");
+		e_cal_backend_notify_object_created (E_CAL_BACKEND (couchdb_backend), task_string);
+
+		/* Add the task to the cache */
+		e_cal_backend_cache_put_component (couchdb_backend->cache, task);
+	}
+
+	g_object_unref (G_OBJECT (task));
+}
+
+
+static void
+document_deleted_cb (CouchdbSession *couchdb, const char *dbname, const char *docid, gpointer user_data)
+{
+	g_warning ("In document_deleted_cb");
+	ECalBackendCouchDB *couchdb_backend = E_CAL_BACKEND_COUCHDB (user_data);
+	ECalComponentId id;
+
+	id.uid = (gchar *)docid;
+
+	if (g_strcmp0 (dbname, couchdb_backend->dbname) != 0)
+		return;
+
+	e_cal_backend_notify_object_removed (E_CAL_BACKEND (couchdb_backend), &id, NULL, NULL);
+
+	// Remove the task from the cache 
+	e_cal_backend_cache_remove_component (couchdb_backend->cache, docid, NULL);
+}
+
+static ECalComponent *
+put_document (ECalBackendCouchDB *couchdb_backend, CouchdbDocument *document)
+{
+	GError *error = NULL;
+
+	if (couchdb_document_put (document, couchdb_backend->dbname, &error)) {
+		ECalComponent *new_task;
+
+		/* couchdb_document_put sets the ID for new documents, so need to send that back */
+		new_task = task_from_couch_document (document);
+
+		/* Add the new task to the cache */
+		e_cal_backend_cache_put_component (couchdb_backend->cache, new_task);
+
+		return new_task;
+
+	} else {
+		if (error != NULL) {
+			g_warning ("Could not PUT document: %s\n", error->message);
+			g_error_free (error);
+		}
+	}
+
+	return NULL;
+}
+
+
+/* Virtual methods */
+
+/* Is read only handler for the calendar backend */
+void 
+e_cal_backend_couchdb_is_read_only (ECalBackend *backend, EDataCal *cal)
+{
+	g_warning ("In _is_read_only");
+	e_data_cal_notify_read_only (cal, GNOME_Evolution_Calendar_Success, FALSE);
+}
+
+/* Returns the email address of the person who opened the calendar */
+void 
+e_cal_backend_couchdb_get_cal_address (ECalBackend *backend, EDataCal *cal)
+{
+	g_warning ("In _get_cal_address");
+	/* FIXME */
+	const gchar *address;
+	address = NULL;
+	e_data_cal_notify_cal_address (cal, GNOME_Evolution_Calendar_Success, address);
+}
+
+/* Email based alarms */
+void 
+e_cal_backend_couchdb_get_alarm_email_address (ECalBackend *backend, EDataCal *cal)
+{
+	g_warning ("In _get_alarm_email_address");
+	/* FIXME */
+	const gchar *address;
+	address = NULL;
+	e_data_cal_notify_alarm_email_address (cal, GNOME_Evolution_Calendar_Success, address);
+}
+
+void 
+e_cal_backend_couchdb_get_ldap_attribute (ECalBackend *backend, EDataCal *cal)
+{
+	g_warning ("In _get_ldap_attribute");
+	/* FIXME */
+	const gchar *attribute;
+	attribute = NULL;
+	e_data_cal_notify_ldap_attribute (cal, GNOME_Evolution_Calendar_Success, attribute);
+}
+
+void 
+e_cal_backend_couchdb_get_static_capabilities (ECalBackend *backend, EDataCal *cal)
+{
+	g_warning ("In _get_static_capabilities");
+	/* FIXME */
+	const gchar *capabilities;
+
+	capabilities = g_strdup ("local,do-initial-query,bulk-removes");
+
+	e_data_cal_notify_static_capabilities(cal, GNOME_Evolution_Calendar_Success, capabilities);
+}
+
+void 
+e_cal_backend_couchdb_open (ECalBackend *backend, EDataCal *cal, gboolean only_if_exists, const gchar *username, const gchar *password)
+{
+	g_warning ("In _open");
+	gchar *uri;
+	const gchar *property;
+	CouchdbDatabaseInfo *db_info;
+	GError *error = NULL;
+	GSList *doc_list, *sl;
+
+	ECalBackendCouchDB *couchdb_backend = E_CAL_BACKEND_COUCHDB (backend);
+	ESource *source;
+
+
+	source = e_cal_backend_get_source (backend);
+	if (!(E_IS_CAL_BACKEND_COUCHDB (couchdb_backend))) {
+		e_data_cal_notify_open (cal, GNOME_Evolution_Calendar_OtherError);
+	}
+
+	if (couchdb_backend->couchdb != NULL)
+		g_object_unref (G_OBJECT (couchdb_backend->couchdb));
+	if (couchdb_backend->dbname != NULL)
+		g_free (couchdb_backend->dbname);
+	if (couchdb_backend->cache != NULL)
+		g_object_unref (G_OBJECT (couchdb_backend->cache));
+
+	/* create CouchDB main object */
+	couchdb_backend->dbname = g_strdup ("tasks");
+	couchdb_backend->using_desktopcouch = FALSE;
+
+	property = e_source_get_property (source, "couchdb_instance");
+	if (g_strcmp0 (property, "user") == 0) {
+		if (! (couchdb_backend->couchdb = COUCHDB_SESSION (desktopcouch_session_new ()))) {
+			g_warning ("Could not create DesktopcouchSession object");
+			e_data_cal_notify_open (cal, GNOME_Evolution_Calendar_NoSuchCal);
+		}
+
+		couchdb_backend->using_desktopcouch = TRUE;
+	} else {
+		if (g_strcmp0 (property, "remote") == 0)
+			uri = g_strdup_printf ("http://%s";, e_source_get_property (source, "couchdb_remote_server"));
+		else
+			uri = g_strdup ("http://127.0.0.1:5984";);
+
+		if (! (couchdb_backend->couchdb = couchdb_session_new (uri))) {
+			g_free (uri);
+			e_data_cal_notify_open (cal, GNOME_Evolution_Calendar_NoSuchCal);
+		}
+
+		g_free (uri);
+	}
+
+	/* check if only_if_exists */
+	error = NULL;
+	db_info = couchdb_session_get_database_info (couchdb_backend->couchdb,
+						     couchdb_backend->dbname,
+						     &error);
+	if (!db_info) {
+		if (error) {
+			g_warning ("Could not get CouchDB database info: %s", error->message);
+			g_error_free (error);
+		}
+
+		if (only_if_exists)
+			e_data_cal_notify_open (cal, GNOME_Evolution_Calendar_NoSuchCal);
+		
+		/* if it does not exist, create it */
+		error = NULL;
+		if (!couchdb_session_create_database (couchdb_backend->couchdb,
+						      couchdb_backend->dbname,
+						      &error)) {
+			g_warning ("Could not create 'tasks' database: %s", error->message);
+			g_error_free (error);
+
+			e_data_cal_notify_open (cal, GNOME_Evolution_Calendar_PermissionDenied);
+		}
+	} else
+		couchdb_database_info_unref (db_info);
+
+	g_warning ("CREATE CACHE BEGIN");
+
+	/* Create cache */
+	// uri = e_source_get_uri (source);
+	//couchdb_backend->cache = e_cal_backend_cache_new ((const gchar *) uri, E_CAL_SOURCE_TYPE_TODO);
+	couchdb_backend->cache = e_cal_backend_cache_new (e_cal_backend_get_uri (E_CAL_BACKEND (couchdb_backend)), E_CAL_SOURCE_TYPE_TODO);
+	//g_free (uri);
+
+	g_warning ("CREATE CACHE FINISH");
+
+	/* Populate the cache */
+	e_file_cache_clean (E_FILE_CACHE (couchdb_backend->cache));
+	error = NULL;
+	doc_list = couchdb_session_list_documents (couchdb_backend->couchdb,
+						   couchdb_backend->dbname,
+						   &error);
+
+	for (sl = doc_list; sl != NULL; sl = sl->next) {
+		ECalComponent *task;
+		CouchdbDocument *document;
+		CouchdbDocumentInfo *doc_info = (CouchdbDocumentInfo *) sl->data;
+
+		/* Retrieve this document */
+		error = NULL;
+		document = couchdb_document_get (couchdb_backend->couchdb,
+						 couchdb_backend->dbname,
+						 couchdb_document_info_get_docid (doc_info),
+						 &error);
+		if (!document)
+			continue;
+
+		task = task_from_couch_document (document);
+		if (task != NULL) {
+			e_cal_backend_cache_put_component (couchdb_backend->cache, task);
+			g_object_unref (G_OBJECT (task));
+		}
+
+		g_object_unref (G_OBJECT (document));
+	}
+
+	/* Timezone */
+	// e_cal_backend_cache_put_default_timezone (couchdb_backend->cache, couchdb_backend->default_zone);
+
+	couchdb_session_free_document_list (doc_list);
+
+	/* Listen for changes on database */
+	g_signal_connect (G_OBJECT (couchdb_backend->couchdb), "document_created",
+			  G_CALLBACK (document_updated_cb), couchdb_backend);
+	g_signal_connect (G_OBJECT (couchdb_backend->couchdb), "document_updated",
+			  G_CALLBACK (document_updated_cb), couchdb_backend);
+	g_signal_connect (G_OBJECT (couchdb_backend->couchdb), "document_deleted",
+			  G_CALLBACK (document_deleted_cb), couchdb_backend);
+	couchdb_session_listen_for_changes (couchdb_backend->couchdb, couchdb_backend->dbname);
+
+	//e_cal_backend_set_is_loaded (backend, TRUE);
+	//e_cal_backend_set_is_writable (backend, TRUE);
+	
+	e_data_cal_notify_open (cal, GNOME_Evolution_Calendar_Success);
+	
+}
+
+void 
+e_cal_backend_couchdb_remove (ECalBackend *backend, EDataCal *cal)
+{
+	g_warning ("In _remove");
+	ECalBackendCouchDB *couchdb_backend = E_CAL_BACKEND_COUCHDB (backend);
+
+	/* Remove the cache */
+	if (couchdb_backend->cache != NULL) {
+		// Added
+		e_file_cache_remove (E_FILE_CACHE (couchdb_backend->cache));
+
+		g_object_unref (G_OBJECT (couchdb_backend->cache));
+		couchdb_backend->cache = NULL;
+	}
+
+	/* We don't remove data from CouchDB, since it would affect other apps,
+	   so just report success */
+	e_data_cal_notify_remove (cal, GNOME_Evolution_Calendar_Success);
+}
+
+/* Object related virtual methods */
+
+void 
+e_cal_backend_couchdb_create_object (ECalBackend *backend, EDataCal *cal, const gchar *calobj)
+{
+	g_warning ("In _create_object");
+	ECalComponent *task, *new_task;
+	CouchdbDocument *document;
+	ECalBackendCouchDB *couchdb_backend = E_CAL_BACKEND_COUCHDB (backend);
+	const gchar *uid;
+
+	task = e_cal_component_new_from_string (calobj);
+	e_cal_component_get_uid (task, &uid);
+
+	// g_warning("UID:%s", uid);
+ 
+	if (!task) {
+		e_data_cal_notify_object_created (cal, GNOME_Evolution_Calendar_OtherError, uid, NULL);
+		return;
+	}
+
+	document = couch_document_from_task (couchdb_backend, task);
+	if (!document) {
+		e_data_cal_notify_object_created (cal, GNOME_Evolution_Calendar_OtherError, uid, NULL);
+		g_object_unref (G_OBJECT (task));
+		return;
+	}
+
+	/* save the task into the DB */
+	if ((new_task = put_document (couchdb_backend, document)) != NULL) {
+		g_warning ("In _open: saving the task into the DB");
+		e_data_cal_notify_object_created (cal, GNOME_Evolution_Calendar_Success, uid, calobj);
+		g_object_unref (new_task);
+	} else
+		e_data_cal_notify_object_created (cal, GNOME_Evolution_Calendar_OtherError, uid, NULL);
+
+	/* free memory */
+	g_object_unref (G_OBJECT (task));
+	g_object_unref (G_OBJECT (document));
+}
+
+void 
+e_cal_backend_couchdb_modify_object (ECalBackend *backend, EDataCal *cal, const gchar *calobj, CalObjModType mod)
+{
+	g_warning ("In _modify_object");
+	ECalComponent *task, *new_task;
+	CouchdbDocument *document;
+	ECalBackendCouchDB *couchdb_backend = E_CAL_BACKEND_COUCHDB (backend);
+
+	task = e_cal_component_new_from_string (calobj);
+	if (!task) {
+		e_data_cal_notify_object_modified (cal, GNOME_Evolution_Calendar_OtherError, NULL, NULL);
+		return;
+	}
+
+	document = couch_document_from_task (couchdb_backend, task);
+	if (!document) {
+		e_data_cal_notify_object_modified (cal, GNOME_Evolution_Calendar_OtherError, NULL, NULL);
+		g_object_unref (G_OBJECT (document));
+		return;
+	}
+
+	/* save the task into the DB */
+	if ((new_task = put_document (couchdb_backend, document)) != NULL) {
+		e_cal_component_commit_sequence (new_task);
+		e_data_cal_notify_object_modified (cal, GNOME_Evolution_Calendar_Success, calobj,  e_cal_component_get_as_string (new_task));
+		g_object_unref (new_task);
+	} else
+		e_data_cal_notify_object_modified (cal, GNOME_Evolution_Calendar_OtherError, NULL, NULL);
+
+	/* free memory */
+	g_object_unref (G_OBJECT (task));
+	g_object_unref (G_OBJECT (document));
+	e_data_cal_notify_object_modified (cal, GNOME_Evolution_Calendar_OtherError, NULL, NULL);
+}
+
+void 
+e_cal_backend_couchdb_remove_object (ECalBackend *backend, EDataCal *cal, const gchar *uid, const gchar *rid, CalObjModType mod)
+{
+	g_warning ("In _remove_object");
+
+	ECalBackendCouchDB *couchdb_backend = E_CAL_BACKEND_COUCHDB (backend);
+	CouchdbDocument *document;
+	GError *error = NULL;
+	ECalComponentId id;
+	gboolean deleted;
+
+	id.uid = (gchar *)uid;
+	id.rid = (gchar *)rid;
+
+	document = couchdb_document_get (couchdb_backend->couchdb, couchdb_backend->dbname, uid, &error);
+	if (document) {
+		if (couchdb_backend->using_desktopcouch) {
+			CouchdbStructField *app_annotations, *u1_annotations, *private_annotations;
+
+			/* For desktopcouch, we don't remove tasks, we just
+			* mark them as deleted */
+			app_annotations = desktopcouch_document_get_application_annotations (document);
+			if (app_annotations == NULL)
+				app_annotations = couchdb_struct_field_new ();
+
+			u1_annotations = couchdb_struct_field_get_struct_field (app_annotations, "Ubuntu One");
+			if (u1_annotations == NULL)
+				u1_annotations = couchdb_struct_field_new ();
+
+			private_annotations = couchdb_struct_field_get_struct_field (u1_annotations, "private_application_annotations");
+			if (private_annotations == NULL)
+				private_annotations = couchdb_struct_field_new ();
+
+			couchdb_struct_field_set_boolean_field (private_annotations, "deleted", TRUE);
+			couchdb_struct_field_set_struct_field (u1_annotations, "private_application_annotations", private_annotations);
+			couchdb_struct_field_set_struct_field (app_annotations, "Ubuntu One", u1_annotations);
+			desktopcouch_document_set_application_annotations (document, app_annotations);
+
+			/* Now put the new revision of the document */
+			if (couchdb_document_put (document, couchdb_backend->dbname, &error)) {
+				deleted = TRUE;
+				e_cal_backend_cache_remove_component (couchdb_backend->cache, uid, rid);
+			} else {
+				if (error != NULL) {
+					g_warning ("Error deleting document: %s", error->message);
+					g_error_free (error);
+				} else
+					g_warning ("Error deleting document");
+			}
+
+			/* Free memory */
+			couchdb_struct_field_unref (app_annotations);
+			couchdb_struct_field_unref (u1_annotations);
+			couchdb_struct_field_unref (private_annotations);
+		
+		} else {
+			if (couchdb_document_delete (document, &error)) {
+				deleted = TRUE;
+				e_cal_backend_cache_remove_component (couchdb_backend->cache, uid, rid);
+			} else {
+				if (error != NULL) {
+					g_warning ("Error deleting document: %s", error->message);
+					g_error_free (error);
+				} else
+					g_warning ("Error deleting document");
+			}
+		}
+	} else {
+		if (error != NULL) {
+			g_warning ("Error getting document: %s", error->message);
+			g_error_free (error);
+		} else
+			g_warning ("Error getting document");
+	}
+
+	if (deleted) {
+		g_warning ("In _remove_object: object removed successfully");
+		e_data_cal_notify_object_removed (cal, GNOME_Evolution_Calendar_Success, &id, NULL, NULL);
+	} else {
+		g_warning ("In _remove_object: object not removed successfully");
+		e_data_cal_notify_object_removed (cal, GNOME_Evolution_Calendar_OtherError, &id, NULL, NULL);
+	}
+}
+
+/* Discard_alarm handler for the calendar backend */
+void 
+e_cal_backend_couchdb_discard_alarm (ECalBackend *backend, EDataCal *cal, const gchar *uid, const gchar *auid)
+{
+	g_warning ("In _discard_alarm");
+	e_data_cal_notify_alarm_discarded (cal, GNOME_Evolution_Calendar_Success);
+}
+
+void 
+e_cal_backend_couchdb_receive_objects (ECalBackend *backend, EDataCal *cal, const gchar *calobj)
+{
+	g_warning ("In _receive_objects");
+	e_data_cal_notify_objects_received (cal, GNOME_Evolution_Calendar_OtherError);
+}
+
+void 
+e_cal_backend_couchdb_send_objects (ECalBackend *backend, EDataCal *cal, const gchar *calobj)
+{
+	g_warning ("In _send_objects");
+	e_data_cal_notify_objects_sent (cal, GNOME_Evolution_Calendar_OtherError, NULL, NULL);
+}
+
+void 
+e_cal_backend_couchdb_get_default_object (ECalBackend *backend, EDataCal *cal)
+{
+	g_warning ("In _get_default_object");
+	/*ECalComponent *task;
+	const gchar *object;
+
+        task = e_cal_component_new ();
+	e_cal_component_set_new_vtype (task, E_CAL_COMPONENT_TODO);
+
+	e_cal_component_commit_sequence (task);
+	object = (const gchar *)e_cal_component_get_as_string (task);
+
+	if (task)
+		g_object_unref (task);
+
+	e_data_cal_notify_default_object (cal, GNOME_Evolution_Calendar_Success, object);*/
+	e_data_cal_notify_default_object (cal, GNOME_Evolution_Calendar_OtherError, NULL);
+	//e_data_cal_notify_default_object (cal, GNOME_Evolution_Calendar_Success, NULL);
+}
+
+void 
+e_cal_backend_couchdb_get_object (ECalBackend *backend, EDataCal *cal, const gchar *uid, const gchar *rid)
+{
+	g_warning ("In _get_object");
+	GError *error = NULL;
+	ECalComponent *task;
+	ECalBackendCouchDB *couchdb_backend = E_CAL_BACKEND_COUCHDB (backend);
+
+	task = e_cal_backend_cache_get_component (couchdb_backend->cache, uid, rid);
+	if (task != NULL) {
+		e_cal_component_commit_sequence (task);
+		gchar *task_string = e_cal_component_get_as_string (task);
+
+		g_object_unref (G_OBJECT (task));
+		if (task_string != NULL) {
+			e_data_cal_notify_object (cal, GNOME_Evolution_Calendar_Success, task_string);
+			g_free (task_string);
+			return;
+		}
+	}
+
+	e_data_cal_notify_object (cal, GNOME_Evolution_Calendar_ObjectNotFound, "");
+}
+
+void 
+e_cal_backend_couchdb_get_object_list (ECalBackend *backend, EDataCal *cal, const gchar *sexp)
+{
+	g_warning ("In _get_object_list");
+	GList *doc_list, *tasks = NULL;
+	GError *error = NULL;
+	ECalBackendCouchDB *couchdb_backend = E_CAL_BACKEND_COUCHDB (backend);
+
+	/* Get the list of documents from cache */
+	doc_list = e_cal_backend_cache_get_components (couchdb_backend->cache);
+
+	while (doc_list != NULL) {
+		gchar *task_string;
+		ECalComponent *task = E_CAL_COMPONENT (doc_list->data);
+
+		 e_cal_component_commit_sequence (task);
+		task_string = e_cal_component_get_as_string (task);
+		if (!task_string)
+			tasks = g_list_prepend (tasks, task_string);
+
+		doc_list = g_list_remove (doc_list, task);
+		g_object_unref (G_OBJECT (task));
+	}
+
+	e_data_cal_notify_object_list (cal, GNOME_Evolution_Calendar_Success, tasks);
+}
+
+void 
+e_cal_backend_couchdb_get_attachment_list (ECalBackend *backend, EDataCal *cal, const gchar *uid, const gchar *rid)
+{
+	g_warning ("In _get_attachment_list");
+	e_data_cal_notify_attachment_list (cal, GNOME_Evolution_Calendar_OtherError, NULL);
+}
+
+/* Timezone related virtual methods */
+void 
+e_cal_backend_couchdb_get_timezone (ECalBackend *backend, EDataCal *cal, const gchar *tzid)
+{
+	g_warning ("In _get_timezone");
+	e_data_cal_notify_timezone_requested (cal, GNOME_Evolution_Calendar_OtherError, NULL);
+}
+
+void 
+e_cal_backend_couchdb_add_timezone (ECalBackend *backend, EDataCal *cal, const gchar *object)
+{
+	g_warning ("In _add_timezone");
+	e_data_cal_notify_timezone_added (cal, GNOME_Evolution_Calendar_OtherError, NULL);
+}
+
+void 
+e_cal_backend_couchdb_set_default_zone (ECalBackend *backend, EDataCal *cal, const gchar *tzobj)
+{
+	g_warning ("In _set_default_zone");
+	icalcomponent *tz_comp;
+	ECalBackendCouchDB *couchdb_backend;
+	icaltimezone *zone;
+
+	couchdb_backend = (ECalBackendCouchDB *) backend;
+
+	if (!(E_IS_CAL_BACKEND_COUCHDB(couchdb_backend)))
+		e_data_cal_notify_default_timezone_set (cal, GNOME_Evolution_Calendar_OtherError);
+	if (!(tzobj != NULL))
+		e_data_cal_notify_default_timezone_set (cal, GNOME_Evolution_Calendar_OtherError);
+
+	tz_comp = icalparser_parse_string (tzobj);
+	if (!tz_comp)
+		e_data_cal_notify_default_timezone_set (cal, GNOME_Evolution_Calendar_InvalidObject);
+
+	zone = icaltimezone_new ();
+	icaltimezone_set_component (zone, tz_comp);
+
+	if (couchdb_backend->default_zone)
+		icaltimezone_free (couchdb_backend->default_zone, 1);
+
+	couchdb_backend->default_zone = zone;
+	e_data_cal_notify_default_timezone_set (cal, GNOME_Evolution_Calendar_Success);
+}
+
+/*void 
+e_cal_backend_couchdb_set_default_timezone (ECalBackend *backend, EDataCal *cal, const gchar *tzid)
+{
+	e_cal_backend_notify_error (backend, "No implemented");
+}*/
+
+static icaltimezone *
+e_cal_backend_couchdb_internal_get_default_timezone (ECalBackend *backend)
+{	
+	g_warning ("In _internal_get_default_timezone");
+	ECalBackendCouchDB *couchdb_backend = E_CAL_BACKEND_COUCHDB (backend);
+	return couchdb_backend->default_zone;
+}
+
+void 
+e_cal_backend_couchdb_start_query (ECalBackend *backend, EDataCalView *query)
+{
+	g_warning ("In _start_query");
+	GList *doc_list;
+	ECalBackendCouchDB *couchdb_backend = E_CAL_BACKEND_COUCHDB (backend);
+	ECalBackendSExp *sexp;
+
+	e_cal_backend_add_query (backend, query);
+	sexp = e_data_cal_view_get_object_sexp (query);
+
+	// Get the list of documents from cache
+	doc_list = e_cal_backend_cache_get_components (couchdb_backend->cache);
+
+	while (doc_list != NULL) {
+		gchar *task_string;
+		ECalComponent *task = E_CAL_COMPONENT (doc_list->data);
+
+		e_cal_component_commit_sequence (task);
+		task_string = e_cal_component_get_as_string (task);
+		if (!task_string)
+			continue;
+
+		if (e_cal_backend_sexp_match_comp (sexp, task, backend))
+			e_data_cal_view_notify_objects_added_1 (query, task_string);
+
+		doc_list = g_list_remove (doc_list, task);
+		g_object_unref (G_OBJECT (task));
+	}
+
+
+	e_data_cal_view_notify_done (query, GNOME_Evolution_Calendar_Success);
+
+	//e_data_cal_notify_query (cal, GNOME_Evolution_Calendar_Success, query);
+}
+
+/* Mode relate virtual methods */
+CalMode 
+e_cal_backend_couchdb_get_mode (ECalBackend *backend)
+{
+	g_warning ("In _get_mode");
+	//e_data_cal_notify_mode (NULL, GNOME_Evolution_Calendar_OtherError, GNOME_Evolution_Calendar_CalListener_MODE_NOT_SET);
+	return CAL_MODE_LOCAL;
+}
+
+void 
+e_cal_backend_couchdb_set_mode (ECalBackend *backend, CalMode mode)
+{
+	g_warning ("In _set_mode");
+	//e_data_cal_notify_mode (NULL, GNOME_Evolution_Calendar_OtherError, GNOME_Evolution_Calendar_CalListener_MODE_NOT_SET);
+	e_cal_backend_notify_mode (backend, GNOME_Evolution_Calendar_CalListener_MODE_SET, GNOME_Evolution_Calendar_MODE_REMOTE);
+}
+
+void 
+e_cal_backend_couchdb_get_free_busy (ECalBackend *backend, EDataCal *cal, GList *users, time_t start, time_t end)
+{
+	g_warning ("In _get_free_busy");
+	e_data_cal_notify_free_busy (cal, GNOME_Evolution_Calendar_OtherError, NULL);
+}
+
+void 
+e_cal_backend_couchdb_get_changes (ECalBackend *backend, EDataCal *cal, const gchar *change_id)
+{
+	g_warning ("In _get_changes");
+	e_data_cal_notify_changes (cal, GNOME_Evolution_Calendar_OtherError, NULL, NULL, NULL);
+}
+
+static void
+e_cal_backend_couchdb_dispose (GObject *object)
+{
+	g_warning ("In _dispose");
+
+	ECalBackendCouchDB *couchdb_backend;
+
+	couchdb_backend = E_CAL_BACKEND_COUCHDB (object);
+
+	// Free all memory and resources
+	if (couchdb_backend->couchdb) {
+		g_object_unref (G_OBJECT (couchdb_backend->couchdb));
+		couchdb_backend->couchdb = NULL;
+	}
+
+	if (couchdb_backend->cache != NULL) {
+		g_object_unref (G_OBJECT (couchdb_backend->cache));
+		couchdb_backend->cache = NULL;
+	}
+
+	if (couchdb_backend->dbname) {
+		g_free (couchdb_backend->dbname);
+		couchdb_backend->dbname = NULL;
+	}
+
+}
+
+
+static void
+e_cal_backend_couchdb_class_init (ECalBackendCouchDBClass *klass)
+{
+
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	ECalBackendClass *parent_class;
+
+	parent_class = E_CAL_BACKEND_CLASS (klass);
+
+	// Virtual methods 
+	parent_class->is_read_only            = e_cal_backend_couchdb_is_read_only;
+	parent_class->get_cal_address	      = e_cal_backend_couchdb_get_cal_address;
+	parent_class->get_alarm_email_address = e_cal_backend_couchdb_get_alarm_email_address;
+	parent_class->get_ldap_attribute      = e_cal_backend_couchdb_get_ldap_attribute;
+	parent_class->get_static_capabilities = e_cal_backend_couchdb_get_static_capabilities;
+
+	parent_class->open	              = e_cal_backend_couchdb_open;
+	parent_class->remove		      = e_cal_backend_couchdb_remove;
+
+	// Object related virtual methods 
+	parent_class->create_object           = e_cal_backend_couchdb_create_object;
+	parent_class->modify_object           = e_cal_backend_couchdb_modify_object;
+	parent_class->remove_object           = e_cal_backend_couchdb_remove_object;
+
+	parent_class->discard_alarm           = e_cal_backend_couchdb_discard_alarm;
+
+	parent_class->receive_objects         = e_cal_backend_couchdb_receive_objects;
+	parent_class->send_objects    	      = e_cal_backend_couchdb_send_objects;
+
+	parent_class->get_default_object      = e_cal_backend_couchdb_get_default_object;
+	parent_class->get_object	      = e_cal_backend_couchdb_get_object;
+	parent_class->get_object_list         = e_cal_backend_couchdb_get_object_list;
+
+	parent_class->get_attachment_list     = e_cal_backend_couchdb_get_attachment_list;
+
+
+	// Timezone related virtual methods 
+	parent_class->get_timezone            = e_cal_backend_couchdb_get_timezone;
+	parent_class->add_timezone            = e_cal_backend_couchdb_add_timezone;
+	parent_class->set_default_zone        = e_cal_backend_couchdb_set_default_zone;
+	//parent_class->set_default_timezone    = e_cal_backend_couchdb_set_default_timezone;
+	parent_class->internal_get_default_timezone = e_cal_backend_couchdb_internal_get_default_timezone;
+
+	parent_class->start_query             = e_cal_backend_couchdb_start_query;
+
+	// Mode relate virtual methods 
+	parent_class->get_mode                = e_cal_backend_couchdb_get_mode;
+	parent_class->set_mode                = e_cal_backend_couchdb_set_mode;
+
+	parent_class->get_free_busy           = e_cal_backend_couchdb_get_free_busy;
+	parent_class->get_changes             = e_cal_backend_couchdb_get_changes;
+
+	object_class->dispose                 = e_cal_backend_couchdb_dispose;
+	
+
+}
+
+static void
+e_cal_backend_couchdb_init (ECalBackendCouchDB *backend)
+{
+	backend->couchdb = NULL;
+	backend->dbname = NULL;
+	backend->cache = NULL;
+}
diff --git a/calendar/e-cal-backend-couchdb.h b/calendar/e-cal-backend-couchdb.h
new file mode 100644
index 0000000..3aa7d8d
--- /dev/null
+++ b/calendar/e-cal-backend-couchdb.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/* e-cal-backend-couchdb.h - CouchDB calendar backend factory.
+ *
+ * Copyright (C) 2009 Canonical, Ltd. (www.canonical.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 3 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, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Miguel Angel Rodelas Delgado <miguel rodelas gmail com>
+ */
+
+#ifndef __E_CAL_BACKEND_COUCHDB_H__
+#define __E_CAL_BACKEND_COUCHDB_H__
+
+#include <couchdb-glib.h>
+#include <desktopcouch-glib.h>
+#include <libedata-cal/e-cal-backend.h>
+#include <libedata-cal/e-cal-backend-cache.h>
+
+#define E_TYPE_CAL_BACKEND_COUCHDB        (e_cal_backend_couchdb_get_type ())
+#define E_CAL_BACKEND_COUCHDB(o)          (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_CAL_BACKEND_COUCHDB, ECalBackendCouchDB))
+#define E_CAL_BACKEND_COUCHDB_CLASS(k)    (G_TYPE_CHECK_CLASS_CAST((k), E_TYPE_CAL_BACKEND_COUCHDB, ECalBackendCouchDBClass))
+#define E_IS_CAL_BACKEND_COUCHDB(o)       (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_CAL_BACKEND_COUCHDB))
+#define E_IS_CAL_BACKEND_COUCHDB_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_CAL_BACKEND_COUCHDB))
+#define E_CAL_BACKEND_COUCHDB_GET_CLASS(k) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_CAL_BACKEND_COUCHDB, ECalBackenCouchDBClass))
+
+
+typedef struct {
+	ECalBackend parent_object;
+
+	CouchdbSession *couchdb;
+	ECalBackendCache *cache;
+	char *dbname;
+	gboolean using_desktopcouch;
+
+	icaltimezone *default_zone;
+} ECalBackendCouchDB;
+
+typedef struct {
+	ECalBackendClass parent_class;
+} ECalBackendCouchDBClass;
+
+
+GType         e_cal_backend_couchdb_get_type (void);
+ECalBackend *e_cal_backend_couchdb_new (void);
+
+#endif



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]