aboutsummaryrefslogtreecommitdiffstats
path: root/addressbook/backend/pas/pas-backend.c
diff options
context:
space:
mode:
Diffstat (limited to 'addressbook/backend/pas/pas-backend.c')
-rw-r--r--addressbook/backend/pas/pas-backend.c362
1 files changed, 344 insertions, 18 deletions
diff --git a/addressbook/backend/pas/pas-backend.c b/addressbook/backend/pas/pas-backend.c
index 6d64ba938b..513632c909 100644
--- a/addressbook/backend/pas/pas-backend.c
+++ b/addressbook/backend/pas/pas-backend.c
@@ -10,6 +10,11 @@
#include "pas-backend.h"
#include "pas-marshal.h"
+struct _PASBackendPrivate {
+ GList *clients;
+ gboolean loaded, writable;
+};
+
/* Signal IDs */
enum {
LAST_CLIENT_GONE,
@@ -18,6 +23,7 @@ enum {
static guint pas_backend_signals[LAST_SIGNAL];
+static GObjectClass *parent_class;
gboolean
pas_backend_construct (PASBackend *backend)
@@ -32,6 +38,7 @@ pas_backend_load_uri (PASBackend *backend,
g_return_val_if_fail (backend != NULL, FALSE);
g_return_val_if_fail (PAS_IS_BACKEND (backend), FALSE);
g_return_val_if_fail (uri != NULL, FALSE);
+ g_return_val_if_fail (backend->priv->loaded == FALSE, FALSE);
g_assert (PAS_BACKEND_GET_CLASS (backend)->load_uri != NULL);
@@ -51,12 +58,279 @@ pas_backend_get_uri (PASBackend *backend)
{
g_return_val_if_fail (backend != NULL, NULL);
g_return_val_if_fail (PAS_IS_BACKEND (backend), NULL);
+ g_return_val_if_fail (backend->priv->loaded, NULL);
g_assert (PAS_BACKEND_GET_CLASS (backend)->get_uri != NULL);
return (* PAS_BACKEND_GET_CLASS (backend)->get_uri) (backend);
}
+
+void
+pas_backend_create_card (PASBackend *backend,
+ PASBook *book,
+ PASCreateCardRequest *req)
+{
+ g_return_if_fail (PAS_IS_BACKEND (backend));
+ g_return_if_fail (PAS_IS_BOOK (book));
+ g_return_if_fail (req != NULL && req->vcard != NULL);
+
+ g_assert (PAS_BACKEND_GET_CLASS (backend)->create_card != NULL);
+
+ return (* PAS_BACKEND_GET_CLASS (backend)->create_card) (backend, book, req);
+}
+
+void
+pas_backend_remove_card (PASBackend *backend,
+ PASBook *book,
+ PASRemoveCardRequest *req)
+{
+ g_return_if_fail (PAS_IS_BACKEND (backend));
+ g_return_if_fail (PAS_IS_BOOK (book));
+ g_return_if_fail (req != NULL && req->id != NULL);
+
+ g_assert (PAS_BACKEND_GET_CLASS (backend)->remove_card != NULL);
+
+ return (* PAS_BACKEND_GET_CLASS (backend)->remove_card) (backend, book, req);
+}
+
+void
+pas_backend_modify_card (PASBackend *backend,
+ PASBook *book,
+ PASModifyCardRequest *req)
+{
+ g_return_if_fail (PAS_IS_BACKEND (backend));
+ g_return_if_fail (PAS_IS_BOOK (book));
+ g_return_if_fail (req != NULL && req->vcard != NULL);
+
+ g_assert (PAS_BACKEND_GET_CLASS (backend)->modify_card != NULL);
+
+ return (* PAS_BACKEND_GET_CLASS (backend)->modify_card) (backend, book, req);
+}
+
+void
+pas_backend_check_connection (PASBackend *backend,
+ PASBook *book,
+ PASCheckConnectionRequest *req)
+{
+ g_return_if_fail (PAS_IS_BACKEND (backend));
+ g_return_if_fail (PAS_IS_BOOK (book));
+ g_return_if_fail (req != NULL);
+
+ g_assert (PAS_BACKEND_GET_CLASS (backend)->check_connection != NULL);
+
+ return (* PAS_BACKEND_GET_CLASS (backend)->check_connection) (backend, book, req);
+}
+
+void
+pas_backend_get_vcard (PASBackend *backend,
+ PASBook *book,
+ PASGetVCardRequest *req)
+{
+ g_return_if_fail (PAS_IS_BACKEND (backend));
+ g_return_if_fail (PAS_IS_BOOK (book));
+ g_return_if_fail (req != NULL && req->id != NULL);
+
+ g_assert (PAS_BACKEND_GET_CLASS (backend)->get_vcard != NULL);
+
+ return (* PAS_BACKEND_GET_CLASS (backend)->get_vcard) (backend, book, req);
+}
+
+void
+pas_backend_get_cursor (PASBackend *backend,
+ PASBook *book,
+ PASGetCursorRequest *req)
+{
+ g_return_if_fail (PAS_IS_BACKEND (backend));
+ g_return_if_fail (PAS_IS_BOOK (book));
+ g_return_if_fail (req != NULL && req->search != NULL);
+
+ g_assert (PAS_BACKEND_GET_CLASS (backend)->get_cursor != NULL);
+
+ return (* PAS_BACKEND_GET_CLASS (backend)->get_cursor) (backend, book, req);
+}
+
+void
+pas_backend_get_book_view (PASBackend *backend,
+ PASBook *book,
+ PASGetBookViewRequest *req)
+{
+ g_return_if_fail (PAS_IS_BACKEND (backend));
+ g_return_if_fail (PAS_IS_BOOK (book));
+ g_return_if_fail (req != NULL && req->search != NULL && req->listener != CORBA_OBJECT_NIL);
+
+ g_assert (PAS_BACKEND_GET_CLASS (backend)->get_book_view != NULL);
+
+ return (* PAS_BACKEND_GET_CLASS (backend)->get_book_view) (backend, book, req);
+}
+
+void
+pas_backend_get_completion_view (PASBackend *backend,
+ PASBook *book,
+ PASGetCompletionViewRequest *req)
+{
+ g_return_if_fail (PAS_IS_BACKEND (backend));
+ g_return_if_fail (PAS_IS_BOOK (book));
+ g_return_if_fail (req != NULL && req->search != NULL && req->listener != CORBA_OBJECT_NIL);
+
+ g_assert (PAS_BACKEND_GET_CLASS (backend)->get_completion_view != NULL);
+
+ return (* PAS_BACKEND_GET_CLASS (backend)->get_completion_view) (backend, book, req);
+}
+
+void
+pas_backend_get_changes (PASBackend *backend,
+ PASBook *book,
+ PASGetChangesRequest *req)
+{
+ g_return_if_fail (PAS_IS_BACKEND (backend));
+ g_return_if_fail (PAS_IS_BOOK (book));
+ g_return_if_fail (req != NULL && req->change_id != NULL && req->listener != CORBA_OBJECT_NIL);
+
+ g_assert (PAS_BACKEND_GET_CLASS (backend)->get_changes != NULL);
+
+ return (* PAS_BACKEND_GET_CLASS (backend)->get_changes) (backend, book, req);
+}
+
+void
+pas_backend_authenticate_user (PASBackend *backend,
+ PASBook *book,
+ PASAuthenticateUserRequest *req)
+{
+ g_return_if_fail (PAS_IS_BACKEND (backend));
+ g_return_if_fail (PAS_IS_BOOK (book));
+ g_return_if_fail (req != NULL);
+
+ g_assert (PAS_BACKEND_GET_CLASS (backend)->authenticate_user != NULL);
+
+ return (* PAS_BACKEND_GET_CLASS (backend)->authenticate_user) (backend, book, req);
+}
+
+void
+pas_backend_get_supported_fields (PASBackend *backend,
+ PASBook *book,
+ PASGetSupportedFieldsRequest *req)
+{
+ g_return_if_fail (PAS_IS_BACKEND (backend));
+ g_return_if_fail (PAS_IS_BOOK (book));
+ g_return_if_fail (req != NULL);
+
+ g_assert (PAS_BACKEND_GET_CLASS (backend)->get_supported_fields != NULL);
+
+ return (* PAS_BACKEND_GET_CLASS (backend)->get_supported_fields) (backend, book, req);
+}
+
+static void
+process_client_requests (PASBook *book, gpointer user_data)
+{
+ PASBackend *backend;
+ PASRequest *req;
+
+ backend = PAS_BACKEND (user_data);
+
+ req = pas_book_pop_request (book);
+ if (req == NULL)
+ return;
+
+ switch (req->op) {
+ case CreateCard:
+ pas_backend_create_card (backend, book, &req->create);
+ break;
+
+ case RemoveCard:
+ pas_backend_remove_card (backend, book, &req->remove);
+ break;
+
+ case ModifyCard:
+ pas_backend_modify_card (backend, book, &req->modify);
+ break;
+
+ case CheckConnection:
+ pas_backend_check_connection (backend, book, &req->check_connection);
+ break;
+
+ case GetVCard:
+ pas_backend_get_vcard (backend, book, &req->get_vcard);
+ break;
+
+ case GetCursor:
+ pas_backend_get_cursor (backend, book, &req->get_cursor);
+ break;
+
+ case GetBookView:
+ pas_backend_get_book_view (backend, book, &req->get_book_view);
+ break;
+
+ case GetCompletionView:
+ pas_backend_get_completion_view (backend, book, &req->get_completion_view);
+ break;
+
+ case GetChanges:
+ pas_backend_get_changes (backend, book, &req->get_changes);
+ break;
+
+ case AuthenticateUser:
+ pas_backend_authenticate_user (backend, book, &req->auth_user);
+ break;
+
+ case GetSupportedFields:
+ pas_backend_get_supported_fields (backend, book, &req->get_supported_fields);
+ break;
+ }
+
+ pas_book_free_request (req);
+}
+
+static void
+book_destroy_cb (gpointer data, GObject *where_book_was)
+{
+ PASBackend *backend = PAS_BACKEND (data);
+
+ pas_backend_remove_client (backend, (PASBook *)where_book_was);
+}
+
+static void
+last_client_gone (PASBackend *backend)
+{
+ g_signal_emit (backend, pas_backend_signals[LAST_CLIENT_GONE], 0);
+}
+
+static gboolean
+add_client (PASBackend *backend,
+ GNOME_Evolution_Addressbook_BookListener listener)
+{
+ PASBook *book;
+
+ book = pas_book_new (backend, listener);
+ if (!book) {
+ if (!backend->priv->clients)
+ last_client_gone (backend);
+
+ return FALSE;
+ }
+
+ g_object_weak_ref (G_OBJECT (book), book_destroy_cb, backend);
+
+ g_signal_connect (book, "requests_queued",
+ G_CALLBACK (process_client_requests), backend);
+
+ backend->priv->clients = g_list_prepend (backend->priv->clients, book);
+
+ if (backend->priv->loaded) {
+ pas_book_respond_open (
+ book, GNOME_Evolution_Addressbook_BookListener_Success);
+ } else {
+ pas_book_respond_open (
+ book, GNOME_Evolution_Addressbook_BookListener_OtherError);
+ }
+
+ pas_book_report_writable (book, backend->priv->writable);
+
+ bonobo_object_unref (BONOBO_OBJECT (book));
+
+ return TRUE;
+}
+
/**
* pas_backend_add_client:
* @backend: An addressbook backend.
@@ -67,10 +341,9 @@ pas_backend_get_uri (PASBackend *backend)
* Return value: TRUE on success, FALSE on failure to add the client.
*/
gboolean
-pas_backend_add_client (PASBackend *backend,
+pas_backend_add_client (PASBackend *backend,
GNOME_Evolution_Addressbook_BookListener listener)
{
- g_return_val_if_fail (backend != NULL, FALSE);
g_return_val_if_fail (PAS_IS_BACKEND (backend), FALSE);
g_return_val_if_fail (listener != CORBA_OBJECT_NIL, FALSE);
@@ -79,13 +352,25 @@ pas_backend_add_client (PASBackend *backend,
return PAS_BACKEND_GET_CLASS (backend)->add_client (backend, listener);
}
+static void
+remove_client (PASBackend *backend,
+ PASBook *book)
+{
+ /* Disconnect */
+ 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);
+}
+
void
pas_backend_remove_client (PASBackend *backend,
PASBook *book)
{
- g_return_if_fail (backend != NULL);
g_return_if_fail (PAS_IS_BACKEND (backend));
- g_return_if_fail (book != NULL);
g_return_if_fail (PAS_IS_BOOK (book));
g_assert (PAS_BACKEND_GET_CLASS (backend)->remove_client != NULL);
@@ -104,26 +389,64 @@ pas_backend_get_static_capabilities (PASBackend *backend)
return PAS_BACKEND_GET_CLASS (backend)->get_static_capabilities (backend);
}
-/**
- * pas_backend_last_client_gone:
- * @backend: An addressbook backend.
- *
- * Emits the "last_client_gone" signal for the specified backend. Should
- * only be called from backend implementations if the backend really does
- * not have any more clients.
- **/
+gboolean
+pas_backend_is_loaded (PASBackend *backend)
+{
+ g_return_val_if_fail (PAS_IS_BACKEND (backend), FALSE);
+
+ return backend->priv->loaded;
+}
+
void
-pas_backend_last_client_gone (PASBackend *backend)
+pas_backend_set_is_loaded (PASBackend *backend, gboolean is_loaded)
{
- g_return_if_fail (backend != NULL);
g_return_if_fail (PAS_IS_BACKEND (backend));
- g_signal_emit (backend, pas_backend_signals[LAST_CLIENT_GONE], 0);
+ backend->priv->loaded = is_loaded;
+}
+
+gboolean
+pas_backend_is_writable (PASBackend *backend)
+{
+ g_return_val_if_fail (PAS_IS_BACKEND (backend), FALSE);
+
+ return backend->priv->writable;
+}
+
+void
+pas_backend_set_is_writable (PASBackend *backend, gboolean is_writable)
+{
+ g_return_if_fail (PAS_IS_BACKEND (backend));
+
+ backend->priv->writable = is_writable;
}
static void
pas_backend_init (PASBackend *backend)
{
+ PASBackendPrivate *priv;
+
+ priv = g_new0 (PASBackendPrivate, 1);
+ priv->clients = NULL;
+
+ backend->priv = priv;
+}
+
+static void
+pas_backend_dispose (GObject *object)
+{
+ PASBackend *backend;
+
+ backend = PAS_BACKEND (object);
+
+ if (backend->priv) {
+ g_list_free (backend->priv->clients);
+ g_free (backend->priv);
+
+ backend->priv = NULL;
+ }
+
+ G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
@@ -131,11 +454,14 @@ pas_backend_class_init (PASBackendClass *klass)
{
GObjectClass *object_class;
+ parent_class = g_type_class_peek_parent (klass);
+
object_class = (GObjectClass *) klass;
- klass->add_client = NULL;
- klass->remove_client = NULL;
- klass->get_static_capabilities = NULL;
+ klass->add_client = add_client;
+ klass->remove_client = remove_client;
+
+ object_class->dispose = pas_backend_dispose;
pas_backend_signals[LAST_CLIENT_GONE] =
g_signal_new ("last_client_gone",