[evolution-data-server/treitter-factory-refactor] Factor out generic EDataFactory (and subclasses) from EDataBookFactory.
- From: Travis Reitter <treitter src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [evolution-data-server/treitter-factory-refactor] Factor out generic EDataFactory (and subclasses) from EDataBookFactory.
- Date: Tue, 26 Jan 2010 18:15:42 +0000 (UTC)
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]