[evolution-data-server/treitter-factory-refactor] Factor out generic EDataFactory (and subclasses) from EDataBookFactory.



commit ebef732018837b0939c5f59d53cb6faf527e1b21
Author: Travis Reitter <treitter gmail com>
Date:   Tue Jan 26 09:56:18 2010 -0800

    Factor out generic EDataFactory (and subclasses) from EDataBookFactory.

 addressbook/libedata-book/e-book-backend-factory.c |   50 +--
 addressbook/libedata-book/e-book-backend-factory.h |    5 +-
 addressbook/libedata-book/e-book-backend-sexp.c    |   33 +--
 addressbook/libedata-book/e-book-backend-sexp.h    |   16 +-
 addressbook/libedata-book/e-book-backend.c         |  231 ++++------
 addressbook/libedata-book/e-book-backend.h         |    8 +-
 addressbook/libedata-book/e-data-book-factory.c    |  369 ++-------------
 addressbook/libedata-book/e-data-book-factory.h    |    6 +-
 addressbook/libedata-book/e-data-book-view.c       |  313 +++++++-----
 addressbook/libedata-book/e-data-book-view.h       |    4 +-
 addressbook/libedata-book/e-data-book.c            |  144 +++----
 addressbook/libedata-book/e-data-book.h            |   12 +-
 configure.ac                                       |    2 +-
 libebackend/Makefile.am                            |   18 +-
 libebackend/e-backend-factory.c                    |   75 +++
 libebackend/e-backend-factory.h                    |   60 +++
 libebackend/e-backend-sexp.c                       |   67 +++
 libebackend/e-backend-sexp.h                       |   58 +++
 libebackend/e-backend.c                            |  474 ++++++++++++++++++
 libebackend/e-backend.h                            |  158 ++++++
 libebackend/e-data-factory.c                       |  505 ++++++++++++++++++++
 libebackend/e-data-factory.h                       |   86 ++++
 libebackend/e-data-types.h                         |   76 +++
 libebackend/e-data-view.c                          |  323 +++++++++++++
 libebackend/e-data-view.h                          |   65 +++
 libebackend/e-data.c                               |  241 ++++++++++
 libebackend/e-data.h                               |   71 +++
 27 files changed, 2677 insertions(+), 793 deletions(-)
---
diff --git a/addressbook/libedata-book/e-book-backend-factory.c b/addressbook/libedata-book/e-book-backend-factory.c
index 66fdcc0..336810b 100644
--- a/addressbook/libedata-book/e-book-backend-factory.c
+++ b/addressbook/libedata-book/e-book-backend-factory.c
@@ -12,42 +12,11 @@
 #endif
 
 #include <string.h>
+#include <libebackend/e-backend-factory.h>
 
 #include "e-book-backend-factory.h"
 
-static void
-e_book_backend_factory_instance_init (EBookBackendFactory *factory)
-{
-}
-
-static void
-e_book_backend_factory_class_init (EBookBackendFactoryClass *klass)
-{
-}
-
-GType
-e_book_backend_factory_get_type (void)
-{
-	static GType type = 0;
-
-	if (! type) {
-		GTypeInfo info = {
-			sizeof (EBookBackendFactoryClass),
-			NULL, /* base_class_init */
-			NULL, /* base_class_finalize */
-			(GClassInitFunc)  e_book_backend_factory_class_init,
-			NULL, /* class_finalize */
-			NULL, /* class_data */
-			sizeof (EBookBackendFactory),
-			0,    /* n_preallocs */
-			(GInstanceInitFunc) e_book_backend_factory_instance_init
-		};
-
-		type = g_type_register_static (G_TYPE_OBJECT, "EBookBackendFactory", &info, 0);
-	}
-
-	return type;
-}
+G_DEFINE_TYPE (EBookBackendFactory, e_book_backend_factory, E_TYPE_BACKEND_FACTORY);
 
 /**
  * e_book_backend_factory_get_protocol:
@@ -80,3 +49,18 @@ e_book_backend_factory_new_backend (EBookBackendFactory *factory)
 
 	return E_BOOK_BACKEND_FACTORY_GET_CLASS (factory)->new_backend (factory);
 }
+
+static void
+e_book_backend_factory_init (EBookBackendFactory *factory)
+{
+}
+
+static void
+e_book_backend_factory_class_init (EBookBackendFactoryClass *klass)
+{
+	EBackendFactoryClass *parent_class = E_BACKEND_FACTORY_CLASS (klass);
+
+	/* XXX: do some ugly casting to avoid breaking API */
+	parent_class->get_protocol = (const char* (*)(EBackendFactory*)) e_book_backend_factory_get_protocol;
+	parent_class->new_backend = (EBackend* (*)(EBackendFactory*)) e_book_backend_factory_new_backend;
+}
diff --git a/addressbook/libedata-book/e-book-backend-factory.h b/addressbook/libedata-book/e-book-backend-factory.h
index 4739367..318aa62 100644
--- a/addressbook/libedata-book/e-book-backend-factory.h
+++ b/addressbook/libedata-book/e-book-backend-factory.h
@@ -24,6 +24,7 @@
 #define _E_BOOK_BACKEND_FACTORY_H_
 
 #include <glib-object.h>
+#include <libebackend/e-backend-factory.h>
 #include "e-book-backend.h"
 
 G_BEGIN_DECLS
@@ -38,11 +39,11 @@ G_BEGIN_DECLS
 typedef struct _EBookBackendFactoryPrivate EBookBackendFactoryPrivate;
 
 typedef struct {
-	GObject            parent_object;
+	EBackendFactory parent_object;
 } EBookBackendFactory;
 
 typedef struct {
-	GObjectClass parent_class;
+	EBackendFactoryClass parent_class;
 
 	const gchar *   (*get_protocol) (EBookBackendFactory *factory);
 	EBookBackend* (*new_backend)  (EBookBackendFactory *factory);
diff --git a/addressbook/libedata-book/e-book-backend-sexp.c b/addressbook/libedata-book/e-book-backend-sexp.c
index de16beb..77dfd1e 100644
--- a/addressbook/libedata-book/e-book-backend-sexp.c
+++ b/addressbook/libedata-book/e-book-backend-sexp.c
@@ -23,7 +23,7 @@
 #include "libedataserver/e-data-server-util.h"
 #include "e-book-backend-sexp.h"
 
-static GObjectClass *parent_class;
+static EBackendSExpClass *parent_class;
 
 typedef struct _SearchContext SearchContext;
 
@@ -36,6 +36,8 @@ struct _SearchContext {
 	EContact *contact;
 };
 
+G_DEFINE_TYPE (EBookBackendSExp, e_book_backend_sexp, E_TYPE_BACKEND_SEXP);
+
 static gboolean
 compare_im (EContact *contact, const gchar *str,
 	    gchar *(*compare)(const gchar *, const gchar *),
@@ -864,7 +866,7 @@ e_book_backend_sexp_match_vcard (EBookBackendSExp *sexp, const gchar *vcard)
 EBookBackendSExp *
 e_book_backend_sexp_new (const gchar *text)
 {
-	EBookBackendSExp *sexp = g_object_new (E_TYPE_BACKEND_SEXP, NULL);
+	EBookBackendSExp *sexp = g_object_new (E_TYPE_BOOK_BACKEND_SEXP, NULL);
 	gint esexp_error;
 	gint i;
 
@@ -931,30 +933,3 @@ e_book_backend_sexp_init (EBookBackendSExp *sexp)
 	sexp->priv = priv;
 	priv->search_context = g_new (SearchContext, 1);
 }
-
-/**
- * e_book_backend_sexp_get_type:
- */
-GType
-e_book_backend_sexp_get_type (void)
-{
-	static GType type = 0;
-
-	if (! type) {
-		GTypeInfo info = {
-			sizeof (EBookBackendSExpClass),
-			NULL, /* base_class_init */
-			NULL, /* base_class_finalize */
-			(GClassInitFunc)  e_book_backend_sexp_class_init,
-			NULL, /* class_finalize */
-			NULL, /* class_data */
-			sizeof (EBookBackendSExp),
-			0,    /* n_preallocs */
-			(GInstanceInitFunc) e_book_backend_sexp_init
-		};
-
-		type = g_type_register_static (G_TYPE_OBJECT, "EBookBackendSExp", &info, 0);
-	}
-
-	return type;
-}
diff --git a/addressbook/libedata-book/e-book-backend-sexp.h b/addressbook/libedata-book/e-book-backend-sexp.h
index 42d6e93..b724eda 100644
--- a/addressbook/libedata-book/e-book-backend-sexp.h
+++ b/addressbook/libedata-book/e-book-backend-sexp.h
@@ -28,25 +28,27 @@
 #include <glib-object.h>
 #include <libebook/e-contact.h>
 #include <libedata-book/e-data-book-types.h>
+#include <libebackend/e-data-types.h>
+#include <libebackend/e-backend-sexp.h>
 
 G_BEGIN_DECLS
 
-#define E_TYPE_BACKEND_SEXP        (e_book_backend_sexp_get_type ())
-#define E_BOOK_BACKEND_SEXP(o)          (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_BACKEND_SEXP, EBookBackendSExp))
+#define E_TYPE_BOOK_BACKEND_SEXP        (e_book_backend_sexp_get_type ())
+#define E_BOOK_BACKEND_SEXP(o)          (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_BOOK_BACKEND_SEXP, EBookBackendSExp))
 #define E_BOOK_BACKEND_SEXP_CLASS(k)    (G_TYPE_CHECK_CLASS_CAST((k), E_BOOK_BACKEND_TYPE, EBookBackendSExpClass))
-#define E_IS_BACKEND_SEXP(o)       (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_BACKEND_SEXP))
-#define E_IS_BACKEND_SEXP_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_BACKEND_SEXP))
-#define E_BOOK_BACKEND_SEXP_GET_CLASS(k) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_BACKEND_SEXP, EBookBackendSExpClass))
+#define E_IS_BOOK_BACKEND_SEXP(o)       (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_BOOK_BACKEND_SEXP))
+#define E_IS_BOOK_BACKEND_SEXP_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_BOOK_BACKEND_SEXP))
+#define E_BOOK_BACKEND_SEXP_GET_CLASS(k) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_BOOK_BACKEND_SEXP, EBookBackendSExpClass))
 
 typedef struct _EBookBackendSExpPrivate EBookBackendSExpPrivate;
 
 struct _EBookBackendSExp {
-	GObject parent_object;
+	EBackendSExp parent_object;
 	EBookBackendSExpPrivate *priv;
 };
 
 struct _EBookBackendSExpClass {
-	GObjectClass parent_class;
+	EBackendSExpClass parent_class;
 };
 
 EBookBackendSExp *e_book_backend_sexp_new      (const gchar *text);
diff --git a/addressbook/libedata-book/e-book-backend.c b/addressbook/libedata-book/e-book-backend.c
index 0842906..609b943 100644
--- a/addressbook/libedata-book/e-book-backend.c
+++ b/addressbook/libedata-book/e-book-backend.c
@@ -11,29 +11,22 @@
 #include "e-data-book-view.h"
 #include "e-data-book.h"
 #include "e-book-backend.h"
+#include <libebackend/e-data-types.h>
+#include <libebackend/e-data.h>
+#include <libebackend/e-backend.h>
 
 struct _EBookBackendPrivate {
 	GMutex *open_mutex;
 
-	GMutex *clients_mutex;
-	GList *clients;
-
-	ESource *source;
-	gboolean loaded, writable, removed, online;
-
-	GMutex *views_mutex;
-	EList *views;
+	gboolean loaded;
+	gboolean writable;
+	gboolean removed;
+	gboolean online;
 };
 
-/* Signal IDs */
-enum {
-	LAST_CLIENT_GONE,
-	LAST_SIGNAL
-};
-
-static guint e_book_backend_signals[LAST_SIGNAL];
+static EBackendClass *parent_class;
 
-static GObjectClass *parent_class;
+G_DEFINE_TYPE (EBookBackend, e_book_backend, E_TYPE_BACKEND);
 
 /**
  * e_book_backend_construct:
@@ -75,8 +68,7 @@ e_book_backend_load_source (EBookBackend           *backend,
 	status = (* E_BOOK_BACKEND_GET_CLASS (backend)->load_source) (backend, source, only_if_exists);
 
 	if (status == GNOME_Evolution_Addressbook_Success || status == GNOME_Evolution_Addressbook_InvalidServerVersion) {
-		g_object_ref (source);
-		backend->priv->source = source;
+		e_backend_set_source (E_BACKEND (backend), source);
 	}
 
 	return status;
@@ -95,7 +87,7 @@ e_book_backend_get_source (EBookBackend *backend)
 {
 	g_return_val_if_fail (E_IS_BOOK_BACKEND (backend), NULL);
 
-	return backend->priv->source;
+	return e_backend_get_source (E_BACKEND (backend));
 }
 
 /**
@@ -469,12 +461,6 @@ e_book_backend_cancel_operation (EBookBackend *backend,
 	return (* E_BOOK_BACKEND_GET_CLASS (backend)->cancel_operation) (backend, book);
 }
 
-static void
-last_client_gone (EBookBackend *backend)
-{
-	g_signal_emit (backend, e_book_backend_signals[LAST_CLIENT_GONE], 0);
-}
-
 /**
  * e_book_backend_get_book_views:
  * @backend: an #EBookBackend
@@ -488,7 +474,7 @@ e_book_backend_get_book_views (EBookBackend *backend)
 {
 	g_return_val_if_fail (E_IS_BOOK_BACKEND (backend), NULL);
 
-	return g_object_ref (backend->priv->views);
+	return e_backend_get_views (E_BACKEND (backend));
 }
 
 /**
@@ -504,11 +490,7 @@ e_book_backend_add_book_view (EBookBackend *backend,
 {
 	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
 
-	g_mutex_lock (backend->priv->views_mutex);
-
-	e_list_append (backend->priv->views, view);
-
-	g_mutex_unlock (backend->priv->views_mutex);
+	e_backend_add_view (E_BACKEND (backend), E_DATA_VIEW (view));
 }
 
 /**
@@ -524,34 +506,26 @@ e_book_backend_remove_book_view (EBookBackend *backend,
 {
 	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
 
-	g_mutex_lock (backend->priv->views_mutex);
-
-	e_list_remove (backend->priv->views, view);
-
-	g_mutex_unlock (backend->priv->views_mutex);
+	e_backend_add_view (E_BACKEND (backend), E_DATA_VIEW (view));
 }
 
 /**
  * e_book_backend_add_client:
  * @backend: An addressbook backend.
- * @book: the corba object representing the client connection.
+ * @book: the object representing the client connection.
  *
  * Adds a client to an addressbook backend.
  *
  * Return value: TRUE on success, FALSE on failure to add the client.
  */
 gboolean
-e_book_backend_add_client (EBookBackend      *backend,
-			   EDataBook         *book)
+e_book_backend_add_client (EBookBackend *backend,
+			   EDataBook    *book)
 {
 	g_return_val_if_fail (E_IS_BOOK_BACKEND (backend), FALSE);
 	g_return_val_if_fail (E_IS_DATA_BOOK (book), FALSE);
 
-	g_mutex_lock (backend->priv->clients_mutex);
-	backend->priv->clients = g_list_prepend (backend->priv->clients, book);
-	g_mutex_unlock (backend->priv->clients_mutex);
-
-	return TRUE;
+	return e_backend_add_client (E_BACKEND (backend), E_DATA (book));
 }
 
 /**
@@ -565,27 +539,7 @@ void
 e_book_backend_remove_client (EBookBackend *backend,
 			      EDataBook    *book)
 {
-	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
-	g_return_if_fail (E_IS_DATA_BOOK (book));
-
-	/* up our backend's refcount here so that last_client_gone
-	   doesn't end up unreffing us (while we're holding the
-	   lock) */
-	g_object_ref (backend);
-
-	/* Disconnect */
-	g_mutex_lock (backend->priv->clients_mutex);
-	backend->priv->clients = g_list_remove (backend->priv->clients, book);
-
-	/* When all clients go away, notify the parent factory about it so that
-	 * it may decide whether to kill the backend or not.
-	 */
-	if (!backend->priv->clients)
-		last_client_gone (backend);
-
-	g_mutex_unlock (backend->priv->clients_mutex);
-
-	g_object_unref (backend);
+	e_backend_remove_client (E_BACKEND (backend), E_DATA (book));
 }
 
 /**
@@ -717,6 +671,31 @@ e_book_backend_set_is_removed (EBookBackend *backend, gboolean is_removed)
 	backend->priv->removed = is_removed;
 }
 
+static void
+e_book_backend_set_mode_from_data_mode (EBookBackend *backend,
+					EDataMode     mode)
+{
+	GNOME_Evolution_Addressbook_BookMode real_mode = E_DATA_BOOK_MODE_ANY;
+
+	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
+
+	switch (mode) {
+		case E_DATA_MODE_LOCAL:
+			real_mode = E_DATA_BOOK_MODE_LOCAL;
+			break;
+		case E_DATA_MODE_REMOTE:
+			real_mode = E_DATA_BOOK_MODE_REMOTE;
+			break;
+		case E_DATA_MODE_ANY:
+			real_mode = E_DATA_BOOK_MODE_ANY;
+			break;
+		default:
+			g_warning (G_STRLOC ": unsupported EDataMode: %d; using 'any'", mode);
+	}
+
+	e_book_backend_set_mode (backend, real_mode);
+}
+
 /**
  * e_book_backend_set_mode:
  * @backend: an #EBookbackend
@@ -727,13 +706,13 @@ e_book_backend_set_is_removed (EBookBackend *backend, gboolean is_removed)
  **/
 void
 e_book_backend_set_mode (EBookBackend *backend,
-			 GNOME_Evolution_Addressbook_BookMode  mode)
+			 GNOME_Evolution_Addressbook_BookMode mode)
 {
 	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
 
 	g_assert (E_BOOK_BACKEND_GET_CLASS (backend)->set_mode);
 
-        (* E_BOOK_BACKEND_GET_CLASS (backend)->set_mode) (backend,  mode);
+        (* E_BOOK_BACKEND_GET_CLASS (backend)->set_mode) (backend, mode);
 
 }
 
@@ -921,18 +900,21 @@ e_book_backend_notify_complete (EBookBackend *backend)
 void
 e_book_backend_notify_writable (EBookBackend *backend, gboolean is_writable)
 {
-	EBookBackendPrivate *priv;
-	GList *clients;
+        EBookBackendPrivate *priv;
+        GList *l;
+	GMutex *mutex;
 
-	priv = backend->priv;
-	priv->writable = is_writable;
-	g_mutex_lock (priv->clients_mutex);
+        priv = backend->priv;
+        priv->writable = is_writable;
 
-	for (clients = priv->clients; clients != NULL; clients = g_list_next (clients))
-		e_data_book_report_writable (E_DATA_BOOK (clients->data), is_writable);
+	mutex = e_backend_get_clients_mutex (E_BACKEND (backend));
+        g_mutex_lock (mutex);
 
-	g_mutex_unlock (priv->clients_mutex);
+        l = e_backend_get_clients (E_BACKEND (backend));
+        for (; l != NULL; l = g_list_next (l))
+                e_data_book_report_writable (l->data, is_writable);
 
+        g_mutex_unlock (mutex);
 }
 
 /**
@@ -946,17 +928,21 @@ e_book_backend_notify_writable (EBookBackend *backend, gboolean is_writable)
 void
 e_book_backend_notify_connection_status (EBookBackend *backend, gboolean is_online)
 {
-	EBookBackendPrivate *priv;
-	GList *clients;
+        EBookBackendPrivate *priv;
+        GList *l;
+	GMutex *mutex;
 
-	priv = backend->priv;
-	priv->online = is_online;
-	g_mutex_lock (priv->clients_mutex);
+        priv = backend->priv;
+        priv->online = is_online;
 
-	for (clients = priv->clients; clients != NULL; clients = g_list_next (clients))
-		e_data_book_report_connection_status (E_DATA_BOOK (clients->data), is_online);
+	mutex = e_backend_get_clients_mutex (E_BACKEND (backend));
+        g_mutex_lock (mutex);
 
-	g_mutex_unlock (priv->clients_mutex);
+        l = e_backend_get_clients (E_BACKEND (backend));
+        for (; l != NULL; l = g_list_next (l))
+                e_data_book_report_connection_status (l->data, is_online);
+
+        g_mutex_unlock (mutex);
 }
 
 /**
@@ -969,15 +955,7 @@ e_book_backend_notify_connection_status (EBookBackend *backend, gboolean is_onli
 void
 e_book_backend_notify_auth_required (EBookBackend *backend)
 {
-	EBookBackendPrivate *priv;
-	GList *clients;
-
-	priv = backend->priv;
-	g_mutex_lock (priv->clients_mutex);
-
-	for (clients = priv->clients; clients != NULL; clients = g_list_next (clients))
-		e_data_book_report_auth_required (E_DATA_BOOK (clients->data));
-	g_mutex_unlock (priv->clients_mutex);
+	e_backend_notify_auth_required (E_BACKEND (backend));
 }
 
 static void
@@ -986,12 +964,7 @@ e_book_backend_init (EBookBackend *backend)
 	EBookBackendPrivate *priv;
 
 	priv          = g_new0 (EBookBackendPrivate, 1);
-	priv->clients = NULL;
-	priv->source = NULL;
-	priv->views   = e_list_new((EListCopyFunc) NULL, (EListFreeFunc) NULL, NULL);
 	priv->open_mutex = g_mutex_new ();
-	priv->clients_mutex = g_mutex_new ();
-	priv->views_mutex = g_mutex_new ();
 
 	backend->priv = priv;
 }
@@ -1004,21 +977,7 @@ e_book_backend_dispose (GObject *object)
 	backend = E_BOOK_BACKEND (object);
 
 	if (backend->priv) {
-		g_list_free (backend->priv->clients);
-
-		if (backend->priv->views) {
-			g_object_unref (backend->priv->views);
-			backend->priv->views = NULL;
-		}
-
-		if (backend->priv->source) {
-			g_object_unref (backend->priv->source);
-			backend->priv->source = NULL;
-		}
-
 		g_mutex_free (backend->priv->open_mutex);
-		g_mutex_free (backend->priv->clients_mutex);
-		g_mutex_free (backend->priv->views_mutex);
 
 		g_free (backend->priv);
 		backend->priv = NULL;
@@ -1030,47 +989,19 @@ e_book_backend_dispose (GObject *object)
 static void
 e_book_backend_class_init (EBookBackendClass *klass)
 {
-	GObjectClass *object_class;
-
-	parent_class = g_type_class_peek_parent (klass);
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
-	object_class = (GObjectClass *) klass;
+	parent_class = E_BACKEND_CLASS (klass);
 
 	object_class->dispose = e_book_backend_dispose;
 
-	e_book_backend_signals[LAST_CLIENT_GONE] =
-		g_signal_new ("last_client_gone",
-			      G_OBJECT_CLASS_TYPE (object_class),
-			      G_SIGNAL_RUN_FIRST,
-			      G_STRUCT_OFFSET (EBookBackendClass, last_client_gone),
-			      NULL, NULL,
-			      g_cclosure_marshal_VOID__VOID,
-			      G_TYPE_NONE, 0);
-}
-
-/**
- * e_book_backend_get_type:
- */
-GType
-e_book_backend_get_type (void)
-{
-	static GType type = 0;
-
-	if (! type) {
-		GTypeInfo info = {
-			sizeof (EBookBackendClass),
-			NULL, /* base_class_init */
-			NULL, /* base_class_finalize */
-			(GClassInitFunc)  e_book_backend_class_init,
-			NULL, /* class_finalize */
-			NULL, /* class_data */
-			sizeof (EBookBackend),
-			0,    /* n_preallocs */
-			(GInstanceInitFunc) e_book_backend_init
-		};
-
-		type = g_type_register_static (G_TYPE_OBJECT, "EBookBackend", &info, 0);
-	}
-
-	return type;
+	/* XXX: do some ugly casting to avoid breaking API */
+	parent_class->stop_view = (void (*)(EBackend*, EDataView*)) e_book_backend_stop_book_view;
+	parent_class->remove = (void (*)(EBackend*, EData*, guint32)) e_book_backend_remove;
+	parent_class->get_static_capabilities = (gchar* (*)(EBackend*)) e_book_backend_get_static_capabilities;
+	parent_class->set_mode = (void (*)(EBackend*, EDataMode)) e_book_backend_set_mode_from_data_mode;
+	parent_class->add_client = (gboolean (*)(EBackend*, EData*)) e_book_backend_add_client;
+	parent_class->remove_client = (void (*)(EBackend*, EData*)) e_book_backend_remove_client;
+	parent_class->is_loaded = (gboolean (*)(EBackend*)) e_book_backend_is_loaded;
+	parent_class->get_changes = (void (*)(EBackend*, EData*, guint32, const gchar *)) e_book_backend_get_changes;
 }
diff --git a/addressbook/libedata-book/e-book-backend.h b/addressbook/libedata-book/e-book-backend.h
index f33e6ee..c8645ea 100644
--- a/addressbook/libedata-book/e-book-backend.h
+++ b/addressbook/libedata-book/e-book-backend.h
@@ -42,12 +42,12 @@ G_BEGIN_DECLS
 typedef struct _EBookBackendPrivate EBookBackendPrivate;
 
 struct _EBookBackend {
-	GObject parent_object;
+	EBackend parent_object;
 	EBookBackendPrivate *priv;
 };
 
 struct _EBookBackendClass {
-	GObjectClass parent_class;
+	EBackendClass parent_class;
 
 	/* Virtual methods */
 	GNOME_Evolution_Addressbook_CallStatus (*load_source) (EBookBackend *backend, ESource *source, gboolean only_if_exists);
@@ -81,6 +81,8 @@ struct _EBookBackendClass {
 	void (*_pas_reserved4) (void);
 };
 
+GType       e_book_backend_get_type                 (void);
+
 gboolean    e_book_backend_construct                (EBookBackend             *backend);
 
 GNOME_Evolution_Addressbook_CallStatus
@@ -178,8 +180,6 @@ void        e_book_backend_notify_connection_status   (EBookBackend *backend, gb
 void        e_book_backend_notify_auth_required       (EBookBackend *backend);
 void        e_book_backend_sync                       (EBookBackend *backend);
 
-GType       e_book_backend_get_type                 (void);
-
 /* protected functions for subclasses */
 void        e_book_backend_set_is_loaded            (EBookBackend             *backend,
 						     gboolean                  is_loaded);
diff --git a/addressbook/libedata-book/e-data-book-factory.c b/addressbook/libedata-book/e-data-book-factory.c
index 88a755c..dbadcee 100644
--- a/addressbook/libedata-book/e-data-book-factory.c
+++ b/addressbook/libedata-book/e-data-book-factory.c
@@ -32,6 +32,7 @@
 #include <dbus/dbus-glib-bindings.h>
 #include <libebackend/e-data-server-module.h>
 #include <libebackend/e-offline-listener.h>
+#include <libebackend/e-data-factory.h>
 #include "e-book-backend-factory.h"
 #include "e-data-book-factory.h"
 #include "e-data-book.h"
@@ -43,10 +44,6 @@
 static void impl_BookFactory_getBook(EDataBookFactory *factory, const gchar *IN_uri, DBusGMethodInvocation *context);
 #include "e-data-book-factory-glue.h"
 
-static GMainLoop *loop;
-static EDataBookFactory *factory;
-extern DBusGConnection *connection;
-
 /* Convenience macro to test and set a GError/return on failure */
 #define g_set_error_val_if_fail(test, returnval, error, domain, code) G_STMT_START{ \
 		if G_LIKELY (test) {} else {				\
@@ -56,26 +53,11 @@ extern DBusGConnection *connection;
 		}							\
 	}G_STMT_END
 
-G_DEFINE_TYPE(EDataBookFactory, e_data_book_factory, G_TYPE_OBJECT);
+G_DEFINE_TYPE(EDataBookFactory, e_data_book_factory, E_TYPE_DATA_FACTORY);
 
 #define E_DATA_BOOK_FACTORY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), E_TYPE_DATA_BOOK_FACTORY, EDataBookFactoryPrivate))
 
 struct _EDataBookFactoryPrivate {
-	/* TODO: as the factory is not threaded these locks could be removed */
-	GMutex *backends_lock;
-	GHashTable *backends;
-
-	GMutex *books_lock;
-	/* A hash of object paths for book URIs to EDataBooks */
-	GHashTable *books;
-
-	GMutex *connections_lock;
-	/* This is a hash of client addresses to GList* of EDataBooks */
-	GHashTable *connections;
-
-	guint exit_timeout;
-
-        gint mode;
 };
 
 /* Create the EDataBookFactory error quark */
@@ -88,66 +70,28 @@ e_data_book_factory_error_quark (void)
 	return quark;
 }
 
-/**
- * e_data_book_factory_register_backend:
- * @factory: an #EDataBookFactory
- * @backend_factory: an #EBookBackendFactory
- *
- * Registers @backend_factory with @factory.
- **/
-static void
-e_data_book_factory_register_backend (EDataBookFactory      *book_factory,
-				      EBookBackendFactory   *backend_factory)
+static EDataBook*
+data_new (EBookBackend *backend,
+	  ESource      *source)
 {
-	const gchar *proto;
-
-	g_return_if_fail (E_IS_DATA_BOOK_FACTORY (book_factory));
-	g_return_if_fail (E_IS_BOOK_BACKEND_FACTORY (backend_factory));
+	g_return_val_if_fail (E_IS_BOOK_BACKEND (backend), NULL);
+	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
 
-	proto = E_BOOK_BACKEND_FACTORY_GET_CLASS (backend_factory)->get_protocol (backend_factory);
-
-	if (g_hash_table_lookup (book_factory->priv->backends, proto) != NULL) {
-		g_warning ("e_data_book_factory_register_backend: "
-			   "Proto \"%s\" already registered!\n", proto);
-	}
-
-	g_hash_table_insert (book_factory->priv->backends,
-			     g_strdup (proto), backend_factory);
+	return e_data_book_new (backend, source);
 }
 
-/**
- * e_data_book_factory_register_backends:
- * @book_factory: an #EDataBookFactory
- *
- * Register the backends supported by the Evolution Data Server,
- * with @book_factory.
- **/
-static void
-e_data_book_factory_register_backends (EDataBookFactory *book_factory)
+static GType
+get_backend_type ()
 {
-	GList *factories, *f;
-
-	factories = e_data_server_get_extensions_for_type (E_TYPE_BOOK_BACKEND_FACTORY);
-	for (f = factories; f; f = f->next) {
-		EBookBackendFactory *backend_factory = f->data;
-
-		e_data_book_factory_register_backend (book_factory, g_object_ref (backend_factory));
-	}
-
-	e_data_server_extension_list_free (factories);
-	e_data_server_module_remove_unused ();
+	return E_TYPE_BOOK_BACKEND_FACTORY;
 }
 
-static void
-set_backend_online_status (gpointer key, gpointer value, gpointer data)
+static const char*
+get_dbus_name_format (EDataBookFactory *factory)
 {
-	GList *books;
-	EBookBackend *backend = NULL;
+	g_return_val_if_fail (E_IS_DATA_BOOK_FACTORY (factory), NULL);
 
-	for (books = (GList *) value; books; books = g_list_next (books)) {
-		backend =  E_BOOK_BACKEND (books->data);
-		e_book_backend_set_mode (backend,  GPOINTER_TO_INT (data));
-	}
+	return "/org/gnome/evolution/dataserver/addressbook/%d/%u";
 }
 
 /**
@@ -160,18 +104,19 @@ set_backend_online_status (gpointer key, gpointer value, gpointer data)
 void
 e_data_book_factory_set_backend_mode (EDataBookFactory *factory, gint mode)
 {
-	EDataBookFactoryPrivate *priv = factory->priv;
-
-	priv->mode = mode;
-	g_mutex_lock (priv->connections_lock);
-	g_hash_table_foreach (priv->connections, set_backend_online_status, GINT_TO_POINTER (priv->mode));
-	g_mutex_unlock (priv->connections_lock);
+	e_data_factory_set_backend_mode (E_DATA_FACTORY (factory), mode);
 }
 
 static void
 e_data_book_factory_class_init (EDataBookFactoryClass *e_data_book_factory_class)
 {
-	g_type_class_add_private (e_data_book_factory_class, sizeof (EDataBookFactoryPrivate));
+	EDataFactoryClass *parent_class = E_DATA_FACTORY_CLASS (e_data_book_factory_class);
+
+	/* XXX: do some ugly casting to avoid breaking API */
+	parent_class->data_new = (EData* (*)(EBackend*, ESource*)) data_new;
+	parent_class->get_backend_type = get_backend_type;
+	parent_class->get_dbus_name_format = (const char* (*)(EDataFactory*)) get_dbus_name_format;
+
 	dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (e_data_book_factory_class), &dbus_glib_e_data_book_factory_object_info);
 }
 
@@ -179,284 +124,32 @@ e_data_book_factory_class_init (EDataBookFactoryClass *e_data_book_factory_class
 static void
 e_data_book_factory_init (EDataBookFactory *factory)
 {
-	factory->priv = E_DATA_BOOK_FACTORY_GET_PRIVATE (factory);
-
-	factory->priv->backends_lock = g_mutex_new ();
-	factory->priv->backends = g_hash_table_new (g_str_hash, g_str_equal);
-
-	factory->priv->books_lock = g_mutex_new ();
-	factory->priv->books = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
-
-	factory->priv->connections_lock = g_mutex_new ();
-	factory->priv->connections = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
-
-	e_data_server_module_init ();
-	e_data_book_factory_register_backends (factory);
-}
-
-/* TODO: write dispose to kill hash */
-static gchar *
-e_data_book_factory_extract_proto_from_uri (const gchar *uri)
-{
-	gchar *proto, *p;
-	p = strchr (uri, ':');
-	if (p == NULL)
-		return NULL;
-	proto = g_malloc0 (p - uri + 1);
-	strncpy (proto, uri, p - uri);
-	return proto;
-}
-
-static EBookBackendFactory*
-e_data_book_factory_lookup_backend_factory (EDataBookFactory *factory,
-					    const gchar     *uri)
-{
-	EBookBackendFactory *backend_factory;
-	gchar                *proto;
-
-	g_return_val_if_fail (E_IS_DATA_BOOK_FACTORY (factory), NULL);
-	g_return_val_if_fail (uri != NULL, NULL);
-
-	proto = e_data_book_factory_extract_proto_from_uri (uri);
-	if (proto == NULL) {
-		g_warning ("Cannot extract protocol from URI %s", uri);
-		return NULL;
-	}
-
-	backend_factory = g_hash_table_lookup (factory->priv->backends, proto);
-
-	g_free (proto);
-
-	return backend_factory;
-}
-
-static gchar *
-construct_book_factory_path (void)
-{
-	static volatile gint counter = 1;
-
-	return g_strdup_printf (
-		"/org/gnome/evolution/dataserver/addressbook/%d/%u",
-		getpid (),
-		g_atomic_int_exchange_and_add (&counter, 1));
-}
-
-static void
-my_remove (gchar *key, GObject *dead)
-{
-	EDataBookFactoryPrivate *priv = factory->priv;
-	GHashTableIter iter;
-	gpointer hkey, hvalue;
-
-	d (g_debug ("%s (%p) is dead", key, dead));
-
-	g_hash_table_remove (priv->books, key);
-
-	g_hash_table_iter_init (&iter, priv->connections);
-	while (g_hash_table_iter_next (&iter, &hkey, &hvalue)) {
-		GList *books = hvalue;
-
-		if (g_list_find (books, dead)) {
-			books = g_list_remove (books, dead);
-			if (books) {
-				g_hash_table_insert (priv->connections, g_strdup (hkey), books);
-			} else {
-				g_hash_table_remove (priv->connections, hkey);
-			}
-
-			break;
-		}
-	}
-
-	g_free (key);
-
-	/* If there are no open books, start a timer to quit */
-	if (priv->exit_timeout == 0 && g_hash_table_size (priv->books) == 0) {
-		priv->exit_timeout = g_timeout_add (10000, (GSourceFunc)g_main_loop_quit, loop);
-	}
-}
-
-static void
-impl_BookFactory_getBook(EDataBookFactory *factory, const gchar *IN_source, DBusGMethodInvocation *context)
-{
-	EDataBook *book;
-	EBookBackend *backend;
-	EDataBookFactoryPrivate *priv = factory->priv;
-	ESource *source;
-	gchar *uri, *path, *sender;
-	GList *list;
-
-	if (IN_source == NULL || IN_source[0] == '\0') {
-		dbus_g_method_return_error (context, g_error_new (E_DATA_BOOK_ERROR, E_DATA_BOOK_STATUS_NO_SUCH_BOOK, _("Empty URI")));
-		return;
-	}
-
-	/* Remove a pending exit */
-	if (priv->exit_timeout) {
-		g_source_remove (priv->exit_timeout);
-		priv->exit_timeout = 0;
-	}
-
-	g_mutex_lock (priv->backends_lock);
-
-	source = e_source_new_from_standalone_xml (IN_source);
-	if (!source) {
-		g_mutex_unlock (priv->backends_lock);
-		dbus_g_method_return_error (context, g_error_new (E_DATA_BOOK_ERROR, E_DATA_BOOK_STATUS_NO_SUCH_BOOK, _("Invalid source")));
-		return;
-	}
-
-	uri = e_source_get_uri (source);
-
-	g_mutex_lock (priv->books_lock);
-	backend = g_hash_table_lookup (priv->backends, uri);
-
-	if (!backend) {
-		EBookBackendFactory *backend_factory = e_data_book_factory_lookup_backend_factory (factory, uri);
-
-		if (backend_factory)
-			backend = e_book_backend_factory_new_backend (backend_factory);
-
-		if (backend) {
-			g_hash_table_insert (priv->backends, g_strdup (uri), backend);
-			e_book_backend_set_mode (backend, priv->mode);
-		}
-	}
-
-	if (!backend) {
-		g_free (uri);
-		g_object_unref (source);
-
-		g_mutex_unlock (priv->books_lock);
-		g_mutex_unlock (priv->backends_lock);
-		dbus_g_method_return_error (context, g_error_new (E_DATA_BOOK_ERROR, E_DATA_BOOK_STATUS_NO_SUCH_BOOK, _("Invalid source")));
-		return;
-	}
-
-	path = construct_book_factory_path ();
-	book = e_data_book_new (backend, source);
-	g_hash_table_insert (priv->books, g_strdup (path), book);
-	e_book_backend_add_client (backend, book);
-	dbus_g_connection_register_g_object (connection, path, G_OBJECT (book));
-	g_object_weak_ref (G_OBJECT (book), (GWeakNotify)my_remove, g_strdup (path));
-
-	/* Update the hash of open connections */
-	g_mutex_lock (priv->connections_lock);
-	sender = dbus_g_method_get_sender (context);
-	list = g_hash_table_lookup (priv->connections, sender);
-	list = g_list_prepend (list, book);
-	g_hash_table_insert (priv->connections, sender, list);
-	g_mutex_unlock (priv->connections_lock);
-
-	g_mutex_unlock (priv->books_lock);
-	g_mutex_unlock (priv->backends_lock);
-
-	g_object_unref (source);
-	g_free (uri);
-
-	dbus_g_method_return (context, path);
-}
-
-static void
-name_owner_changed (DBusGProxy *proxy,
-                    const gchar *name,
-                    const gchar *prev_owner,
-                    const gchar *new_owner,
-                    EDataBookFactory *factory)
-{
-	if (strcmp (new_owner, "") == 0 && strcmp (name, prev_owner) == 0) {
-		gchar *key;
-		GList *list = NULL;
-		g_mutex_lock (factory->priv->connections_lock);
-		while (g_hash_table_lookup_extended (factory->priv->connections, prev_owner, (gpointer)&key, (gpointer)&list)) {
-			/* this should trigger the book's weak ref notify
-			 * function, which will remove it from the list before
-			 * it's freed, and will remove the connection from
-			 * priv->connections once they're all gone */
-			g_object_unref (list->data);
-		}
-
-		g_mutex_unlock (factory->priv->connections_lock);
-	}
-}
-
-/* Convenience function to print an error and exit */
-G_GNUC_NORETURN static void
-die (const gchar *prefix, GError *error)
-{
-	g_error("%s: %s", prefix, error->message);
-	g_error_free (error);
-	exit(1);
 }
 
 static void
-offline_state_changed_cb (EOfflineListener *eol, EDataBookFactory *factory)
+impl_BookFactory_getBook (EDataBookFactory      *factory,
+			  const gchar           *IN_source,
+			  DBusGMethodInvocation *context)
 {
-	EOfflineListenerState state = e_offline_listener_get_state (eol);
-
-	g_return_if_fail (state == EOL_STATE_ONLINE || state == EOL_STATE_OFFLINE);
-
-	e_data_book_factory_set_backend_mode (factory, state == EOL_STATE_ONLINE ? E_DATA_BOOK_MODE_REMOTE : E_DATA_BOOK_MODE_LOCAL);
+	e_data_factory_publish_data (E_DATA_FACTORY (factory), IN_source, context);
 }
 
 #define E_DATA_BOOK_FACTORY_SERVICE_NAME "org.gnome.evolution.dataserver.AddressBook"
+#define E_DATA_BOOK_FACTORY_OBJECT_PATH "/org/gnome/evolution/dataserver/addressbook/BookFactory"
 
 gint
 main (gint argc, gchar **argv)
 {
-	GError *error = NULL;
-	DBusGProxy *bus_proxy;
-	guint32 request_name_ret;
-	EOfflineListener *eol;
+	EDataBookFactory *factory;
+	GMainLoop *loop;
 
 	g_type_init ();
 	g_set_prgname (E_PRGNAME);
 	if (!g_thread_supported ()) g_thread_init (NULL);
-	dbus_g_thread_init ();
 
 	loop = g_main_loop_new (NULL, FALSE);
 
-	/* Obtain a connection to the session bus */
-	connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
-	if (connection == NULL)
-		die ("Failed to open connection to bus", error);
-
-	bus_proxy = dbus_g_proxy_new_for_name (connection,
-					       DBUS_SERVICE_DBUS,
-					       DBUS_PATH_DBUS,
-					       DBUS_INTERFACE_DBUS);
-
-	if (!org_freedesktop_DBus_request_name (bus_proxy, E_DATA_BOOK_FACTORY_SERVICE_NAME,
-						0, &request_name_ret, &error))
-		die ("Failed to get name", error);
-
-	if (request_name_ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
-		g_error ("Got result code %u from requesting name", request_name_ret);
-		exit (1);
-	}
-
 	factory = g_object_new (E_TYPE_DATA_BOOK_FACTORY, NULL);
-	dbus_g_connection_register_g_object (connection,
-					     "/org/gnome/evolution/dataserver/addressbook/BookFactory",
-					     G_OBJECT (factory));
-
-	dbus_g_proxy_add_signal (bus_proxy, "NameOwnerChanged",
-				 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
-	dbus_g_proxy_connect_signal (bus_proxy, "NameOwnerChanged", G_CALLBACK (name_owner_changed), factory, NULL);
-
-	eol = e_offline_listener_new ();
-	offline_state_changed_cb (eol, factory);
-	g_signal_connect (eol, "changed", G_CALLBACK (offline_state_changed_cb), factory);
-
-	printf ("Server is up and running...\n");
-
-	g_main_loop_run (loop);
-
-	g_object_unref (eol);
-
-	dbus_g_connection_unref (connection);
-
-	printf ("Bye.\n");
 
-	return 0;
+	return e_data_factory_main (argc, argv, E_DATA_FACTORY (factory), loop, E_DATA_BOOK_FACTORY_SERVICE_NAME, E_DATA_BOOK_FACTORY_OBJECT_PATH);
 }
diff --git a/addressbook/libedata-book/e-data-book-factory.h b/addressbook/libedata-book/e-data-book-factory.h
index 298a988..f23a02d 100644
--- a/addressbook/libedata-book/e-data-book-factory.h
+++ b/addressbook/libedata-book/e-data-book-factory.h
@@ -22,6 +22,8 @@
 #define __E_DATA_BOOK_FACTORY_H__
 
 #include <glib-object.h>
+#include <libebackend/e-data-factory.h>
+#include "e-book-backend.h"
 
 G_BEGIN_DECLS
 
@@ -35,12 +37,12 @@ G_BEGIN_DECLS
 typedef struct _EDataBookFactoryPrivate EDataBookFactoryPrivate;
 
 typedef struct {
-	GObject parent;
+	EDataFactory parent;
 	EDataBookFactoryPrivate *priv;
 } EDataBookFactory;
 
 typedef struct {
-	GObjectClass parent;
+	EDataFactoryClass parent;
 } EDataBookFactoryClass;
 
 typedef enum {
diff --git a/addressbook/libedata-book/e-data-book-view.c b/addressbook/libedata-book/e-data-book-view.c
index 0594f06..5b715a7 100644
--- a/addressbook/libedata-book/e-data-book-view.c
+++ b/addressbook/libedata-book/e-data-book-view.c
@@ -29,8 +29,6 @@
 #include <libebook/e-contact.h>
 #include "e-data-book-view.h"
 
-extern DBusGConnection *connection;
-
 static gboolean impl_BookView_start (EDataBookView *view, GError **error);
 static gboolean impl_BookView_stop (EDataBookView *view, GError **error);
 static gboolean impl_BookView_dispose (EDataBookView *view, GError **eror);
@@ -39,20 +37,17 @@ static gboolean impl_BookView_dispose (EDataBookView *view, GError **eror);
 
 static void reset_array (GArray *array);
 
-G_DEFINE_TYPE (EDataBookView, e_data_book_view, G_TYPE_OBJECT);
+G_DEFINE_TYPE (EDataBookView, e_data_book_view, E_TYPE_DATA_VIEW);
 #define E_DATA_BOOK_VIEW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), E_TYPE_DATA_BOOK_VIEW, EDataBookViewPrivate))
 
 #define THRESHOLD 32
 
 struct _EDataBookViewPrivate {
-	EDataBook *book;
-	EBookBackend *backend;
-
-	gchar * card_query;
-	EBookBackendSExp *card_sexp;
+	gchar* query;
 	gint max_results;
 
 	gboolean running;
+
 	GMutex *pending_mutex;
 
 	GArray *adds;
@@ -64,6 +59,12 @@ struct _EDataBookViewPrivate {
 };
 
 enum {
+	PROP_NONE,
+	PROP_MAX_RESULTS,
+	PROP_QUERY,
+};
+
+enum {
 	CONTACTS_ADDED,
 	CONTACTS_CHANGED,
 	CONTACTS_REMOVED,
@@ -74,92 +75,17 @@ enum {
 
 static guint signals[LAST_SIGNAL] = { 0 };
 
-static void e_data_book_view_dispose (GObject *object);
-static void e_data_book_view_finalize (GObject *object);
-
 static void
-e_data_book_view_class_init (EDataBookViewClass *klass)
+e_data_book_view_stop_if_running (EDataBookView *view)
 {
-	GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
-	object_class->dispose = e_data_book_view_dispose;
-	object_class->finalize = e_data_book_view_finalize;
-
-	signals[CONTACTS_ADDED] =
-		g_signal_new ("contacts-added",
-			      G_OBJECT_CLASS_TYPE (klass),
-			      G_SIGNAL_RUN_LAST,
-			      0, NULL, NULL,
-			      g_cclosure_marshal_VOID__BOXED,
-			      G_TYPE_NONE, 1, G_TYPE_STRV);
-
-	signals[CONTACTS_CHANGED] =
-		g_signal_new ("contacts-changed",
-			      G_OBJECT_CLASS_TYPE (klass),
-			      G_SIGNAL_RUN_LAST,
-			      0, NULL, NULL,
-			      g_cclosure_marshal_VOID__BOXED,
-			      G_TYPE_NONE, 1, G_TYPE_STRV);
-
-	signals[CONTACTS_REMOVED] =
-		g_signal_new ("contacts-removed",
-			      G_OBJECT_CLASS_TYPE (klass),
-			      G_SIGNAL_RUN_LAST,
-			      0, NULL, NULL,
-			      g_cclosure_marshal_VOID__BOXED,
-			      G_TYPE_NONE, 1, G_TYPE_STRV);
-
-	signals[STATUS_MESSAGE] =
-		g_signal_new ("status-message",
-			      G_OBJECT_CLASS_TYPE (klass),
-			      G_SIGNAL_RUN_LAST,
-			      0, NULL, NULL,
-			      g_cclosure_marshal_VOID__STRING,
-			      G_TYPE_NONE, 1, G_TYPE_STRING);
-
-	signals[COMPLETE] =
-		g_signal_new ("complete",
-			      G_OBJECT_CLASS_TYPE (klass),
-			      G_SIGNAL_RUN_LAST,
-			      0, NULL, NULL,
-			      g_cclosure_marshal_VOID__UINT,
-			      G_TYPE_NONE, 1, G_TYPE_UINT);
-
-	g_type_class_add_private (klass, sizeof (EDataBookViewPrivate));
-
-	dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass), &dbus_glib_e_data_book_view_object_info);
-}
-
-static void
-e_data_book_view_init (EDataBookView *book_view)
-{
-	EDataBookViewPrivate *priv = E_DATA_BOOK_VIEW_GET_PRIVATE (book_view);
-	book_view->priv = priv;
-
-	priv->running = FALSE;
-	priv->pending_mutex = g_mutex_new ();
-
-	priv->adds = g_array_sized_new (TRUE, TRUE, sizeof (gchar *), THRESHOLD);
-	priv->changes = g_array_sized_new (TRUE, TRUE, sizeof (gchar *), THRESHOLD);
-	priv->removes = g_array_sized_new (TRUE, TRUE, sizeof (gchar *), THRESHOLD);
-
-	priv->ids = g_hash_table_new_full (g_str_hash, g_str_equal,
-					   g_free, NULL);
-}
-
-static void
-book_destroyed_cb (gpointer data, GObject *dead)
-{
-	EDataBookView *view = E_DATA_BOOK_VIEW (data);
 	EDataBookViewPrivate *priv = view->priv;
 
-	/* The book has just died, so unset the pointer so we don't try and remove a
-	   dead weak reference. */
-	view->priv->book = NULL;
-
 	/* If the view is running stop it here. */
 	if (priv->running) {
-		e_book_backend_stop_book_view (priv->backend, view);
+		EBookBackend *backend;
+
+		backend = E_BOOK_BACKEND (e_data_view_get_backend (E_DATA_VIEW (view)));
+		e_book_backend_stop_book_view (backend, view);
 		priv->running = FALSE;
 	}
 }
@@ -284,6 +210,7 @@ e_data_book_view_notify_update (EDataBookView *book_view,
 	gboolean currently_in_view, want_in_view;
 	const gchar *id;
 	gchar *vcard;
+	EBookBackendSExp *sexp;
 
 	if (!priv->running)
 		return;
@@ -294,8 +221,10 @@ e_data_book_view_notify_update (EDataBookView *book_view,
 
 	currently_in_view =
 		g_hash_table_lookup (priv->ids, id) != NULL;
+
+	sexp = E_BOOK_BACKEND_SEXP (e_data_view_get_sexp (E_DATA_VIEW (book_view)));
 	want_in_view =
-		e_book_backend_sexp_match_contact (priv->card_sexp, contact);
+		e_book_backend_sexp_match_contact (sexp, contact);
 
 	if (want_in_view) {
 		vcard = e_vcard_to_string (E_VCARD (contact),
@@ -334,6 +263,7 @@ e_data_book_view_notify_update_vcard (EDataBookView *book_view, gchar *vcard)
 	gboolean currently_in_view, want_in_view;
 	const gchar *id;
 	EContact *contact;
+	EBookBackendSExp *sexp;
 
 	if (!priv->running)
 		return;
@@ -344,8 +274,10 @@ e_data_book_view_notify_update_vcard (EDataBookView *book_view, gchar *vcard)
 	id = e_contact_get_const (contact, E_CONTACT_UID);
 	currently_in_view =
 		g_hash_table_lookup (priv->ids, id) != NULL;
+
+	sexp = E_BOOK_BACKEND_SEXP (e_data_view_get_sexp (E_DATA_VIEW (book_view)));
 	want_in_view =
-		e_book_backend_sexp_match_contact (priv->card_sexp, contact);
+		e_book_backend_sexp_match_contact (sexp, contact);
 
 	if (want_in_view) {
 		if (currently_in_view)
@@ -496,23 +428,13 @@ e_data_book_view_notify_status_message (EDataBookView *book_view, const gchar *m
 EDataBookView *
 e_data_book_view_new (EDataBook *book, const gchar *path, const gchar *card_query, EBookBackendSExp *card_sexp, gint max_results)
 {
-	EDataBookView *view;
-	EDataBookViewPrivate *priv;
-
-	view = g_object_new (E_TYPE_DATA_BOOK_VIEW, NULL);
-	priv = view->priv;
-
-	priv->book = book;
-	/* Attach a weak reference to the book, so if it dies the book view is destroyed too */
-	g_object_weak_ref (G_OBJECT (priv->book), book_destroyed_cb, view);
-	priv->backend = g_object_ref (e_data_book_get_backend (book));
-	priv->card_query = g_strdup (card_query);
-	priv->card_sexp = card_sexp;
-	priv->max_results = max_results;
-
-	dbus_g_connection_register_g_object (connection, path, G_OBJECT (view));
-
-	return view;
+	return g_object_new (E_TYPE_DATA_BOOK_VIEW,
+			"data", book,
+			"dbus-path", path,
+			"query", card_query,
+			"sexp", card_sexp,
+			"max-results", max_results,
+			NULL);
 }
 
 static void
@@ -521,23 +443,6 @@ e_data_book_view_dispose (GObject *object)
 	EDataBookView *book_view = E_DATA_BOOK_VIEW (object);
 	EDataBookViewPrivate *priv = book_view->priv;
 
-	if (priv->book) {
-		/* Remove the weak reference */
-		g_object_weak_unref (G_OBJECT (priv->book), book_destroyed_cb, book_view);
-		priv->book = NULL;
-	}
-
-	if (priv->backend) {
-		e_book_backend_remove_book_view (priv->backend, book_view);
-		g_object_unref (priv->backend);
-		priv->backend = NULL;
-	}
-
-	if (priv->card_sexp) {
-		g_object_unref (priv->card_sexp);
-		priv->card_sexp = NULL;
-	}
-
 	if (priv->idle_id) {
 		g_source_remove (priv->idle_id);
 		priv->idle_id = 0;
@@ -559,7 +464,7 @@ e_data_book_view_finalize (GObject *object)
 	g_array_free (priv->changes, TRUE);
 	g_array_free (priv->removes, TRUE);
 
-	g_free (priv->card_query);
+	g_free (priv->query);
 
 	g_mutex_free (priv->pending_mutex);
 
@@ -568,15 +473,161 @@ e_data_book_view_finalize (GObject *object)
 	G_OBJECT_CLASS (e_data_book_view_parent_class)->finalize (object);
 }
 
+static void
+e_data_book_view_get_property (GObject    *object,
+			       guint       property_id,
+			       GValue     *value,
+			       GParamSpec *pspec)
+{
+	EDataBookViewPrivate *priv = E_DATA_BOOK_VIEW (object)->priv;
+
+	switch (property_id)
+	{
+		case PROP_MAX_RESULTS:
+			g_value_set_int (value, priv->max_results);
+		break;
+
+		case PROP_QUERY:
+			g_value_set_string (value, priv->query);
+		break;
+
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+	}
+}
+
+static void
+e_data_book_view_set_property (GObject      *object,
+			       guint         property_id,
+			       const GValue *value,
+			       GParamSpec   *pspec)
+{
+	EDataBookViewPrivate *priv = E_DATA_BOOK_VIEW (object)->priv;
+
+        switch (property_id)
+        {
+                case PROP_MAX_RESULTS:
+                        priv->max_results = g_value_get_int (value);
+                break;
+
+                case PROP_QUERY:
+                        priv->query = g_value_dup_string (value);
+                break;
+
+                default:
+                        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+        }
+}
+
+static void
+e_data_book_view_class_init (EDataBookViewClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	EDataViewClass *parent_class = E_DATA_VIEW_CLASS (klass);
+
+	object_class->dispose = e_data_book_view_dispose;
+	object_class->finalize = e_data_book_view_finalize;
+	object_class->get_property = e_data_book_view_get_property;
+	object_class->set_property = e_data_book_view_set_property;
+
+	parent_class->stop_if_running = (void (*)(EDataView*)) e_data_book_view_stop_if_running;
+
+	signals[CONTACTS_ADDED] =
+		g_signal_new ("contacts-added",
+			      G_OBJECT_CLASS_TYPE (klass),
+			      G_SIGNAL_RUN_LAST,
+			      0, NULL, NULL,
+			      g_cclosure_marshal_VOID__BOXED,
+			      G_TYPE_NONE, 1, G_TYPE_STRV);
+
+	signals[CONTACTS_CHANGED] =
+		g_signal_new ("contacts-changed",
+			      G_OBJECT_CLASS_TYPE (klass),
+			      G_SIGNAL_RUN_LAST,
+			      0, NULL, NULL,
+			      g_cclosure_marshal_VOID__BOXED,
+			      G_TYPE_NONE, 1, G_TYPE_STRV);
+
+	signals[CONTACTS_REMOVED] =
+		g_signal_new ("contacts-removed",
+			      G_OBJECT_CLASS_TYPE (klass),
+			      G_SIGNAL_RUN_LAST,
+			      0, NULL, NULL,
+			      g_cclosure_marshal_VOID__BOXED,
+			      G_TYPE_NONE, 1, G_TYPE_STRV);
+
+	signals[STATUS_MESSAGE] =
+		g_signal_new ("status-message",
+			      G_OBJECT_CLASS_TYPE (klass),
+			      G_SIGNAL_RUN_LAST,
+			      0, NULL, NULL,
+			      g_cclosure_marshal_VOID__STRING,
+			      G_TYPE_NONE, 1, G_TYPE_STRING);
+
+	signals[COMPLETE] =
+		g_signal_new ("complete",
+			      G_OBJECT_CLASS_TYPE (klass),
+			      G_SIGNAL_RUN_LAST,
+			      0, NULL, NULL,
+			      g_cclosure_marshal_VOID__UINT,
+			      G_TYPE_NONE, 1, G_TYPE_UINT);
+
+        g_object_class_install_property
+                (object_class,
+                 PROP_MAX_RESULTS,
+                 g_param_spec_int
+                         ("max-results",
+                          "The maximum results to return",
+                          "The maximum number of results to return.",
+                          -1, G_MAXINT, -1,
+                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+                          G_PARAM_STATIC_STRINGS));
+
+        g_object_class_install_property
+                (object_class,
+                 PROP_QUERY,
+                 g_param_spec_string
+                         ("query",
+                          "String version of view's query",
+                          "The string version of the view's query.",
+                          "",
+                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+                          G_PARAM_STATIC_STRINGS));
+
+	g_type_class_add_private (klass, sizeof (EDataBookViewPrivate));
+
+	dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass), &dbus_glib_e_data_book_view_object_info);
+}
+
+static void
+e_data_book_view_init (EDataBookView *book_view)
+{
+	EDataBookViewPrivate *priv = E_DATA_BOOK_VIEW_GET_PRIVATE (book_view);
+	book_view->priv = priv;
+
+	priv->running = FALSE;
+	priv->pending_mutex = g_mutex_new ();
+
+	priv->adds = g_array_sized_new (TRUE, TRUE, sizeof (gchar *), THRESHOLD);
+	priv->changes = g_array_sized_new (TRUE, TRUE, sizeof (gchar *), THRESHOLD);
+	priv->removes = g_array_sized_new (TRUE, TRUE, sizeof (gchar *), THRESHOLD);
+
+	priv->ids = g_hash_table_new_full (g_str_hash, g_str_equal,
+					   g_free, NULL);
+}
+
 static gboolean
 bookview_idle_start (gpointer data)
 {
 	EDataBookView *book_view = data;
+	EBookBackend *backend;
 
 	book_view->priv->running = TRUE;
 	book_view->priv->idle_id = 0;
 
-	e_book_backend_start_book_view (book_view->priv->backend, book_view);
+	backend = E_BOOK_BACKEND (e_data_view_get_backend (E_DATA_VIEW (book_view)));
+	e_book_backend_start_book_view (backend, book_view);
+
 	return FALSE;
 }
 
@@ -591,8 +642,10 @@ static gboolean
 bookview_idle_stop (gpointer data)
 {
 	EDataBookView *book_view = data;
+	EBookBackend *backend;
 
-	e_book_backend_stop_book_view (book_view->priv->backend, book_view);
+	backend = E_BOOK_BACKEND (e_data_view_get_backend (E_DATA_VIEW (book_view)));
+	e_book_backend_stop_book_view (backend, book_view);
 
 	book_view->priv->running = FALSE;
 	book_view->priv->idle_id = 0;
@@ -642,7 +695,7 @@ e_data_book_view_get_card_query (EDataBookView *book_view)
 {
 	g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (book_view), NULL);
 
-	return book_view->priv->card_query;
+	return book_view->priv->query;
 }
 
 /**
@@ -659,7 +712,7 @@ e_data_book_view_get_card_sexp (EDataBookView *book_view)
 {
 	g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (book_view), NULL);
 
-	return book_view->priv->card_sexp;
+	return E_BOOK_BACKEND_SEXP (e_data_view_get_sexp (E_DATA_VIEW (book_view)));
 }
 
 /**
@@ -692,7 +745,7 @@ e_data_book_view_get_backend (EDataBookView *book_view)
 {
 	g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (book_view), NULL);
 
-	return book_view->priv->backend;
+	return E_BOOK_BACKEND (e_data_view_get_backend (E_DATA_VIEW (book_view)));
 }
 
 /**
diff --git a/addressbook/libedata-book/e-data-book-view.h b/addressbook/libedata-book/e-data-book-view.h
index 160a443..c058656 100644
--- a/addressbook/libedata-book/e-data-book-view.h
+++ b/addressbook/libedata-book/e-data-book-view.h
@@ -43,12 +43,12 @@ G_BEGIN_DECLS
 typedef struct _EDataBookViewPrivate EDataBookViewPrivate;
 
 struct _EDataBookView {
-	GObject parent;
+	EDataView parent;
 	EDataBookViewPrivate *priv;
 };
 
 struct _EDataBookViewClass {
-	GObjectClass parent;
+	EDataViewClass parent;
 };
 
 EDataBookView *e_data_book_view_new                  (EDataBook        *book,
diff --git a/addressbook/libedata-book/e-data-book.c b/addressbook/libedata-book/e-data-book.c
index 7794e8b..5d00b4c 100644
--- a/addressbook/libedata-book/e-data-book.c
+++ b/addressbook/libedata-book/e-data-book.c
@@ -34,8 +34,6 @@
 #include "e-book-backend-sexp.h"
 #include "opid.h"
 
-DBusGConnection *connection;
-
 /* DBus glue */
 static void impl_AddressBook_Book_open(EDataBook *book, gboolean only_if_exists, DBusGMethodInvocation *context);
 static void impl_AddressBook_Book_remove(EDataBook *book, DBusGMethodInvocation *context);
@@ -55,7 +53,6 @@ static gboolean impl_AddressBook_Book_cancelOperation(EDataBook *book, GError **
 static void impl_AddressBook_Book_close(EDataBook *book, DBusGMethodInvocation *context);
 #include "e-data-book-glue.h"
 
-static void return_status_and_list (guint32 opid, EDataBookStatus status, GList *list, gboolean free_data);
 static void data_book_return_error (DBusGMethodInvocation *context, gint code, const gchar *error_str);
 
 enum {
@@ -185,59 +182,20 @@ e_data_book_error_quark (void)
 }
 
 /* Generate the GObject boilerplate */
-G_DEFINE_TYPE(EDataBook, e_data_book, G_TYPE_OBJECT)
+G_DEFINE_TYPE(EDataBook, e_data_book, E_TYPE_DATA)
 
 static void
-e_data_book_dispose (GObject *object)
+e_data_book_class_init (EDataBookClass *e_data_book_class)
 {
-	EDataBook *book = E_DATA_BOOK (object);
+	EDataClass *data_class = E_DATA_CLASS (e_data_book_class);
 
-	if (book->backend) {
-		g_object_unref (book->backend);
-		book->backend = NULL;
-	}
+	/* XXX: do some ugly casting to avoid breaking API */
+	data_class->get_backend = (EBackend* (*)(EData*)) e_data_book_get_backend;
+	data_class->get_source =  (ESource* (*)(EData*)) e_data_book_get_source;
 
-	if (book->source) {
-		g_object_unref (book->source);
-		book->source = NULL;
-	}
-
-	G_OBJECT_CLASS (e_data_book_parent_class)->dispose (object);
-}
-
-static void
-e_data_book_class_init (EDataBookClass *e_data_book_class)
-{
-	GObjectClass *object_class = G_OBJECT_CLASS (e_data_book_class);
-
-	object_class->dispose = e_data_book_dispose;
-
-	signals[WRITABLE] =
-		g_signal_new ("writable",
-			      G_OBJECT_CLASS_TYPE (e_data_book_class),
-			      G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
-			      0,
-			      NULL, NULL,
-			      g_cclosure_marshal_VOID__BOOLEAN,
-			      G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
-
-	signals[CONNECTION] =
-		g_signal_new ("connection",
-			      G_OBJECT_CLASS_TYPE (e_data_book_class),
-			      G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
-			      0,
-			      NULL, NULL,
-			      g_cclosure_marshal_VOID__BOOLEAN,
-			      G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
-
-	signals[AUTH_REQUIRED] =
-		g_signal_new ("auth-required",
-			      G_OBJECT_CLASS_TYPE (e_data_book_class),
-			      G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
-			      0,
-			      NULL, NULL,
-			      g_cclosure_marshal_VOID__VOID,
-			      G_TYPE_NONE, 0);
+	signals[WRITABLE] = g_signal_lookup ("writable", E_TYPE_DATA);
+	signals[CONNECTION] = g_signal_lookup ("connection", E_TYPE_DATA);
+	signals[AUTH_REQUIRED] = g_signal_lookup ("auth-required", E_TYPE_DATA);
 
 	dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (e_data_book_class), &dbus_glib_e_data_book_object_info);
 
@@ -259,9 +217,10 @@ e_data_book_new (EBookBackend *backend, ESource *source)
 {
 	EDataBook *book;
 
-	book = g_object_new (E_TYPE_DATA_BOOK, NULL);
-	book->backend = g_object_ref (backend);
-	book->source = g_object_ref (source);
+	book = g_object_new (E_TYPE_DATA_BOOK,
+			     "backend", backend,
+			     "source", source,
+			     NULL);
 
 	return book;
 }
@@ -269,17 +228,17 @@ e_data_book_new (EBookBackend *backend, ESource *source)
 ESource*
 e_data_book_get_source (EDataBook *book)
 {
-	g_return_val_if_fail (book != NULL, NULL);
+	g_return_val_if_fail (E_IS_DATA_BOOK (book), NULL);
 
-	return book->source;
+	return e_data_get_source (E_DATA (book));
 }
 
 EBookBackend*
 e_data_book_get_backend (EDataBook *book)
 {
-	g_return_val_if_fail (book != NULL, NULL);
+	g_return_val_if_fail (E_IS_DATA_BOOK (book), NULL);
 
-	return book->backend;
+	return E_BOOK_BACKEND (e_data_get_backend (E_DATA (book)));
 }
 
 static void
@@ -307,7 +266,11 @@ e_data_book_respond_open (EDataBook *book, guint opid, EDataBookStatus status)
 static void
 impl_AddressBook_Book_remove(EDataBook *book, DBusGMethodInvocation *context)
 {
-	e_book_backend_remove (book->backend, book, opid_store (context));
+	EBookBackend *backend;
+
+	backend = e_data_book_get_backend (book);
+
+	e_book_backend_remove (backend, book, opid_store (context));
 }
 
 void
@@ -364,6 +327,33 @@ impl_AddressBook_Book_getContactList (EDataBook *book, const gchar *query, DBusG
 	g_thread_pool_push (op_pool, op, NULL);
 }
 
+static void
+return_status_and_list (guint32 opid, EDataBookStatus status, GList *list, gboolean free_data)
+{
+	DBusGMethodInvocation *context = opid_fetch (opid);
+
+	if (status == E_DATA_BOOK_STATUS_SUCCESS) {
+		gchar **array;
+		GList *l;
+		gint i = 0;
+
+		array = g_new0 (gchar *, g_list_length (list) + 1);
+		for (l = list; l != NULL; l = l->next) {
+			array[i++] = l->data;
+		}
+
+		dbus_g_method_return (context, array);
+
+		if (free_data) {
+			g_strfreev (array);
+		} else {
+			g_free (array);
+		}
+	} else {
+		data_book_return_error (context, status, _("Cannot complete operation"));
+	}
+}
+
 void
 e_data_book_respond_get_contact_list (EDataBook *book, guint32 opid, EDataBookStatus status, GList *cards)
 {
@@ -577,6 +567,7 @@ impl_AddressBook_Book_getBookView (EDataBook *book, const gchar *search, const g
 
 	dbus_g_method_return (context, path);
 	g_free (path);
+	g_object_unref (card_sexp);
 }
 
 static void
@@ -649,6 +640,8 @@ impl_AddressBook_Book_close(EDataBook *book, DBusGMethodInvocation *context)
 	dbus_g_method_return (context);
 }
 
+/* XXX: this should instead be a (static) handler for a signal on EBookBackend
+ * that announces it is writable */
 void
 e_data_book_report_writable (EDataBook *book, gboolean writable)
 {
@@ -657,6 +650,8 @@ e_data_book_report_writable (EDataBook *book, gboolean writable)
 	g_signal_emit (book, signals[WRITABLE], 0, writable);
 }
 
+/* XXX: this should instead be a (static) handler for a signal on EBookBackend
+ * that announces it is connected */
 void
 e_data_book_report_connection_status (EDataBook *book, gboolean connected)
 {
@@ -668,34 +663,7 @@ e_data_book_report_connection_status (EDataBook *book, gboolean connected)
 void
 e_data_book_report_auth_required (EDataBook *book)
 {
-	g_return_if_fail (book != NULL);
-
-	g_signal_emit (book, signals[AUTH_REQUIRED], 0);
-}
-
-static void
-return_status_and_list (guint32 opid, EDataBookStatus status, GList *list, gboolean free_data)
-{
-	DBusGMethodInvocation *context = opid_fetch (opid);
-
-	if (status == E_DATA_BOOK_STATUS_SUCCESS) {
-		gchar **array;
-		GList *l;
-		gint i = 0;
-
-		array = g_new0 (gchar *, g_list_length (list) + 1);
-		for (l = list; l != NULL; l = l->next) {
-			array[i++] = l->data;
-		}
-
-		dbus_g_method_return (context, array);
+	g_return_if_fail (E_IS_DATA_BOOK (book));
 
-		if (free_data) {
-			g_strfreev (array);
-		} else {
-			g_free (array);
-		}
-	} else {
-		data_book_return_error (context, status, _("Cannot complete operation"));
-	}
+	e_data_notify_auth_required (E_DATA (book));
 }
diff --git a/addressbook/libedata-book/e-data-book.h b/addressbook/libedata-book/e-data-book.h
index 6b58a0d..522d208 100644
--- a/addressbook/libedata-book/e-data-book.h
+++ b/addressbook/libedata-book/e-data-book.h
@@ -26,6 +26,8 @@
 #include <glib-object.h>
 #include <dbus/dbus-glib.h>
 #include <libedataserver/e-source.h>
+#include <libebackend/e-data-types.h>
+#include <libebackend/e-data.h>
 #include "e-book-backend.h"
 #include "e-data-book-types.h"
 
@@ -39,15 +41,15 @@ G_BEGIN_DECLS
 #define E_DATA_BOOK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), E_TYPE_DATA_BOOK, EDataBookClass))
 
 struct _EDataBook {
-	GObject parent;
-	EBookBackend *backend;
-	ESource *source;
+	EData parent;
 };
 
 struct _EDataBookClass {
-	GObjectClass parent;
+	EDataClass parent;
 };
 
+GType                   e_data_book_get_type               (void);
+
 GQuark e_data_book_error_quark (void);
 #define E_DATA_BOOK_ERROR e_data_book_error_quark ()
 
@@ -109,8 +111,6 @@ void                    e_data_book_report_connection_status (EDataBook
 
 void                    e_data_book_report_auth_required     (EDataBook                       *book);
 
-GType                   e_data_book_get_type               (void);
-
 G_END_DECLS
 
 #endif /* ! __E_DATA_BOOK_H__ */
diff --git a/configure.ac b/configure.ac
index f7a0526..1f1de24 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1233,7 +1233,7 @@ EVO_SET_COMPILE_FLAGS(E_DATA_SERVER_UI, $E_DATA_SERVER_UI_DEPS, $THREADS_CFLAGS,
 AC_SUBST(E_DATA_SERVER_UI_CFLAGS)
 AC_SUBST(E_DATA_SERVER_UI_LIBS)
 
-E_BACKEND_DEPS="gobject-2.0 libxml-2.0 gmodule-2.0 gconf-2.0"
+E_BACKEND_DEPS="gobject-2.0 libxml-2.0 gmodule-2.0 gconf-2.0 dbus-glib-1"
 
 dnl ******************************
 dnl libebackend flags
diff --git a/libebackend/Makefile.am b/libebackend/Makefile.am
index 44296cc..bf9de40 100644
--- a/libebackend/Makefile.am
+++ b/libebackend/Makefile.am
@@ -10,6 +10,12 @@ libebackend_1_2_la_CPPFLAGS = \
 
 libebackend_1_2_la_SOURCES =		\
 	e-data-server-module.c		\
+	e-data.c			\
+	e-data-view.c			\
+	e-backend.c			\
+	e-backend-factory.c		\
+	e-backend-sexp.c		\
+	e-data-factory.c		\
 	e-offline-listener.c		\
 	e-dbhash.c			\
 	e-db3-utils.c			\
@@ -21,12 +27,22 @@ libebackend_1_2_la_LIBADD = 				\
 	$(DB_LIBS)
 
 libebackend_1_2_la_LDFLAGS = \
-	-version-info $(LIBEBACKEND_CURRENT):$(LIBEBACKEND_REVISION):$(LIBEBACKEND_AGE) $(NO_UNDEFINED)
+	-version-info $(LIBEBACKEND_CURRENT):$(LIBEBACKEND_REVISION):$(LIBEBACKEND_AGE) $(NO_UNDEFINED) \
+	$(NULL)
 
 libebackendincludedir = $(privincludedir)/libebackend
 
+# FIXME: don't install these new generic headers, if possible
+
 libebackendinclude_HEADERS =		\
 	e-data-server-module.h		\
+	e-data-types.h			\
+	e-data.h			\
+	e-data-view.h			\
+	e-backend.h			\
+	e-backend-factory.h		\
+	e-backend-sexp.h		\
+	e-data-factory.h		\
 	e-offline-listener.h		\
 	e-db3-utils.h			\
 	e-dbhash.h			\
diff --git a/libebackend/e-backend-factory.c b/libebackend/e-backend-factory.c
new file mode 100644
index 0000000..004ba70
--- /dev/null
+++ b/libebackend/e-backend-factory.c
@@ -0,0 +1,75 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2009 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Authors:
+ *   Chris Toshok <toshok ximian com>
+ *   Travis Reitter <travis reitter collabora co uk>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include "e-backend-factory.h"
+
+G_DEFINE_ABSTRACT_TYPE (EBackendFactory, e_backend_factory, G_TYPE_OBJECT);
+
+static void
+e_backend_factory_init (EBackendFactory *factory)
+{
+}
+
+static void
+e_backend_factory_class_init (EBackendFactoryClass *klass)
+{
+}
+
+/**
+ * e_backend_factory_get_protocol:
+ * @factory: an #EBackendFactory
+ *
+ * Gets the protocol that @factory creates backends for.
+ *
+ * Return value: A string representing a protocol.
+ **/
+const gchar *
+e_backend_factory_get_protocol (EBackendFactory *factory)
+{
+	g_return_val_if_fail (E_IS_BACKEND_FACTORY (factory), NULL);
+
+	return E_BACKEND_FACTORY_GET_CLASS (factory)->get_protocol (factory);
+}
+
+/**
+ * e_backend_factory_new_backend:
+ * @factory: an #EBackendFactory
+ *
+ * Creates a new #EBackend with @factory's protocol.
+ *
+ * Return value: A new #EBackend.
+ **/
+EBackend*
+e_backend_factory_new_backend (EBackendFactory *factory)
+{
+	g_return_val_if_fail (E_IS_BACKEND_FACTORY (factory), NULL);
+
+	return E_BACKEND_FACTORY_GET_CLASS (factory)->new_backend (factory);
+}
diff --git a/libebackend/e-backend-factory.h b/libebackend/e-backend-factory.h
new file mode 100644
index 0000000..2bc05ed
--- /dev/null
+++ b/libebackend/e-backend-factory.h
@@ -0,0 +1,60 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2009 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Authors:
+ *   Chris Toshok <toshok ximian com>
+ *   Travis Reitter <travis reitter collabora co uk>
+ */
+
+#ifndef _E_BACKEND_FACTORY_H_
+#define _E_BACKEND_FACTORY_H_
+
+#include <glib-object.h>
+#include "e-backend.h"
+
+G_BEGIN_DECLS
+
+#define E_TYPE_BACKEND_FACTORY        (e_backend_factory_get_type ())
+#define E_BACKEND_FACTORY(o)          (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_BACKEND_FACTORY, EBackendFactory))
+#define E_BACKEND_FACTORY_CLASS(k)    (G_TYPE_CHECK_CLASS_CAST((k), E_TYPE_BACKEND_FACTORY, EBackendFactoryClass))
+#define E_IS_BACKEND_FACTORY(o)       (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_BACKEND_FACTORY))
+#define E_IS_BACKEND_FACTORY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_BACKEND_FACTORY))
+#define E_BACKEND_FACTORY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), E_TYPE_BACKEND_FACTORY, EBackendFactoryClass))
+
+typedef struct _EBackendFactoryPrivate EBackendFactoryPrivate;
+
+typedef struct {
+	GObject            parent_object;
+} EBackendFactory;
+
+typedef struct {
+	GObjectClass parent_class;
+
+	const gchar*	(*get_protocol)	(EBackendFactory *factory);
+	EBackend*	(*new_backend)	(EBackendFactory *factory);
+} EBackendFactoryClass;
+
+GType		e_backend_factory_get_type	(void);
+
+const gchar*	e_backend_factory_get_protocol	(EBackendFactory *factory);
+EBackend*	e_backend_factory_new_backend	(EBackendFactory *factory);
+
+G_END_DECLS
+
+#endif /* _E_BACKEND_FACTORY_H_ */
diff --git a/libebackend/e-backend-sexp.c b/libebackend/e-backend-sexp.c
new file mode 100644
index 0000000..6da3b57
--- /dev/null
+++ b/libebackend/e-backend-sexp.c
@@ -0,0 +1,67 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2009-2010 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License, version 2, as published by the Free Software Foundation.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * Authors:
+ *   Chris Lahey <clahey ximian com>
+ *   Travis Reitter <travis reitter collabora co uk>
+ */
+
+#include <string.h>
+#include "libedataserver/e-sexp.h"
+#include "libedataserver/e-data-server-util.h"
+#include "e-backend-sexp.h"
+
+G_DEFINE_ABSTRACT_TYPE (EBackendSExp, e_backend_sexp, G_TYPE_OBJECT);
+
+struct _EBackendSExpPrivate {
+};
+
+/* FIXME: this class is currently just used for superficial type-safety;
+ * actually pull in what shallow commonality there is between EBookBackendSExp
+ * and ECalBackendSExp */
+
+/**
+ * e_backend_sexp_new:
+ * @text: an s-expression to parse
+ *
+ * Creates a new #EBackendSExp from @text.
+ *
+ * Return value: A new #EBackendSExp.
+ **/
+EBackendSExp *
+e_backend_sexp_new (const gchar *text)
+{
+	EBackendSExp *sexp = g_object_new (E_TYPE_BACKEND_SEXP, NULL);
+
+	return sexp;
+}
+
+static void
+e_backend_sexp_class_init (EBackendSExpClass *klass)
+{
+}
+
+static void
+e_backend_sexp_init (EBackendSExp *sexp)
+{
+	EBackendSExpPrivate *priv;
+
+	priv = g_new0 (EBackendSExpPrivate, 1);
+	sexp->priv = priv;
+}
diff --git a/libebackend/e-backend-sexp.h b/libebackend/e-backend-sexp.h
new file mode 100644
index 0000000..2fc07f5
--- /dev/null
+++ b/libebackend/e-backend-sexp.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2009-2010 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License, version 2, as published by the Free Software Foundation.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * Authors:
+ *   Chris Lahey <clahey ximian com>
+ *   Travis Reitter <travis reitter collabora co uk>
+ */
+
+#ifndef __E_BACKEND_SEXP_H__
+#define __E_BACKEND_SEXP_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "e-data-types.h"
+
+G_BEGIN_DECLS
+
+#define E_TYPE_BACKEND_SEXP        (e_backend_sexp_get_type ())
+#define E_BACKEND_SEXP(o)          (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_BACKEND_SEXP, EBackendSExp))
+#define E_BACKEND_SEXP_CLASS(k)    (G_TYPE_CHECK_CLASS_CAST((k), E_BACKEND_TYPE, EBackendSExpClass))
+#define E_IS_BACKEND_SEXP(o)       (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_BACKEND_SEXP))
+#define E_IS_BACKEND_SEXP_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_BACKEND_SEXP))
+#define E_BACKEND_SEXP_GET_CLASS(k) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_BACKEND_SEXP, EBackendSExpClass))
+
+typedef struct _EBackendSExpPrivate EBackendSExpPrivate;
+
+struct _EBackendSExp {
+	GObject parent_object;
+	EBackendSExpPrivate *priv;
+};
+
+struct _EBackendSExpClass {
+	GObjectClass parent_class;
+};
+
+EBackendSExp*	e_backend_sexp_new	(const gchar *text);
+GType		e_backend_sexp_get_type	(void);
+
+G_END_DECLS
+
+#endif /* __E_BACKEND_SEXP_H__ */
diff --git a/libebackend/e-backend.c b/libebackend/e-backend.c
new file mode 100644
index 0000000..0eb50bc
--- /dev/null
+++ b/libebackend/e-backend.c
@@ -0,0 +1,474 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2009 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Authors:
+ *   Nat Friedman <nat ximian com>
+ *   Travis Reitter <travis reitter collabora co uk>
+ */
+
+#include <config.h>
+
+#include "e-data-view.h"
+#include "e-data.h"
+#include "e-data-types.h"
+#include "e-backend.h"
+
+struct _EBackendPrivate {
+	GMutex *open_mutex;
+
+	GMutex *clients_mutex;
+	GList *clients;
+
+	ESource *source;
+
+	GMutex *views_mutex;
+	EList *views;
+};
+
+/* Signal IDs */
+enum {
+	LAST_CLIENT_GONE,
+	LAST_SIGNAL
+};
+
+static guint e_backend_signals[LAST_SIGNAL];
+
+static GObjectClass *parent_class;
+
+G_DEFINE_ABSTRACT_TYPE (EBackend, e_backend, G_TYPE_OBJECT);
+
+/**
+ * e_backend_get_source:
+ * @backend: An #EBackend.
+ *
+ * Queries the source that @backend is serving.
+ *
+ * Return value: #ESource for the backend.
+ **/
+ESource *
+e_backend_get_source (EBackend *backend)
+{
+	g_return_val_if_fail (E_IS_BACKEND (backend), NULL);
+
+	return backend->priv->source;
+}
+
+/**
+ * e_backend_set_source:
+ * @backend: An #EBackend.
+ * @source: The #ESource.
+ *
+ * Sets the source that @backend is serving.
+ *
+ * Return value: #ESource for the backend.
+ **/
+void
+e_backend_set_source (EBackend *backend,
+		      ESource  *source)
+{
+	g_return_if_fail (E_IS_BACKEND (backend));
+	g_return_if_fail (E_IS_SOURCE (source));
+
+	if (backend->priv->source)
+		g_object_unref (backend->priv->source);
+
+	backend->priv->source = g_object_ref (backend);
+}
+
+/**
+ * e_book_backend_stop_view:
+ * @backend: an #EBackend
+ * @view: the #EDataView to stop
+ *
+ * Stops running the query specified by @view, emitting
+ * no more signals.
+ **/
+void
+e_backend_stop_view (EBackend  *backend,
+		     EDataView *view)
+{
+	EBackendClass *klass;
+
+	g_return_if_fail (E_IS_BACKEND (backend));
+
+	klass = E_BACKEND_GET_CLASS (backend);
+
+	g_assert (klass->stop_view);
+
+	return klass->stop_view (backend, view);
+}
+
+/**
+ * e_backend_remove:
+ * @backend: an #EBackend
+ * @data: an #EData
+ * @opid: the ID to use for this operation
+ *
+ * Executes a 'remove' request to remove all of @backend's data,
+ * specified by @opid on @data.
+ **/
+void
+e_backend_remove (EBackend *backend,
+		  EData    *data,
+		  guint32   opid)
+{
+	EBackendClass *klass;
+
+	g_return_if_fail (E_IS_BACKEND (backend));
+	g_return_if_fail (E_IS_DATA (data));
+
+	klass = E_BACKEND_GET_CLASS (data);
+
+	g_assert (klass->remove);
+
+	klass->remove (backend, data, opid);
+}
+
+/**
+ * e_backend_get_changes:
+ * @backend: an #EBackend
+ * @data: an #EData
+ * @opid: the ID to use for this operation
+ * @change_id: the ID of the changeset
+ *
+ * Executes a 'get changes' request specified by @opid on @data
+ * using @backend.
+ **/
+void
+e_backend_get_changes (EBackend    *backend,
+		       EData       *data,
+		       guint32      opid,
+		       const gchar *change_id)
+{
+	g_return_if_fail (E_IS_BACKEND (backend));
+	g_return_if_fail (E_IS_DATA (data));
+	g_return_if_fail (change_id);
+
+	g_assert (E_BACKEND_GET_CLASS (backend)->get_changes);
+
+	(* E_BACKEND_GET_CLASS (backend)->get_changes) (backend, data, opid, change_id);
+}
+
+static void
+last_client_gone (EBackend *backend)
+{
+	g_signal_emit (backend, e_backend_signals[LAST_CLIENT_GONE], 0);
+}
+
+/**
+ * e_backend_get_views:
+ * @backend: an #EBackend
+ *
+ * Gets the list of #EDataView views running on this backend.
+ *
+ * Return value: An #EList of #EDataView objects.
+ **/
+EList*
+e_backend_get_views (EBackend *backend)
+{
+        g_return_val_if_fail (E_IS_BACKEND (backend), NULL);
+
+        return g_object_ref (backend->priv->views);
+}
+
+/**
+ * e_backend_add_view:
+ * @backend: an #EBackend
+ * @view: an #EDataView
+ *
+ * Adds @view to @backend for querying.
+ **/
+void
+e_backend_add_view (EBackend  *backend,
+		    EDataView *view)
+{
+	g_return_if_fail (E_IS_BACKEND (backend));
+
+	g_mutex_lock (backend->priv->views_mutex);
+
+	e_list_append (backend->priv->views, view);
+
+	g_mutex_unlock (backend->priv->views_mutex);
+}
+
+/**
+ * e_backend_remove_view:
+ * @backend: an #EBackend
+ * @view: an #EDataView
+ *
+ * Removes @view from @backend.
+ **/
+void
+e_backend_remove_view (EBackend  *backend,
+		       EDataView *view)
+{
+	g_return_if_fail (E_IS_BACKEND (backend));
+
+	g_mutex_lock (backend->priv->views_mutex);
+
+	e_list_remove (backend->priv->views, view);
+
+	g_mutex_unlock (backend->priv->views_mutex);
+}
+
+/**
+ * e_backend_add_client:
+ * @backend: An addressbook backend.
+ * @data: the corba object representing the client connection.
+ *
+ * Adds a client to an addressbook backend.
+ *
+ * Return value: TRUE on success, FALSE on failure to add the client.
+ */
+gboolean
+e_backend_add_client (EBackend *backend,
+		      EData    *data)
+{
+	g_return_val_if_fail (E_IS_BACKEND (backend), FALSE);
+	g_return_val_if_fail (E_IS_DATA (data), FALSE);
+
+	g_mutex_lock (backend->priv->clients_mutex);
+	backend->priv->clients = g_list_prepend (backend->priv->clients, data);
+	g_mutex_unlock (backend->priv->clients_mutex);
+
+	return TRUE;
+}
+
+/**
+ * e_backend_remove_client:
+ * @backend: an #EBackend
+ * @data: an #EData to remove
+ *
+ * Removes @data from the list of @backend's clients.
+ **/
+void
+e_backend_remove_client (EBackend *backend,
+			 EData    *data)
+{
+	g_return_if_fail (E_IS_BACKEND (backend));
+	g_return_if_fail (E_IS_DATA (data));
+
+	/* up our backend's refcount here so that last_client_gone
+	   doesn't end up unreffing us (while we're holding the
+	   lock) */
+	g_object_ref (backend);
+
+	/* Disconnect */
+	g_mutex_lock (backend->priv->clients_mutex);
+	backend->priv->clients = g_list_remove (backend->priv->clients, data);
+
+	/* When all clients go away, notify the parent factory about it so that
+	 * it may decide whether to kill the backend or not.
+	 */
+	if (!backend->priv->clients)
+		last_client_gone (backend);
+
+	g_mutex_unlock (backend->priv->clients_mutex);
+
+	g_object_unref (backend);
+}
+
+/**
+ * e_backend_get_clients:
+ * @backend: an #EBackend
+ *
+ * Returns a #GList of #EData clients. This list and its members are owned by
+ * @backend. Be sure to also lock and unlock the mutex from
+ * @e_backend_get_clients_mutex() as appropriately when using this list of
+ * clients.
+ **/
+GList*
+e_backend_get_clients (EBackend *backend)
+{
+	g_return_val_if_fail (E_IS_BACKEND (backend), NULL);
+
+	return backend->priv->clients;
+}
+
+/**
+ * e_backend_get_clients_mutex:
+ * @backend: an #EBackend
+ *
+ * Returns the #GMutex used to regulate access of the clients list and the
+ * clients themselves. The mutex is owned by @backend.
+ **/
+GMutex*
+e_backend_get_clients_mutex (EBackend *backend)
+{
+	g_return_val_if_fail (E_IS_BACKEND (backend), NULL);
+
+	return backend->priv->clients_mutex;
+}
+
+/**
+ * e_backend_get_static_capabilities:
+ * @backend: an #EBackend
+ *
+ * Gets the capabilities offered by this @backend.
+ *
+ * Return value: A string listing the capabilities.
+ **/
+gchar *
+e_backend_get_static_capabilities (EBackend *backend)
+{
+	EBackendClass *klass;
+
+	g_return_val_if_fail (E_IS_BACKEND (backend), NULL);
+
+	klass = E_BACKEND_GET_CLASS (backend);
+
+	g_assert (klass->get_static_capabilities);
+
+	return klass->get_static_capabilities (backend);
+}
+
+/**
+ * e_backend_is_loaded:
+ * @backend: an #EBackend
+ *
+ * Checks if @backend's storage has been opened and the backend
+ * itself is ready for accessing.
+ *
+ * Return value: %TRUE if loaded, %FALSE otherwise.
+ **/
+gboolean
+e_backend_is_loaded (EBackend *backend)
+{
+	EBackendClass *klass;
+
+	g_return_val_if_fail (E_IS_BACKEND (backend), FALSE);
+
+	klass = E_BACKEND_GET_CLASS (backend);
+
+	g_assert (klass->is_loaded);
+
+	return klass->is_loaded (backend);
+}
+
+/**
+ * e_backend_set_mode:
+ * @backend: an #EBackend
+ * @mode: a mode indicating the online/offline status of the backend
+ *
+ * Sets @backend's online/offline mode to @mode. Mode can be 1 for offline
+ * or 2 indicating that it is connected and online.
+ **/
+void
+e_backend_set_mode (EBackend  *backend,
+		    EDataMode  mode)
+{
+	EBackendClass *klass;
+
+	g_return_if_fail (E_IS_BACKEND (backend));
+
+	klass = E_BACKEND_GET_CLASS (backend);
+
+	g_assert (klass->set_mode);
+
+	klass->set_mode (backend, mode);
+}
+
+/**
+ * e_backend_notify_auth_required:
+ * @backend: an #EBackend
+ *
+ * Notifies clients that @backend requires authentication in order to
+ * connect. Means to be used by backend implementations.
+ **/
+void
+e_backend_notify_auth_required (EBackend *backend)
+{
+	EBackendPrivate *priv;
+	GList *clients;
+
+	priv = backend->priv;
+	g_mutex_lock (priv->clients_mutex);
+
+	for (clients = priv->clients; clients != NULL; clients = g_list_next (clients))
+		e_data_notify_auth_required (E_DATA (clients->data));
+	g_mutex_unlock (priv->clients_mutex);
+}
+
+static void
+e_backend_init (EBackend *backend)
+{
+	EBackendPrivate *priv;
+
+	priv          = g_new0 (EBackendPrivate, 1);
+	priv->clients = NULL;
+	priv->source = NULL;
+	priv->views   = e_list_new((EListCopyFunc) NULL, (EListFreeFunc) NULL, NULL);
+	priv->open_mutex = g_mutex_new ();
+	priv->clients_mutex = g_mutex_new ();
+	priv->views_mutex = g_mutex_new ();
+
+	backend->priv = priv;
+}
+
+static void
+e_backend_dispose (GObject *object)
+{
+	EBackend *backend;
+
+	backend = E_BACKEND (object);
+
+	if (backend->priv) {
+		g_list_free (backend->priv->clients);
+
+		if (backend->priv->views) {
+			g_object_unref (backend->priv->views);
+			backend->priv->views = NULL;
+		}
+
+		if (backend->priv->source) {
+			g_object_unref (backend->priv->source);
+			backend->priv->source = NULL;
+		}
+
+		g_mutex_free (backend->priv->open_mutex);
+		g_mutex_free (backend->priv->clients_mutex);
+		g_mutex_free (backend->priv->views_mutex);
+
+		g_free (backend->priv);
+		backend->priv = NULL;
+	}
+
+	G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+e_backend_class_init (EBackendClass *klass)
+{
+	GObjectClass *object_class;
+
+	parent_class = g_type_class_peek_parent (klass);
+
+	object_class = (GObjectClass *) klass;
+
+	object_class->dispose = e_backend_dispose;
+
+	e_backend_signals[LAST_CLIENT_GONE] =
+		g_signal_new ("last_client_gone",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_FIRST,
+			      G_STRUCT_OFFSET (EBackendClass, last_client_gone),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE, 0);
+}
diff --git a/libebackend/e-backend.h b/libebackend/e-backend.h
new file mode 100644
index 0000000..f50942b
--- /dev/null
+++ b/libebackend/e-backend.h
@@ -0,0 +1,158 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2009 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * 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 Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ * Authors:
+ *   Nat Friedman <nat ximian com>
+ *   Travis Reitter <travis reitter collabora co uk>
+ */
+
+#ifndef __E_BACKEND_H__
+#define __E_BACKEND_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <libedataserver/e-list.h>
+#include <libedataserver/e-source.h>
+
+#include "e-data-view.h"
+#include "e-data-types.h"
+#include "e-data.h"
+
+G_BEGIN_DECLS
+
+#define E_TYPE_BACKEND         (e_backend_get_type ())
+#define E_BACKEND(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_BACKEND, EBackend))
+#define E_BACKEND_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), E_TYPE_BACKEND, EBackendClass))
+#define E_IS_BACKEND(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_BACKEND))
+#define E_IS_BACKEND_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_BACKEND))
+#define E_BACKEND_GET_CLASS(k) (G_TYPE_INSTANCE_GET_CLASS ((k), E_TYPE_BACKEND, EBackendClass))
+
+typedef struct _EBackendPrivate EBackendPrivate;
+
+struct _EBackend {
+	GObject parent_object;
+	EBackendPrivate *priv;
+};
+
+struct _EBackendClass {
+	GObjectClass parent_class;
+
+/* XXX: eCal equiv is start_query */
+	/* FIXME: this could be genericized
+	void (*start_view) (EBackend *backend,
+			EDataView *view);
+			*/
+	void		(*stop_view)			(EBackend  *backend,
+							 EDataView *view);
+
+	void		(*remove)			(EBackend  *backend,
+							 EData     *data,
+							 guint32    opid);
+
+        gchar *		(*get_static_capabilities)	(EBackend  *backend);
+
+	void		(*set_mode)			(EBackend  *backend,
+							 EDataMode  mode);
+
+	gboolean	(*add_client)			(EBackend  *backend,
+							 EData     *data);
+
+	void		(*remove_client)		(EBackend  *backend,
+							 EData     *data);
+
+	gboolean	(*is_loaded)			(EBackend  *backend);
+
+	void		(*get_changes)			(EBackend    *backend,
+							 EData       *data,
+							 guint32      opid,
+							 const gchar *change_id);
+
+	/* Notification signals */
+	void (* last_client_gone) (EBackend *backend);
+
+	/* Padding for future expansion */
+	void (*_pas_reserved1) (void);
+	void (*_pas_reserved2) (void);
+	void (*_pas_reserved3) (void);
+	void (*_pas_reserved4) (void);
+};
+
+GType		e_backend_get_type		(void);
+
+ESource*	e_backend_get_source		(EBackend *backend);
+
+void		e_backend_set_source		(EBackend *backend,
+						 ESource  *source);
+
+/* XXX: ecal equiv: add_query */
+void		e_backend_add_view		(EBackend           *backend,
+						 EDataView          *view);
+/* XXX: ecal equiv: remove_query */
+void		e_backend_remove_view		(EBackend           *backend,
+						 EDataView          *view);
+
+EList*		e_backend_get_views		(EBackend           *backend);
+
+void		e_backend_notify_auth_required	(EBackend           *backend);
+
+
+void		e_backend_remove			(EBackend  *backend,
+							 EData     *data,
+							 guint32    opid);
+
+gchar*		e_backend_get_static_capabilities	(EBackend  *backend);
+
+void		e_backend_set_mode			(EBackend  *backend,
+							 EDataMode  mode);
+
+gboolean	e_backend_add_client			(EBackend  *backend,
+							 EData     *data);
+
+void		e_backend_remove_client			(EBackend  *backend,
+							 EData     *data);
+
+GList*		e_backend_get_clients			(EBackend  *backend);
+
+GMutex*		e_backend_get_clients_mutex		(EBackend  *backend);
+
+gboolean	e_backend_is_loaded			(EBackend  *backend);
+
+void		e_backend_get_changes			(EBackend    *backend,
+							 EData       *data,
+							 guint32      opid,
+							 const gchar *change_id);
+
+void		e_backend_notify_writable		(EBackend *backend, gboolean is_writable);
+
+void		e_backend_notify_connection_status	(EBackend *backend, gboolean is_online);
+
+void		e_backend_stop_view			(EBackend  *backend,
+							 EDataView *view);
+
+/* FIXME: these could be genericized a bit */
+#if 0
+/* XXX: the ECal equivalent is "start_query" */
+void        e_backend_start_data_view            (EBackend           *backend,
+						       EDataView          *view);
+#endif
+
+G_END_DECLS
+
+#endif /* ! __E_BACKEND_H__ */
+
diff --git a/libebackend/e-data-factory.c b/libebackend/e-data-factory.c
new file mode 100644
index 0000000..9288b6d
--- /dev/null
+++ b/libebackend/e-data-factory.c
@@ -0,0 +1,505 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2006 OpenedHand Ltd
+ * Copyright (C) 2009 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of version 2.1 of the GNU Lesser General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This library 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 Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ *   Ross Burton <ross linux intel com>
+ *   Travis Reitter <travis reitter collabora co uk>
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <glib-object.h>
+#include <glib/gi18n.h>
+#include <dbus/dbus-protocol.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+#include <dbus/dbus-glib-bindings.h>
+#include "e-data-server-module.h"
+#include "e-offline-listener.h"
+#include "e-backend-factory.h"
+#include "e-data-factory.h"
+#include "e-data.h"
+#include "e-backend.h"
+
+#define d(x)
+
+static GMainLoop *loop;
+DBusGConnection *connection;
+
+/* Convenience macro to test and set a GError/return on failure */
+#define g_set_error_val_if_fail(test, returnval, error, domain, code) G_STMT_START{ \
+		if G_LIKELY (test) {} else {				\
+			g_set_error (error, domain, code, #test);	\
+			g_warning(#test " failed");			\
+			return (returnval);				\
+		}							\
+	}G_STMT_END
+
+G_DEFINE_ABSTRACT_TYPE (EDataFactory, e_data_factory, G_TYPE_OBJECT);
+
+#define E_DATA_FACTORY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), E_TYPE_DATA_FACTORY, EDataFactoryPrivate))
+
+struct _EDataFactoryPrivate {
+	/* TODO: as the factory is not threaded these locks could be removed */
+	GMutex *backends_lock;
+	GHashTable *backends;
+	GHashTable *backend_factories;
+
+	GMutex *books_lock;
+	/* A hash of object paths for data URIs to EDatas */
+	GHashTable *books;
+
+	GMutex *connections_lock;
+	/* This is a hash of client addresses to GList* of EDatas */
+	GHashTable *connections;
+
+	guint exit_timeout;
+
+        gint mode;
+};
+
+/* Create the EDataFactory error quark */
+GQuark
+e_data_factory_error_quark (void)
+{
+	static GQuark quark = 0;
+	if (!quark)
+		quark = g_quark_from_static_string ("e_data_factory_error");
+	return quark;
+}
+
+/**
+ * register_backend_factory:
+ * @data_factory: an #EDataFactory
+ * @backend_factory: an #EBackendFactory
+ *
+ * Registers @backend_factory with @data_factory.
+ **/
+static void
+register_backend_factory (EDataFactory    *data_factory,
+				 EBackendFactory *backend_factory)
+{
+	const gchar *proto;
+
+	g_return_if_fail (E_IS_DATA_FACTORY (data_factory));
+	g_return_if_fail (E_IS_BACKEND_FACTORY (backend_factory));
+
+	proto = E_BACKEND_FACTORY_GET_CLASS (backend_factory)->get_protocol (backend_factory);
+
+	if (g_hash_table_lookup (data_factory->priv->backend_factories, proto) != NULL) {
+		g_warning (G_STRLOC ": Proto \"%s\" already registered!\n", proto);
+	}
+
+	g_hash_table_insert (data_factory->priv->backend_factories,
+			     g_strdup (proto), backend_factory);
+}
+
+/**
+ * register_backend_factories:
+ * @data_factory: an #EDataFactory
+ *
+ * Register the backends supported by the Evolution Data Server,
+ * with @data_factory.
+ **/
+static void
+register_backend_factories (EDataFactory *data_factory,
+				  GType         backend_type)
+{
+	GList *factories, *f;
+
+	factories = e_data_server_get_extensions_for_type (backend_type);
+
+	for (f = factories; f; f = f->next) {
+		EBackendFactory *backend_factory = f->data;
+
+		register_backend_factory (data_factory, g_object_ref (backend_factory));
+	}
+
+	e_data_server_extension_list_free (factories);
+	e_data_server_module_remove_unused ();
+}
+
+static void
+set_backend_online_status (gpointer key, gpointer value, gpointer data)
+{
+	GList *books;
+	EBackend *backend = NULL;
+
+	for (books = (GList *) value; books; books = g_list_next (books)) {
+		backend =  E_BACKEND (books->data);
+		e_backend_set_mode (backend,  GPOINTER_TO_INT (data));
+	}
+}
+
+/**
+ * e_data_factory_set_backend_mode:
+ * @data_factory: A bookendar data_factory.
+ * @mode: Online mode to set.
+ *
+ * Sets the online mode for all backends created by the given data_factory.
+ */
+void
+e_data_factory_set_backend_mode (EDataFactory *data_factory, gint mode)
+{
+	EDataFactoryPrivate *priv = data_factory->priv;
+
+	priv->mode = mode;
+	g_mutex_lock (priv->connections_lock);
+	g_hash_table_foreach (priv->connections, set_backend_online_status, GINT_TO_POINTER (priv->mode));
+	g_mutex_unlock (priv->connections_lock);
+}
+
+static void
+e_data_factory_class_init (EDataFactoryClass *e_data_factory_class)
+{
+	g_type_class_add_private (e_data_factory_class, sizeof (EDataFactoryPrivate));
+}
+
+/* Instance init */
+static void
+e_data_factory_init (EDataFactory *data_factory)
+{
+	data_factory->priv = E_DATA_FACTORY_GET_PRIVATE (data_factory);
+
+	data_factory->priv->backends_lock = g_mutex_new ();
+	data_factory->priv->backends = g_hash_table_new (g_str_hash, g_str_equal);
+	data_factory->priv->backend_factories = g_hash_table_new (g_str_hash, g_str_equal);
+
+	data_factory->priv->books_lock = g_mutex_new ();
+	data_factory->priv->books = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+	data_factory->priv->connections_lock = g_mutex_new ();
+	data_factory->priv->connections = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+	e_data_server_module_init ();
+}
+
+/* FIXME: write dispose to kill all the hashes and locks in priv */
+
+static gchar *
+e_data_factory_extract_proto_from_uri (const gchar *uri)
+{
+	gchar *proto, *p;
+	p = strchr (uri, ':');
+	if (p == NULL)
+		return NULL;
+	proto = g_malloc0 (p - uri + 1);
+	strncpy (proto, uri, p - uri);
+	return proto;
+}
+
+static EBackendFactory*
+e_data_factory_lookup_backend_factory (EDataFactory *data_factory,
+				       const gchar  *uri)
+{
+	EBackendFactory *backend_factory;
+	char *proto;
+
+	g_return_val_if_fail (E_IS_DATA_FACTORY (data_factory), NULL);
+	g_return_val_if_fail (uri != NULL, NULL);
+
+	proto = e_data_factory_extract_proto_from_uri (uri);
+	if (proto == NULL) {
+		g_warning ("Cannot extract protocol from URI %s", uri);
+		return NULL;
+	}
+
+	backend_factory = g_hash_table_lookup (data_factory->priv->backend_factories, proto);
+
+	g_free (proto);
+
+	return backend_factory;
+}
+
+static gchar *
+construct_factory_path (EDataFactory *data_factory)
+{
+	static volatile gint counter = 1;
+        EDataFactoryClass *klass;
+
+        klass = E_DATA_FACTORY_GET_CLASS (data_factory);
+
+        g_assert (klass->get_dbus_name_format);
+
+	return g_strdup_printf (
+		klass->get_dbus_name_format (data_factory),
+		getpid (),
+		g_atomic_int_exchange_and_add (&counter, 1));
+}
+
+typedef struct {
+	gchar *path;
+	EDataFactory *factory;
+} DataWeakNotifyClosure;
+
+static void
+data_weak_notify_closure_free (DataWeakNotifyClosure *closure)
+{
+	g_free (closure->path);
+	g_object_unref (closure->factory);
+	g_free (closure);
+}
+
+static void
+my_remove (DataWeakNotifyClosure *closure, GObject *dead)
+{
+	EDataFactoryPrivate *priv = closure->factory->priv;
+	GHashTableIter iter;
+	gpointer hkey, hvalue;
+
+	d (g_debug ("%s (%p) is dead", closure->path, dead));
+
+	g_hash_table_remove (priv->books, closure->path);
+
+	g_hash_table_iter_init (&iter, priv->connections);
+	while (g_hash_table_iter_next (&iter, &hkey, &hvalue)) {
+		GList *books = hvalue;
+
+		if (g_list_find (books, dead)) {
+			books = g_list_remove (books, dead);
+			if (books) {
+				g_hash_table_insert (priv->connections, g_strdup (hkey), books);
+			} else {
+				g_hash_table_remove (priv->connections, hkey);
+			}
+
+			break;
+		}
+	}
+
+	data_weak_notify_closure_free (closure);
+
+	/* If there are no open books, start a timer to quit */
+	if (priv->exit_timeout == 0 && g_hash_table_size (priv->books) == 0) {
+		priv->exit_timeout = g_timeout_add (10000, (GSourceFunc)g_main_loop_quit, loop);
+	}
+}
+
+void
+e_data_factory_publish_data (EDataFactory *data_factory, const gchar *IN_source, DBusGMethodInvocation *context)
+{
+        EDataFactoryClass *klass;
+	EData *data;
+	EBackend *backend;
+	EDataFactoryPrivate *priv = data_factory->priv;
+	ESource *source;
+	gchar *uri, *path, *sender;
+	GList *list;
+	DataWeakNotifyClosure *closure;
+
+	klass = E_DATA_FACTORY_GET_CLASS (data_factory);
+
+	/* FIXME: the status types (eg, NO_SUCH_DATA) need to be translated to
+	 * something that makes sense for the class */
+	if (IN_source == NULL || IN_source[0] == '\0') {
+		dbus_g_method_return_error (context, g_error_new (E_DATA_ERROR, E_DATA_STATUS_NO_SUCH_DATA, _("Empty URI")));
+		return;
+	}
+
+	/* Remove a pending exit */
+	if (priv->exit_timeout) {
+		g_source_remove (priv->exit_timeout);
+		priv->exit_timeout = 0;
+	}
+
+	g_mutex_lock (priv->backends_lock);
+
+	source = e_source_new_from_standalone_xml (IN_source);
+	if (!source) {
+		g_mutex_unlock (priv->backends_lock);
+		dbus_g_method_return_error (context, g_error_new (E_DATA_ERROR, E_DATA_STATUS_NO_SUCH_DATA, _("Invalid source")));
+		return;
+	}
+
+	uri = e_source_get_uri (source);
+
+	g_mutex_lock (priv->books_lock);
+
+	backend = g_hash_table_lookup (priv->backends, uri);
+
+	if (!backend) {
+		EBackendFactory *backend_factory = e_data_factory_lookup_backend_factory (data_factory, uri);
+
+		if (backend_factory)
+			backend = e_backend_factory_new_backend (backend_factory);
+
+		if (backend) {
+			g_hash_table_insert (priv->backends,
+					g_strdup (uri), backend);
+
+			e_backend_set_mode (backend, priv->mode);
+		}
+	}
+
+	if (!backend) {
+		g_free (uri);
+		g_object_unref (source);
+
+		g_mutex_unlock (priv->books_lock);
+		g_mutex_unlock (priv->backends_lock);
+		dbus_g_method_return_error (context, g_error_new (E_DATA_ERROR, E_DATA_STATUS_NO_SUCH_DATA, _("Invalid source")));
+		return;
+	}
+
+	path = construct_factory_path (data_factory);
+
+	g_assert (klass->data_new);
+	data = klass->data_new (backend, source);
+
+	g_hash_table_insert (priv->books, g_strdup (path), data);
+	e_backend_add_client (backend, data);
+	dbus_g_connection_register_g_object (connection, path, G_OBJECT (data));
+
+	closure = g_new0 (DataWeakNotifyClosure, 1);
+	closure->path = g_strdup (path);
+	closure->factory = g_object_ref (data_factory);
+	g_object_weak_ref (G_OBJECT (data), (GWeakNotify)my_remove, closure);
+
+	/* Update the hash of open connections */
+	g_mutex_lock (priv->connections_lock);
+	sender = dbus_g_method_get_sender (context);
+	list = g_hash_table_lookup (priv->connections, sender);
+	list = g_list_prepend (list, data);
+	g_hash_table_insert (priv->connections, sender, list);
+	g_mutex_unlock (priv->connections_lock);
+
+	g_mutex_unlock (priv->books_lock);
+	g_mutex_unlock (priv->backends_lock);
+
+	g_object_unref (source);
+	g_free (uri);
+
+	dbus_g_method_return (context, path);
+}
+
+static void
+name_owner_changed (DBusGProxy *proxy,
+                    const gchar *name,
+                    const gchar *prev_owner,
+                    const gchar *new_owner,
+                    EDataFactory *data_factory)
+{
+	if (strcmp (new_owner, "") == 0 && strcmp (name, prev_owner) == 0) {
+		gchar *key;
+		GList *list = NULL;
+		g_mutex_lock (data_factory->priv->connections_lock);
+		while (g_hash_table_lookup_extended (data_factory->priv->connections, prev_owner, (gpointer)&key, (gpointer)&list)) {
+			/* this should trigger the data's weak ref notify
+			 * function, which will remove it from the list before
+			 * it's freed, and will remove the connection from
+			 * priv->connections once they're all gone */
+			g_object_unref (list->data);
+		}
+
+		g_mutex_unlock (data_factory->priv->connections_lock);
+	}
+}
+
+/* Convenience function to print an error and exit */
+G_GNUC_NORETURN static void
+die (const gchar *prefix, GError *error)
+{
+	g_error("%s: %s", prefix, error->message);
+	g_error_free (error);
+	exit(1);
+}
+
+static void
+offline_state_changed_cb (EOfflineListener *eol, EDataFactory *data_factory)
+{
+	EOfflineListenerState state = e_offline_listener_get_state (eol);
+
+	g_return_if_fail (state == EOL_STATE_ONLINE || state == EOL_STATE_OFFLINE);
+
+	e_data_factory_set_backend_mode (data_factory, state == EOL_STATE_ONLINE ? E_DATA_MODE_REMOTE : E_DATA_MODE_LOCAL);
+}
+
+gint
+e_data_factory_main (gint           argc,
+ 		     gchar        **argv,
+		     EDataFactory  *factory,
+		     GMainLoop     *loop_in,
+		     const char    *service_name,
+		     const char    *object_path)
+{
+	GError *error = NULL;
+	DBusGProxy *bus_proxy;
+	guint32 request_name_ret;
+	EOfflineListener *eol;
+        EDataFactoryClass *klass;
+
+	g_return_val_if_fail (E_IS_DATA_FACTORY (factory), -1);
+	g_return_val_if_fail (loop_in, -1);
+	g_return_val_if_fail (service_name && service_name[0], -1);
+	g_return_val_if_fail (object_path && object_path[0], -1);
+
+	dbus_g_thread_init ();
+
+	loop = loop_in;
+
+	/* Obtain a connection to the session bus */
+	connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+	if (connection == NULL)
+		die ("Failed to open connection to bus", error);
+
+	bus_proxy = dbus_g_proxy_new_for_name (connection,
+					       DBUS_SERVICE_DBUS,
+					       DBUS_PATH_DBUS,
+					       DBUS_INTERFACE_DBUS);
+
+	if (!org_freedesktop_DBus_request_name (bus_proxy, service_name,
+						0, &request_name_ret, &error))
+		die ("Failed to get name", error);
+
+	if (request_name_ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
+		g_error ("Got result code %u from requesting name", request_name_ret);
+		exit (1);
+	}
+
+	klass = E_DATA_FACTORY_GET_CLASS (factory);
+
+	g_assert (klass->get_backend_type);
+	register_backend_factories (factory, klass->get_backend_type());
+
+	dbus_g_connection_register_g_object (connection,
+					     object_path,
+					     G_OBJECT (factory));
+
+	dbus_g_proxy_add_signal (bus_proxy, "NameOwnerChanged",
+				 G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
+	dbus_g_proxy_connect_signal (bus_proxy, "NameOwnerChanged", G_CALLBACK (name_owner_changed), factory, NULL);
+
+	eol = e_offline_listener_new ();
+	offline_state_changed_cb (eol, factory);
+	g_signal_connect (eol, "changed", G_CALLBACK (offline_state_changed_cb), factory);
+
+	printf ("Server is up and running...\n");
+
+	g_main_loop_run (loop);
+
+	g_object_unref (eol);
+
+	dbus_g_connection_unref (connection);
+
+	printf ("Bye.\n");
+
+	return 0;
+}
diff --git a/libebackend/e-data-factory.h b/libebackend/e-data-factory.h
new file mode 100644
index 0000000..473d09d
--- /dev/null
+++ b/libebackend/e-data-factory.h
@@ -0,0 +1,86 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2006 OpenedHand Ltd
+ * Copyright (C) 2009 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of version 2.1 of the GNU Lesser General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This library 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 Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef __E_DATA_FACTORY_H__
+#define __E_DATA_FACTORY_H__
+
+#include <glib-object.h>
+
+#include "e-backend.h"
+#include "e-backend-factory.h"
+
+G_BEGIN_DECLS
+
+#define E_TYPE_DATA_FACTORY        (e_data_factory_get_type ())
+#define E_DATA_FACTORY(o)          (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_DATA_FACTORY, EDataFactory))
+#define E_DATA_FACTORY_CLASS(k)    (G_TYPE_CHECK_CLASS_CAST((k), E_TYPE_DATA_FACTORY, EDataFactoryClass))
+#define E_IS_DATA_FACTORY(o)       (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_DATA_FACTORY))
+#define E_IS_DATA_FACTORY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_DATA_FACTORY))
+#define E_DATA_FACTORY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), E_TYPE_DATA_FACTORY, EDataFactoryClass))
+
+typedef struct _EDataFactoryPrivate EDataFactoryPrivate;
+
+typedef struct {
+	GObject parent;
+	EDataFactoryPrivate *priv;
+} EDataFactory;
+
+typedef struct {
+	GObjectClass parent;
+
+	GType		(*get_backend_type)	(void);
+
+	/* The string format for the D-Bus unique name for the factory; the
+	 * format must include a %d (for process ID) and %u (for instance ID),
+	 * in that order */
+	const gchar*	(*get_dbus_name_format)	(EDataFactory *factory);
+	EData*		(*data_new)		(EBackend *backend,
+						 ESource  *source);
+	void		(*register_backends)	(EDataFactory *factory);
+	EBackend*	(*lookup_backend)	(EDataFactory *factory,
+						 const char   *uri);
+	EBackendFactory* (*lookup_backend_factory) (EDataFactory *factory,
+						    const char   *proto);
+	void		(*insert_backend)	(EDataFactory *factory,
+						 const char   *uri,
+						 EBackend     *backend);
+	void		(*insert_backend_factory) (EDataFactory    *factory,
+						   const char      *proto,
+						   EBackendFactory *backend_factory);
+} EDataFactoryClass;
+
+typedef enum {
+	E_DATA_FACTORY_ERROR_GENERIC
+} EDataFactoryError;
+
+GQuark e_data_factory_error_quark (void);
+#define E_DATA_FACTORY_ERROR e_data_factory_error_quark ()
+
+GType e_data_factory_get_type (void);
+
+void e_data_factory_set_backend_mode (EDataFactory *factory, gint mode);
+
+/* FIXME: make these private again */
+void e_data_factory_publish_data (EDataFactory *factory, const gchar *IN_source, DBusGMethodInvocation *context);
+gint e_data_factory_main (gint argc, gchar **argv, EDataFactory *factory, GMainLoop *loop, const char *service_name, const char *object_path);
+
+G_END_DECLS
+
+#endif /* ! __E_DATA_FACTORY_H__ */
diff --git a/libebackend/e-data-types.h b/libebackend/e-data-types.h
new file mode 100644
index 0000000..4e6ba04
--- /dev/null
+++ b/libebackend/e-data-types.h
@@ -0,0 +1,76 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2006 OpenedHand Ltd
+ * Copyright (C) 2009 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of version 2.1 of the GNU Lesser General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This library 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 Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ *   Chris Toshok <toshok ximian com>
+ *   Ross Burton <ross linux intel com>
+ *   Travis Reitter <travis reitter collabora co uk>
+ */
+
+#ifndef __E_DATA_TYPES_H__
+#define __E_DATA_TYPES_H__
+
+G_BEGIN_DECLS
+
+typedef struct _EDataView        EDataView;
+typedef struct _EDataViewClass   EDataViewClass;
+
+typedef struct _EBackend        EBackend;
+typedef struct _EBackendClass   EBackendClass;
+
+typedef struct _EBackendSExp        EBackendSExp;
+typedef struct _EBackendSExpClass   EBackendSExpClass;
+
+typedef struct _EData        EData;
+typedef struct _EDataClass   EDataClass;
+
+/* FIXME: do translation for these to the class-specific types */
+typedef enum {
+	E_DATA_STATUS_SUCCESS,
+	E_DATA_STATUS_REPOSITORY_OFFLINE,
+	E_DATA_STATUS_PERMISSION_DENIED,
+	E_DATA_STATUS_CONTACT_NOT_FOUND,
+	E_DATA_STATUS_CONTACTID_ALREADY_EXISTS,
+	E_DATA_STATUS_AUTHENTICATION_FAILED,
+	E_DATA_STATUS_AUTHENTICATION_REQUIRED,
+	E_DATA_STATUS_UNSUPPORTED_FIELD,
+	E_DATA_STATUS_UNSUPPORTED_AUTHENTICATION_METHOD,
+	E_DATA_STATUS_TLS_NOT_AVAILABLE,
+	E_DATA_STATUS_NO_SUCH_DATA,
+	E_DATA_STATUS_REMOVED,
+	E_DATA_STATUS_OFFLINE_UNAVAILABLE,
+	E_DATA_STATUS_SEARCH_SIZE_LIMIT_EXCEEDED,
+	E_DATA_STATUS_SEARCH_TIME_LIMIT_EXCEEDED,
+	E_DATA_STATUS_INVALID_QUERY,
+	E_DATA_STATUS_QUERY_REFUSED,
+	E_DATA_STATUS_COULD_NOT_CANCEL,
+	E_DATA_STATUS_OTHER_ERROR,
+	E_DATA_STATUS_INVALID_SERVER_VERSION,
+	E_DATA_STATUS_NO_SPACE,
+} EDataStatus;
+
+typedef enum {
+	E_DATA_MODE_LOCAL,
+	E_DATA_MODE_REMOTE,
+	E_DATA_MODE_ANY,
+} EDataMode;
+
+G_END_DECLS
+
+#endif /* __E_DATA_TYPES_H__ */
diff --git a/libebackend/e-data-view.c b/libebackend/e-data-view.c
new file mode 100644
index 0000000..6aa47c6
--- /dev/null
+++ b/libebackend/e-data-view.c
@@ -0,0 +1,323 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2006 OpenedHand Ltd
+ * Copyright (C) 2009 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of version 2.1 of the GNU Lesser General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This library 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 Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author: Ross Burton <ross linux intel com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+
+#include "e-data-view.h"
+
+extern DBusGConnection *connection;
+
+#define THRESHOLD 32
+
+G_DEFINE_ABSTRACT_TYPE (EDataView, e_data_view, G_TYPE_OBJECT);
+
+#define E_DATA_VIEW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), E_TYPE_DATA_VIEW, EDataViewPrivate))
+
+struct _EDataViewPrivate {
+	EData *data;
+	EBackend *backend;
+
+	EBackendSExp *sexp;
+
+	gchar *dbus_path;
+};
+
+enum {
+	PROP_NONE,
+	PROP_BACKEND,
+	PROP_DATA,
+	PROP_DBUS_PATH,
+	PROP_SEXP,
+};
+
+static void
+data_destroyed_cb (gpointer data, GObject *dead)
+{
+	EDataView *view = E_DATA_VIEW (data);
+        EDataViewClass *klass;
+
+        klass = E_DATA_VIEW_GET_CLASS (view);
+
+	/* The data has just died, so unset the pointer so we don't try and
+	 * remove a dead weak reference. */
+	view->priv->data = NULL;
+
+	g_assert (klass->stop_if_running);
+	klass->stop_if_running (view);
+}
+
+static void
+e_data_view_get_property (GObject    *object,
+                          guint       property_id,
+                          GValue     *value,
+                          GParamSpec *pspec)
+{
+	EDataViewPrivate *priv = E_DATA_VIEW (object)->priv;
+
+	switch (property_id)
+	{
+		case PROP_BACKEND:
+			g_value_set_object (value, priv->backend);
+		break;
+
+		case PROP_DATA:
+			g_value_set_object (value, priv->data);
+		break;
+
+		case PROP_DBUS_PATH:
+			g_value_set_string (value, priv->dbus_path);
+		break;
+
+		case PROP_SEXP:
+			g_value_set_object (value, priv->sexp);
+		break;
+
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+	}
+}
+
+static void
+e_data_view_set_property (GObject      *object,
+			  guint         property_id,
+			  const GValue *value,
+			  GParamSpec   *pspec)
+{
+	EDataViewPrivate *priv;
+	EDataView *view;
+
+	view = E_DATA_VIEW (object);
+	priv = view->priv;
+
+	switch (property_id)
+	{
+		/* XXX: this property is only independent of the "data" property
+		 * because it would break compatability with EDataCalView (which
+		 * doesn't provide a "data" property value); it would be a bit
+		 * cleaner to make this small break, though */
+		case PROP_BACKEND:
+			/* make the "data" value override the "backend" value
+			 * for priv->backend to avoid a conflict for
+			 * EDataBookView */
+			if (priv->data)
+				break;
+
+			if (priv->backend)
+				g_object_unref (priv->backend);
+
+			priv->backend = g_value_dup_object (value);
+		break;
+
+		case PROP_DATA:
+			if (priv->data)
+				g_object_weak_unref (G_OBJECT (priv->data), data_destroyed_cb, view);
+
+			priv->data = g_value_get_object (value);
+
+			if (priv->data) {
+				/* Attach a weak reference to the data, so if it
+				 * dies the data view is destroyed too */
+				g_object_weak_ref (G_OBJECT (priv->data), data_destroyed_cb, view);
+
+				if (priv->backend)
+					g_object_unref (priv->backend);
+
+				priv->backend = g_object_ref (e_data_get_backend (priv->data));
+			}
+		break;
+
+		case PROP_DBUS_PATH:
+			priv->dbus_path = g_value_dup_string (value);
+		break;
+
+		case PROP_SEXP:
+			priv->sexp = g_value_dup_object (value);
+		break;
+
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+	}
+}
+
+static void
+e_data_view_dispose (GObject *object)
+{
+	EDataView *view = E_DATA_VIEW (object);
+	EDataViewPrivate *priv = view->priv;
+
+	if (priv->data) {
+		/* Remove the weak reference */
+		g_object_weak_unref (G_OBJECT (priv->data), data_destroyed_cb, view);
+		priv->data = NULL;
+	}
+
+	if (priv->backend) {
+		e_backend_remove_view (priv->backend, view);
+		g_object_unref (priv->backend);
+		priv->backend = NULL;
+	}
+
+	if (priv->sexp) {
+		g_object_unref (priv->sexp);
+		priv->sexp = NULL;
+	}
+
+	G_OBJECT_CLASS (e_data_view_parent_class)->dispose (object);
+}
+
+static void
+e_data_view_finalize (GObject *object)
+{
+	EDataView *view = E_DATA_VIEW (object);
+	EDataViewPrivate *priv = view->priv;
+
+	g_free (priv->dbus_path);
+
+	G_OBJECT_CLASS (e_data_view_parent_class)->finalize (object);
+}
+
+static void
+e_data_view_constructed (GObject *object)
+{
+	EDataView *view = E_DATA_VIEW (object);
+
+	dbus_g_connection_register_g_object (connection, view->priv->dbus_path, G_OBJECT (view));
+}
+
+static void
+e_data_view_class_init (EDataViewClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	object_class->dispose = e_data_view_dispose;
+	object_class->finalize = e_data_view_finalize;
+	object_class->constructed = e_data_view_constructed;
+	object_class->get_property = e_data_view_get_property;
+	object_class->set_property = e_data_view_set_property;
+
+        g_object_class_install_property
+                (object_class,
+                 PROP_DATA,
+                 g_param_spec_object
+                         ("data",
+                          "The backing EData",
+                          "The backing EData to base this view upon.",
+                          E_TYPE_DATA,
+                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+                          G_PARAM_STATIC_STRINGS));
+
+        g_object_class_install_property
+                (object_class,
+                 PROP_BACKEND,
+                 g_param_spec_object
+                         ("backend",
+                          "The backend of the view",
+                          "The backing EBackend to base this view upon.",
+                          E_TYPE_BACKEND,
+                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+                          G_PARAM_STATIC_STRINGS));
+
+        g_object_class_install_property
+                (object_class,
+                 PROP_DBUS_PATH,
+                 g_param_spec_string
+                         ("dbus-path",
+                          "D-Bus Object Path",
+                          "D-Bus object path of this object.",
+                          "",
+                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+                          G_PARAM_STATIC_STRINGS));
+
+        g_object_class_install_property
+                (object_class,
+                 PROP_SEXP,
+                 g_param_spec_object
+                         ("sexp",
+                          "The query as an EBackendSExp",
+                          "Structured EBackendSExp version of the query.",
+                          E_TYPE_BACKEND_SEXP,
+                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+                          G_PARAM_STATIC_STRINGS));
+
+	g_type_class_add_private (klass, sizeof (EDataViewPrivate));
+}
+
+static void
+e_data_view_init (EDataView *view)
+{
+	view->priv = E_DATA_VIEW_GET_PRIVATE (view);
+}
+
+/**
+ * e_data_view_get_sexp:
+ * @view: an #EDataView
+ *
+ * Gets the s-expression used for matching contacts to
+ * @view.
+ *
+ * Return value: The #EBackendSExp used.
+ **/
+EBackendSExp*
+e_data_view_get_sexp (EDataView *view)
+{
+	g_return_val_if_fail (E_IS_DATA_VIEW (view), NULL);
+
+	return view->priv->sexp;
+}
+
+/**
+ * e_data_view_get_backend:
+ * @view: an #EDataView
+ *
+ * Gets the backend that @view is querying.
+ *
+ * Return value: The associated #EBackend.
+ **/
+EBackend*
+e_data_view_get_backend (EDataView *view)
+{
+	g_return_val_if_fail (E_IS_DATA_VIEW (view), NULL);
+
+	return view->priv->backend;
+}
+
+/**
+ * e_data_view_get_dbus_path:
+ * @view: an #EDataView
+ *
+ * Gets the D-Bus object path for @view.
+ *
+ * Return value: The D-Bus path.
+ **/
+const gchar*
+e_data_view_get_dbus_path (EDataView *view)
+{
+	g_return_val_if_fail (E_IS_DATA_VIEW (view), NULL);
+
+	return view->priv->dbus_path;
+}
diff --git a/libebackend/e-data-view.h b/libebackend/e-data-view.h
new file mode 100644
index 0000000..f83c54b
--- /dev/null
+++ b/libebackend/e-data-view.h
@@ -0,0 +1,65 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2006 OpenedHand Ltd
+ * Copyright (C) 2009 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of version 2.1 of the GNU Lesser General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This library 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 Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author: Nat Friedman <nat ximian com>
+ * Author: Ross Burton <ross linux intel com>
+ */
+
+#ifndef __E_DATA_VIEW_H__
+#define __E_DATA_VIEW_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "e-data-types.h"
+#include "e-backend.h"
+#include "e-backend-sexp.h"
+
+G_BEGIN_DECLS
+
+#define E_TYPE_DATA_VIEW        (e_data_view_get_type ())
+#define E_DATA_VIEW(o)          (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_DATA_VIEW, EDataView))
+#define E_DATA_VIEW_CLASS(k)    (G_TYPE_CHECK_CLASS_CAST((k), E_TYPE_DATA_VIEW, EDataViewClass))
+#define E_IS_DATA_VIEW(o)       (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_DATA_VIEW))
+#define E_IS_DATA_VIEW_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_DATA_VIEW))
+#define E_DATA_VIEW_GET_CLASS(k) (G_TYPE_INSTANCE_GET_CLASS ((k), E_TYPE_DATA_VIEW, EDataViewClass))
+
+typedef struct _EDataViewPrivate EDataViewPrivate;
+
+struct _EDataView {
+	GObject parent;
+	EDataViewPrivate *priv;
+};
+
+struct _EDataViewClass {
+	GObjectClass parent;
+
+        void	(*stop_if_running)	(EDataView *view);
+};
+
+GType		e_data_view_get_type		(void);
+
+EBackendSExp*	e_data_view_get_sexp		(EDataView *view);
+EBackend*	e_data_view_get_backend		(EDataView *view);
+const gchar*	e_data_view_get_dbus_path	(EDataView *view);
+
+
+G_END_DECLS
+
+#endif /* ! __E_DATA_VIEW_H__ */
diff --git a/libebackend/e-data.c b/libebackend/e-data.c
new file mode 100644
index 0000000..e55962c
--- /dev/null
+++ b/libebackend/e-data.c
@@ -0,0 +1,241 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2006 OpenedHand Ltd
+ * Copyright (C) 2009 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of version 2.1 of the GNU Lesser General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This library 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 Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ *   Ross Burton <ross linux intel com>
+ *   Travis Reitter <travis reitter collabora co uk>
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+#include "e-data-types.h"
+#include "e-data.h"
+#include "e-data-view.h"
+
+G_DEFINE_ABSTRACT_TYPE(EData, e_data, G_TYPE_OBJECT);
+
+#define E_DATA_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), E_TYPE_DATA, EDataPrivate))
+
+struct _EDataPrivate {
+	EBackend *backend;
+	ESource *source;
+};
+
+enum {
+	PROP_0,
+	PROP_BACKEND,
+	PROP_SOURCE,
+};
+
+enum {
+	WRITABLE,
+	CONNECTION,
+	AUTH_REQUIRED,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+/* Create the EData error quark */
+GQuark
+e_data_error_quark (void)
+{
+	static GQuark quark = 0;
+	if (G_UNLIKELY (quark == 0))
+		quark = g_quark_from_static_string ("e-data-data-error");
+	return quark;
+}
+
+static void
+set_property (GObject      *object,
+	      guint         property_id,
+	      const GValue *value,
+	      GParamSpec   *pspec)
+{
+        EData *group;
+        EDataPrivate *priv;
+
+        group = E_DATA (object);
+        priv = E_DATA_GET_PRIVATE (object);
+
+	switch (property_id) {
+		case PROP_BACKEND:
+			if (priv->backend) {
+				g_warning (G_STRLOC ": backend has already been set");
+				return;
+			}
+			priv->backend = g_value_dup_object (value);
+			break;
+
+		case PROP_SOURCE:
+			if (priv->source) {
+				g_warning (G_STRLOC ": source has already been set");
+				return;
+			}
+			priv->source = g_value_dup_object (value);
+			break;
+
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+			break;
+	}
+}
+
+static void
+get_property (GObject    *object,
+	      guint       property_id,
+	      GValue     *value,
+	      GParamSpec *pspec)
+{
+	EDataPrivate *priv;
+
+	priv = E_DATA_GET_PRIVATE (object);
+
+	switch (property_id) {
+		case PROP_BACKEND:
+			g_value_set_object (value, priv->backend);
+			break;
+		case PROP_SOURCE:
+			g_value_set_object (value, priv->source);
+			break;
+		default:
+			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+			break;
+	}
+}
+
+static void
+e_data_dispose (GObject *object)
+{
+	EDataPrivate *priv;
+
+	priv = E_DATA_GET_PRIVATE (object);
+
+	if (priv->backend) {
+		g_object_unref (priv->backend);
+		priv->backend = NULL;
+	}
+
+	if (priv->source) {
+		g_object_unref (priv->source);
+		priv->source = NULL;
+	}
+
+	G_OBJECT_CLASS (e_data_parent_class)->dispose (object);
+}
+
+static void
+e_data_class_init (EDataClass *e_data_class)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (e_data_class);
+
+	object_class->dispose = e_data_dispose;
+	object_class->get_property = get_property;
+	object_class->set_property = set_property;
+
+	g_object_class_install_property
+		(object_class, PROP_BACKEND,
+		 g_param_spec_object
+			("backend",
+			 "Backend",
+			 "The backend that created this object",
+			 E_TYPE_BACKEND,
+			 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+			 G_PARAM_STATIC_STRINGS));
+
+	g_object_class_install_property
+		(object_class, PROP_SOURCE,
+		 g_param_spec_object
+			("source",
+			 "Source",
+			 "The ESource for this object",
+			 E_TYPE_SOURCE,
+			 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+			 G_PARAM_STATIC_STRINGS));
+
+	signals[WRITABLE] =
+		g_signal_new ("writable",
+			      G_OBJECT_CLASS_TYPE (e_data_class),
+			      G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+			      0,
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__BOOLEAN,
+			      G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
+
+	signals[CONNECTION] =
+		g_signal_new ("connection",
+			      G_OBJECT_CLASS_TYPE (e_data_class),
+			      G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+			      0,
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__BOOLEAN,
+			      G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
+
+	signals[AUTH_REQUIRED] =
+		g_signal_new ("auth-required",
+			      G_OBJECT_CLASS_TYPE (e_data_class),
+			      G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+			      0,
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE, 0);
+
+        g_type_class_add_private (e_data_class, sizeof (EDataPrivate));
+}
+
+/* Instance init */
+static void
+e_data_init (EData *ebook)
+{
+}
+
+EBackend*
+e_data_get_backend (EData *data)
+{
+	g_return_val_if_fail (E_IS_DATA (data), NULL);
+
+        return (E_DATA_GET_PRIVATE (data))->backend;
+}
+
+ESource*
+e_data_get_source (EData *data)
+{
+	g_return_val_if_fail (E_IS_DATA (data), NULL);
+
+        return (E_DATA_GET_PRIVATE (data))->source;
+}
+
+void
+e_data_notify_auth_required (EData *data)
+{
+	EDataClass *klass;
+
+	g_return_if_fail (E_IS_DATA (data));
+
+	klass = E_DATA_GET_CLASS (data);
+
+	if (klass->notify_auth_required) {
+		klass->notify_auth_required (data);
+		return;
+	}
+
+	g_signal_emit (data, signals[AUTH_REQUIRED], 0);
+}
diff --git a/libebackend/e-data.h b/libebackend/e-data.h
new file mode 100644
index 0000000..8f49c1c
--- /dev/null
+++ b/libebackend/e-data.h
@@ -0,0 +1,71 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2006 OpenedHand Ltd
+ * Copyright (C) 2009 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of version 2.1 of the GNU Lesser General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This library 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 Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ *   Ross Burton <ross linux intel com>
+ *   Travis Reitter <travis reitter collabora co uk>
+ */
+
+#ifndef __E_DATA_H__
+#define __E_DATA_H__
+
+#include <glib-object.h>
+#include <libedataserver/e-source.h>
+#include "e-backend.h"
+
+#include "e-data-types.h"
+
+G_BEGIN_DECLS
+
+#define E_TYPE_DATA        (e_data_get_type ())
+#define E_DATA(o)          (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_DATA, EData))
+#define E_DATA_CLASS(k)    (G_TYPE_CHECK_CLASS_CAST ((k), E_TYPE_DATA, EDataClass))
+#define E_IS_DATA(o)       (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_DATA))
+#define E_IS_DATA_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_DATA))
+#define E_DATA_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), E_TYPE_DATA, EDataClass))
+
+typedef struct _EDataPrivate EDataPrivate;
+
+struct _EData {
+	GObject parent;
+};
+
+struct _EDataClass {
+	GObjectClass parent;
+
+	/* mandatory virtual functions */
+	EBackend*	(* get_backend)			(EData *data);
+	ESource*	(* get_source)			(EData *data);
+
+	/* optional virtual functions */
+	void		(* notify_auth_required)	(EData *data);
+};
+
+GQuark e_data_error_quark (void);
+#define E_DATA_ERROR e_data_error_quark ()
+
+GType           e_data_get_type                (void);
+
+EBackend	*e_data_get_backend            (EData *data);
+ESource		*e_data_get_source             (EData *data);
+void             e_data_notify_auth_required   (EData *data);
+
+G_END_DECLS
+
+#endif /* ! __E_DATA_H__ */



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