evolution-data-server r9539 - in branches/eds-dbus/addressbook: . libebook libedata-book



Author: rbradford
Date: Fri Sep 12 17:21:22 2008
New Revision: 9539
URL: http://svn.gnome.org/viewvc/evolution-data-server?rev=9539&view=rev

Log:
2008-09-12  Rob Bradford  <rob linux intel com>

	* Makefile.am:
	* libebook/Makefile.am:
	* libebook/e-book-types.h:
	* libebook/e-book-view-private.h:
	* libebook/e-book-view.c (e_book_view_dispose),
	(e_book_view_class_init), (e_book_view_init), (status_message_cb),
	(contacts_added_cb), (contacts_changed_cb), (contacts_removed_cb),
	(complete_cb), (_e_book_view_new), (e_book_view_get_book),
	(e_book_view_start), (e_book_view_stop):
	* libebook/e-book.c (e_book_error_quark), (proxy_destroyed),
	(e_book_dispose), (e_book_finalize), (e_book_class_init),
	(e_book_init), (e_book_activate), (writable_cb), (connection_cb),
	(auth_required_cb), (e_book_get_addressbooks), (e_book_new),
	(e_book_new_from_uri), (e_book_new_system_addressbook),
	(e_book_new_default_addressbook), (e_book_get_source),
	(e_book_open), (open_reply), (e_book_async_open), (e_book_remove),
	(remove_reply), (e_book_async_remove),
	(e_book_get_required_fields), (get_required_fields_reply),
	(e_book_async_get_required_fields), (e_book_get_supported_fields),
	(get_supported_fields_reply), (e_book_async_get_supported_fields),
	(e_book_get_supported_auth_methods),
	(get_supported_auth_methods_reply),
	(e_book_async_get_supported_auth_methods),
	(e_book_authenticate_user), (authenticate_user_reply),
	(e_book_async_authenticate_user), (e_book_get_contact),
	(get_contact_reply), (e_book_async_get_contact),
	(e_book_get_contacts), (get_contacts_reply),
	(e_book_async_get_contacts), (parse_changes_array),
	(e_book_get_changes), (get_changes_reply),
	(e_book_async_get_changes), (e_book_free_change_list),
	(e_book_add_contact), (add_contact_reply),
	(e_book_async_add_contact), (e_book_commit_contact),
	(modify_contact_reply), (e_book_async_commit_contact),
	(e_book_remove_contact), (remove_contact_reply),
	(e_book_async_remove_contact), (remove_contact_by_id_reply),
	(e_book_async_remove_contact_by_id), (e_book_remove_contacts),
	(remove_contacts_reply), (e_book_async_remove_contacts),
	(e_book_get_book_view), (get_book_view_reply),
	(e_book_async_get_book_view), (e_book_is_opened),
	(e_book_is_writable), (e_book_is_online), (e_book_cancel),
	(e_book_get_uri), (e_book_get_static_capabilities),
	(e_book_get_self), (e_book_set_self), (e_book_is_self),
	(e_book_set_default_addressbook), (e_book_set_default_source),
	(e_book_check_static_capability), (unwrap_gerror),
	(get_status_from_error), (flatten_stringlist),
	(array_to_stringlist):
	* libebook/libebook.pc.in:
	* libedata-book/Makefile.am:
	* libedata-book/e-book-backend-sync.h:
	* libedata-book/e-book-backend.c (e_book_backend_load_source),
	(e_book_backend_open), (e_book_backend_modify_contacts),
	(e_book_backend_cancel_operation), (e_book_backend_add_client),
	(e_book_backend_has_out_of_proc_clients),
	(e_book_backend_set_mode), (e_book_backend_change_add_new),
	(e_book_backend_change_modify_new),
	(e_book_backend_change_delete_new), (e_book_backend_foreach_view),
	(view_notify_complete), (e_book_backend_notify_connection_status),
	(e_book_backend_init), (e_book_backend_dispose):
	* libedata-book/e-book-backend.h:
	* libedata-book/e-data-book-factory.c
	(e_data_book_factory_error_quark),
	(e_data_book_factory_register_backend),
	(e_data_book_factory_register_backends),
	(e_data_book_factory_class_init), (e_data_book_factory_init),
	(e_data_book_factory_extract_proto_from_uri),
	(e_data_book_factory_lookup_backend_factory), (make_path_name),
	(my_remove), (book_closed_cb), (impl_BookFactory_getBook),
	(name_owner_changed), (die), (sync_book_foreach), (backup_start),
	(main), (nm_dbus_escape_object_path):
	* libedata-book/e-data-book-factory.h:
	* libedata-book/e-data-book-types.h:
	* libedata-book/e-data-book-view.c (e_data_book_view_class_init),
	(e_data_book_view_init), (book_destroyed_cb),
	(e_data_book_view_new), (e_data_book_view_dispose),
	(e_data_book_view_finalize), (bookview_idle_start),
	(impl_BookView_start), (bookview_idle_stop), (impl_BookView_stop),
	(impl_BookView_dispose), (e_data_book_view_set_thresholds),
	(e_data_book_view_get_card_query),
	(e_data_book_view_get_card_sexp),
	(e_data_book_view_get_max_results), (e_data_book_view_get_backend),
	(send_pending_adds), (send_pending_changes),
	(send_pending_removes), (notify_change), (notify_remove),
	(notify_add), (e_data_book_view_notify_update),
	(e_data_book_view_notify_update_vcard),
	(e_data_book_view_notify_update_prefiltered_vcard),
	(e_data_book_view_notify_remove),
	(e_data_book_view_notify_complete),
	(e_data_book_view_notify_status_message), (reset_array),
	(e_data_book_view_ref), (e_data_book_view_unref):
	* libedata-book/e-data-book-view.h:
	* libedata-book/e-data-book.c (operation_thread), (op_new),
	(e_data_book_error_quark), (e_data_book_dispose),
	(e_data_book_class_init), (e_data_book_init), (e_data_book_new),
	(e_data_book_get_source), (e_data_book_get_backend),
	(impl_AddressBook_Book_open), (e_data_book_respond_open),
	(impl_AddressBook_Book_remove), (e_data_book_respond_remove),
	(impl_AddressBook_Book_getContact),
	(e_data_book_respond_get_contact),
	(impl_AddressBook_Book_getContactList),
	(e_data_book_respond_get_contact_list),
	(impl_AddressBook_Book_authenticateUser),
	(e_data_book_respond_authenticate_user),
	(impl_AddressBook_Book_addContact), (e_data_book_respond_create),
	(impl_AddressBook_Book_modifyContact),
	(e_data_book_respond_modify),
	(impl_AddressBook_Book_modifyContacts),
	(e_data_book_respond_modify_contacts),
	(impl_AddressBook_Book_removeContacts),
	(e_data_book_respond_remove_contacts),
	(impl_AddressBook_Book_getStaticCapabilities),
	(impl_AddressBook_Book_getSupportedFields),
	(e_data_book_respond_get_supported_fields),
	(impl_AddressBook_Book_getRequiredFields),
	(e_data_book_respond_get_required_fields),
	(impl_AddressBook_Book_getSupportedAuthMethods),
	(e_data_book_respond_get_supported_auth_methods),
	(construct_bookview_path), (impl_AddressBook_Book_getBookView),
	(impl_AddressBook_Book_getChanges),
	(e_data_book_respond_get_changes),
	(impl_AddressBook_Book_cancelOperation),
	(impl_AddressBook_Book_close), (e_data_book_report_writable),
	(e_data_book_report_connection_status),
	(e_data_book_report_auth_required), (return_status_and_list):
	* libedata-book/e-data-book.h:
	* libedata-book/libedata-book.pc.in:
	Import & refine core libedata-book and libebook functionality using
	DBUS for IPC. With this it's possible to use the backends unchanged.

Modified:
   branches/eds-dbus/addressbook/ChangeLog
   branches/eds-dbus/addressbook/Makefile.am
   branches/eds-dbus/addressbook/libebook/Makefile.am
   branches/eds-dbus/addressbook/libebook/e-book-types.h
   branches/eds-dbus/addressbook/libebook/e-book-view-private.h
   branches/eds-dbus/addressbook/libebook/e-book-view.c
   branches/eds-dbus/addressbook/libebook/e-book.c
   branches/eds-dbus/addressbook/libebook/libebook.pc.in
   branches/eds-dbus/addressbook/libedata-book/Makefile.am
   branches/eds-dbus/addressbook/libedata-book/e-book-backend-sync.h
   branches/eds-dbus/addressbook/libedata-book/e-book-backend.c
   branches/eds-dbus/addressbook/libedata-book/e-book-backend.h
   branches/eds-dbus/addressbook/libedata-book/e-data-book-factory.c
   branches/eds-dbus/addressbook/libedata-book/e-data-book-factory.h
   branches/eds-dbus/addressbook/libedata-book/e-data-book-types.h
   branches/eds-dbus/addressbook/libedata-book/e-data-book-view.c
   branches/eds-dbus/addressbook/libedata-book/e-data-book-view.h
   branches/eds-dbus/addressbook/libedata-book/e-data-book.c
   branches/eds-dbus/addressbook/libedata-book/e-data-book.h
   branches/eds-dbus/addressbook/libedata-book/libedata-book.pc.in

Modified: branches/eds-dbus/addressbook/Makefile.am
==============================================================================
--- branches/eds-dbus/addressbook/Makefile.am	(original)
+++ branches/eds-dbus/addressbook/Makefile.am	Fri Sep 12 17:21:22 2008
@@ -1 +1 @@
-SUBDIRS = idl libebook libedata-book backends tests
\ No newline at end of file
+SUBDIRS=libebook libedata-book backends

Modified: branches/eds-dbus/addressbook/libebook/Makefile.am
==============================================================================
--- branches/eds-dbus/addressbook/libebook/Makefile.am	(original)
+++ branches/eds-dbus/addressbook/libebook/Makefile.am	Fri Sep 12 17:21:22 2008
@@ -5,56 +5,38 @@
 	-I$(top_builddir)				\
 	-I$(top_srcdir)/addressbook			\
 	-I$(top_builddir)/addressbook			\
-	-I$(top_builddir)/addressbook/libebook		\
-        $(EVOLUTION_ADDRESSBOOK_CFLAGS)
+	$(EVOLUTION_ADDRESSBOOK_CFLAGS)			\
+	$(DBUS_GLIB_CFLAGS)
 
-# The corba stubs and skels
-CORBA_GENERATED_C =				\
-	Evolution-DataServer-Addressbook-common.c		\
-	Evolution-DataServer-Addressbook-skels.c		\
-	Evolution-DataServer-Addressbook-stubs.c
-CORBA_GENERATED_H =			\
-	Evolution-DataServer-Addressbook.h
-
-CORBA_GENERATED = $(CORBA_GENERATED_C) $(CORBA_GENERATED_H)
-
-idls =						\
-	$(srcdir)/../idl/Evolution-DataServer-Addressbook.idl
-
-idl_flags = $(IDL_INCLUDES)
-
-$(CORBA_GENERATED_H): $(idls)
-	$(ORBIT_IDL) $(idl_flags) $(srcdir)/../idl/Evolution-DataServer-Addressbook.idl
-$(CORBA_GENERATED_C): $(CORBA_GENERATED_H)
+# The marshallers
+MARSHAL_GENERATED = e-book-marshal.c e-book-marshal.h
+ EVO_MARSHAL_RULE@
 
 # The library
 lib_LTLIBRARIES = libebook-1.2.la
 
-libebook_1_2_la_SOURCES =				\
-	$(CORBA_GENERATED_C)				\
-	$(CORBA_GENERATED_H)				\
+libebook_1_2_la_SOURCES =					\
+	$(MARSHAL_GENERATED)				\
+	$(DBUS_GENERATED_H)				\
 	e-address-western.c				\
-	e-book-listener.c				\
-	e-book-listener.h				\
 	e-book-query.c					\
-	e-book-view-listener.c				\
-	e-book-view-listener.h				\
-	e-book-view-private.h				\
 	e-book-view.c					\
+	e-book-view-private.h				\
 	e-book.c					\
 	e-contact.c					\
 	e-destination.c					\
 	e-name-western.c				\
-	e-name-western-tables.h                         \
-	e-vcard.c
+	e-name-western-tables.h				\
+	e-vcard.c					\
+	e-error.h
 
 libebook_1_2_la_LIBADD =					\
-	$(top_builddir)/camel/libcamel-1.2.la			\
-	$(top_builddir)/libedataserver/libedataserver-1.2.la    \
-	$(EVOLUTION_ADDRESSBOOK_LIBS)
+	$(EVOLUTION_ADDRESSBOOK_LIBS)				\
+	$(top_builddir)/camel/libcamel-$(API_VERSION).la \
+	$(top_builddir)/libedataserver/libedataserver-$(API_VERSION).la
 
 libebook_1_2_la_LDFLAGS = 							\
-	-version-info $(LIBEBOOK_CURRENT):$(LIBEBOOK_REVISION):$(LIBEBOOK_AGE) $(NO_UNDEFINED)
+	-version-info $(LIBEBOOK_CURRENT):$(LIBEBOOK_REVISION):$(LIBEBOOK_AGE)
 
 libebookincludedir = $(privincludedir)/libebook
 
@@ -72,20 +54,30 @@
 %-$(API_VERSION).pc: %.pc
 	 cp $< $@
 
-e-name-western-tables.h: e-name-western-tables.h.in
-	${srcdir}/gen-western-table.py < $< > $@
-
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = libebook-$(API_VERSION).pc
 
-BUILT_SOURCES = $(CORBA_GENERATED)
+DBUS_GENERATED_H = e-data-book-factory-bindings.h e-data-book-bindings.h e-data-book-view-bindings.h
+%-glue.h: $(top_srcdir)/addressbook/libedata-book/%.xml
+	dbus-binding-tool --mode=glib-server --output=$@ --prefix=$(subst -,_,$*) $^
+
+%-bindings.h: $(top_srcdir)/addressbook/libedata-book/%.xml
+	dbus-binding-tool --mode=glib-client --output=$@ --prefix=$(subst -,_,$*) $^
+
+BUILT_SOURCES = $(DBUS_GENERATED_H) $(MARSHAL_GENERATED)
 CLEANFILES    = $(BUILT_SOURCES)
 DISTCLEANFILES = $(pkgconfig_DATA)
 
 EXTRA_DIST = 						\
-	$(pkgconfig_DATA:-$(API_VERSION).pc=.pc.in)     \
-	e-name-western-tables.h.in                      \
-	gen-western-table.py
+	e-book-marshal.list				\
+	$(pkgconfig_DATA:-$(API_VERSION).pc=.pc.in)
 
 dist-hook:
 	cd $(distdir); rm -f $(BUILT_SOURCES)
+
+
+check_PROGRAMS = test-suite
+test_suite_SOURCES = test-main.c test-econtact.c test-commit.c test-prototypes.h
+test_suite_LDADD = ./libebook-1.2.la -lcheck
+
+TESTS = test-suite

Modified: branches/eds-dbus/addressbook/libebook/e-book-types.h
==============================================================================
--- branches/eds-dbus/addressbook/libebook/e-book-types.h	(original)
+++ branches/eds-dbus/addressbook/libebook/e-book-types.h	Fri Sep 12 17:21:22 2008
@@ -44,7 +44,8 @@
 	E_BOOK_ERROR_OFFLINE_UNAVAILABLE,
 	E_BOOK_ERROR_OTHER_ERROR,
 	E_BOOK_ERROR_INVALID_SERVER_VERSION,
-	E_BOOK_ERROR_UNSUPPORTED_AUTHENTICATION_METHOD
+	E_BOOK_ERROR_UNSUPPORTED_AUTHENTICATION_METHOD,
+	E_BOOK_ERROR_NO_SPACE
 } EBookStatus;
 
 

Modified: branches/eds-dbus/addressbook/libebook/e-book-view-private.h
==============================================================================
--- branches/eds-dbus/addressbook/libebook/e-book-view-private.h	(original)
+++ branches/eds-dbus/addressbook/libebook/e-book-view-private.h	Fri Sep 12 17:21:22 2008
@@ -1,24 +1,30 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
- * The Evolution addressbook client object.
+ * Copyright (C) 2006 OpenedHand Ltd
  *
- * Author:
- *   Nat Friedman (nat ximian com)
+ * 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.
  *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * 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.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Author: Ross Burton <ross openedhand com>
  */
 
 #ifndef __E_BOOK_VIEW_PRIVATE_H__
 #define __E_BOOK_VIEW_PRIVATE_H__
 
-#include <glib.h>
-#include <glib-object.h>
-
-#include "Evolution-DataServer-Addressbook.h"
-#include "e-book-view-listener.h"
+#include "e-book.h"
+#include "e-book-view.h"
 
-/* Creating a new addressbook. */
-EBookView *e_book_view_new (GNOME_Evolution_Addressbook_BookView corba_book_view, EBookViewListener *listener);
+EBookView *_e_book_view_new (EBook *book, DBusGProxy *view_proxy);
 
 G_END_DECLS
 

Modified: branches/eds-dbus/addressbook/libebook/e-book-view.c
==============================================================================
--- branches/eds-dbus/addressbook/libebook/e-book-view.c	(original)
+++ branches/eds-dbus/addressbook/libebook/e-book-view.c	Fri Sep 12 17:21:22 2008
@@ -1,208 +1,251 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
- * The Evolution addressbook client object.
+ * Copyright (C) 2006 OpenedHand Ltd
  *
- * Author:
- *   Nat Friedman (nat ximian com)
+ * 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.
  *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * 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.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Author: Ross Burton <ross openedhand com>
  */
 
-#include <config.h>
-
-#include "e-book-view-listener.h"
+#include <glib-object.h>
+#include <dbus/dbus-glib.h>
+#include "e-book.h"
 #include "e-book-view.h"
 #include "e-book-view-private.h"
-#include "e-book.h"
-
-static GObjectClass *parent_class;
+#include "e-data-book-view-bindings.h"
+#include "e-book-marshal.h"
 
-struct _EBookViewPrivate {
-	GNOME_Evolution_Addressbook_BookView     corba_book_view;
-
-	EBook                 *book;
+G_DEFINE_TYPE(EBookView, e_book_view, G_TYPE_OBJECT);
 
-	EBookViewListener     *listener;
+#define E_BOOK_VIEW_GET_PRIVATE(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), E_TYPE_BOOK_VIEW, EBookViewPrivate))
 
-	int                    response_id;
+struct _EBookViewPrivate {
+  EBook *book;
+  DBusGProxy *view_proxy;
+  gboolean running;
 };
 
 enum {
-	CONTACTS_CHANGED,
-	CONTACTS_REMOVED,
-	CONTACTS_ADDED,
-	SEQUENCE_COMPLETE,
-	STATUS_MESSAGE,
-	LAST_SIGNAL
+  CONTACTS_CHANGED,
+  CONTACTS_REMOVED,
+  CONTACTS_ADDED,
+  SEQUENCE_COMPLETE,
+  STATUS_MESSAGE,
+  LAST_SIGNAL
 };
-
-static guint e_book_view_signals [LAST_SIGNAL];
+static guint signals [LAST_SIGNAL];
 
 static void
-e_book_view_do_added_event (EBookView                 *book_view,
-			    EBookViewListenerResponse *resp)
+e_book_view_dispose (GObject *object)
 {
-	g_signal_emit (book_view, e_book_view_signals [CONTACTS_ADDED], 0,
-		       resp->contacts);
+  EBookView *view = E_BOOK_VIEW (object);
+
+  if (view->priv->view_proxy) {
+    org_gnome_evolution_dataserver_addressbook_BookView_dispose (view->priv->view_proxy, NULL);
+    g_object_unref (view->priv->view_proxy);
+    view->priv->view_proxy = NULL;
+  }
+
+  if (view->priv->book) {
+    g_object_unref (view->priv->book);
+    view->priv->book = NULL;
+  }
 }
 
 static void
-e_book_view_do_modified_event (EBookView                 *book_view,
-			       EBookViewListenerResponse *resp)
+e_book_view_class_init (EBookViewClass *klass)
 {
-	g_signal_emit (book_view, e_book_view_signals [CONTACTS_CHANGED], 0,
-		       resp->contacts);
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->dispose = e_book_view_dispose;
+
+  g_type_class_add_private (klass, sizeof (EBookViewPrivate));
+
+  signals [CONTACTS_CHANGED] = g_signal_new ("contacts_changed",
+                                             G_OBJECT_CLASS_TYPE (object_class),
+                                             G_SIGNAL_RUN_LAST,
+                                             G_STRUCT_OFFSET (EBookViewClass, contacts_changed),
+                                             NULL, NULL,
+                                             e_book_marshal_NONE__POINTER,
+                                             G_TYPE_NONE, 1, G_TYPE_POINTER);
+  signals [CONTACTS_REMOVED] = g_signal_new ("contacts_removed",
+                                             G_OBJECT_CLASS_TYPE (object_class),
+                                             G_SIGNAL_RUN_LAST,
+                                             G_STRUCT_OFFSET (EBookViewClass, contacts_removed),
+                                             NULL, NULL,
+                                             e_book_marshal_NONE__POINTER,
+                                             G_TYPE_NONE, 1, G_TYPE_POINTER);
+  signals [CONTACTS_ADDED] = g_signal_new ("contacts_added",
+                                           G_OBJECT_CLASS_TYPE (object_class),
+                                           G_SIGNAL_RUN_LAST,
+                                           G_STRUCT_OFFSET (EBookViewClass, contacts_added),
+                                           NULL, NULL,
+                                           e_book_marshal_NONE__POINTER,
+                                           G_TYPE_NONE, 1, G_TYPE_POINTER);
+  signals [SEQUENCE_COMPLETE] = g_signal_new ("sequence_complete",
+                                              G_OBJECT_CLASS_TYPE (object_class),
+                                              G_SIGNAL_RUN_LAST,
+                                              G_STRUCT_OFFSET (EBookViewClass, sequence_complete),
+                                              NULL, NULL,
+                                              e_book_marshal_NONE__INT,
+                                              G_TYPE_NONE, 1, G_TYPE_INT);
+  signals [STATUS_MESSAGE] = g_signal_new ("status_message",
+                                           G_OBJECT_CLASS_TYPE (object_class),
+                                           G_SIGNAL_RUN_LAST,
+                                           G_STRUCT_OFFSET (EBookViewClass, status_message),
+                                           NULL, NULL,
+                                           e_book_marshal_NONE__STRING,
+                                           G_TYPE_NONE, 1, G_TYPE_STRING);
 }
 
 static void
-e_book_view_do_removed_event (EBookView                 *book_view,
-			      EBookViewListenerResponse *resp)
+e_book_view_init (EBookView *view)
 {
-	g_signal_emit (book_view, e_book_view_signals [CONTACTS_REMOVED], 0,
-		       resp->ids);
+  EBookViewPrivate *priv = E_BOOK_VIEW_GET_PRIVATE (view);
+
+  priv->book = NULL;
+  priv->view_proxy = NULL;
+  priv->running = FALSE;
+
+  view->priv = priv;
 }
 
 static void
-e_book_view_do_complete_event (EBookView                 *book_view,
-			       EBookViewListenerResponse *resp)
+status_message_cb (DBusGProxy *proxy, const char *message, EBookView *book_view)
 {
-	g_signal_emit (book_view, e_book_view_signals [SEQUENCE_COMPLETE], 0,
-		       resp->status);
+  if (!book_view->priv->running)
+    return;
+
+  g_signal_emit (book_view, signals[STATUS_MESSAGE], 0, message);
 }
 
 static void
-e_book_view_do_status_message_event (EBookView                 *book_view,
-				     EBookViewListenerResponse *resp)
+contacts_added_cb (DBusGProxy *proxy, const char **vcards, EBookView *book_view)
 {
-	g_signal_emit (book_view, e_book_view_signals [STATUS_MESSAGE], 0,
-		       resp->message);
+  const char **p;
+  GList *contacts = NULL;
+
+  if (!book_view->priv->running)
+    return;
+
+  for (p = vcards; *p; p++) {
+    contacts = g_list_prepend (contacts, e_contact_new_from_vcard (*p));
+  }
+  contacts = g_list_reverse (contacts);
+
+  g_signal_emit (book_view, signals[CONTACTS_ADDED], 0, contacts);
+
+  g_list_foreach (contacts, (GFunc)g_object_unref, NULL);
+  g_list_free (contacts);
 }
 
+static void
+contacts_changed_cb (DBusGProxy *proxy, const char **vcards, EBookView *book_view)
+{
+  const char **p;
+  GList *contacts = NULL;
+
+  if (!book_view->priv->running)
+    return;
+
+  for (p = vcards; *p; p++) {
+    contacts = g_list_prepend (contacts, e_contact_new_from_vcard (*p));
+  }
+  contacts = g_list_reverse (contacts);
+
+  g_signal_emit (book_view, signals[CONTACTS_CHANGED], 0, contacts);
+
+  g_list_foreach (contacts, (GFunc)g_object_unref, NULL);
+  g_list_free (contacts);
+}
 
 static void
-e_book_view_handle_response (EBookViewListener *listener, EBookViewListenerResponse *resp, EBookView *book_view)
+contacts_removed_cb (DBusGProxy *proxy, const char **ids, EBookView *book_view)
 {
-	/* we shouldn't need this check.  EBVL only emits the signal when resp != NULL */
-	if (resp == NULL)
-		return;
-
-	switch (resp->op) {
-	case ContactsAddedEvent:
-		e_book_view_do_added_event (book_view, resp);
-		break;
-	case ContactsModifiedEvent:
-		e_book_view_do_modified_event (book_view, resp);
-		break;
-	case ContactsRemovedEvent:
-		e_book_view_do_removed_event (book_view, resp);
-		break;
-	case SequenceCompleteEvent:
-		e_book_view_do_complete_event (book_view, resp);
-		break;
-	case StatusMessageEvent:
-		e_book_view_do_status_message_event (book_view, resp);
-		break;
-	default:
-		g_error ("EBookView: Unknown operation %d in listener queue!\n",
-			 resp->op);
-		break;
-	}
-}
-
-static gboolean
-e_book_view_construct (EBookView *book_view, GNOME_Evolution_Addressbook_BookView corba_book_view, EBookViewListener *listener)
-{
-	CORBA_Environment  ev;
-	g_return_val_if_fail (book_view != NULL,     FALSE);
-	g_return_val_if_fail (E_IS_BOOK_VIEW (book_view), FALSE);
-
-	/*
-	 * Copy in the corba_book_view.
-	 */
-	CORBA_exception_init (&ev);
-
-	book_view->priv->corba_book_view = bonobo_object_dup_ref(corba_book_view, &ev);
-
-	if (ev._major != CORBA_NO_EXCEPTION) {
-		g_warning ("e_book_view_construct: Exception duplicating corba_book_view.\n");
-		CORBA_exception_free (&ev);
-		book_view->priv->corba_book_view = CORBA_OBJECT_NIL;
-		return FALSE;
-	}
-
-	CORBA_exception_free (&ev);
-
-	/*
-	 * Create our local BookListener interface.
-	 */
-	book_view->priv->listener = listener;
-	book_view->priv->response_id = g_signal_connect (book_view->priv->listener, "response",
-							 G_CALLBACK (e_book_view_handle_response), book_view);
+  const char **p;
+  GList *list = NULL;
+
+  if (!book_view->priv->running)
+    return;
+
+  for (p = ids; *p; p++) {
+    list = g_list_prepend (list, (char*)*p);
+  }
+  list = g_list_reverse (list);
 
-	bonobo_object_ref(BONOBO_OBJECT(book_view->priv->listener));
+  g_signal_emit (book_view, signals[CONTACTS_REMOVED], 0, list);
 
-	return TRUE;
+  /* No need to free the values, our caller will */
+  g_list_free (list);
 }
 
-/**
+static void
+complete_cb (DBusGProxy *proxy, guint status, EBookView *book_view)
+{
+  if (!book_view->priv->running)
+    return;
+
+  g_signal_emit (book_view, signals[SEQUENCE_COMPLETE], 0, status);
+}
+
+/*
  * e_book_view_new:
- * @corba_book_view: a CORBA BookView object
- * @listener: an #EBookViewListener
+ * @book: an #EBook
+ * @view_proxy: The #DBusGProxy to get signals from
  *
- * Creates a new #EBookView based on @corba_book_view and listening to
- * @listener.  This is a private function, applications should call
- * #e_book_get_book_view or #e_book_async_get_book_view.
+ * Creates a new #EBookView based on #EBook and listening to @view_proxy.  This
+ * is a private function, applications should call #e_book_get_book_view or
+ * #e_book_async_get_book_view.
  *
  * Return value: A new #EBookView.
  **/
-EBookView *
-e_book_view_new (GNOME_Evolution_Addressbook_BookView corba_book_view, EBookViewListener *listener)
+EBookView*
+_e_book_view_new (EBook *book, DBusGProxy *view_proxy)
 {
-	EBookView *book_view;
+  EBookView *view;
+  EBookViewPrivate *priv;
 
-	book_view = g_object_new (E_TYPE_BOOK_VIEW, NULL);
+  view = g_object_new (E_TYPE_BOOK_VIEW, NULL);
+  priv = view->priv;
 
-	if (! e_book_view_construct (book_view, corba_book_view, listener)) {
-		g_object_unref (book_view);
-		return NULL;
-	}
+  priv->book = g_object_ref (book);
 
-	return book_view;
-}
+  /* Take ownership of the view_proxy object */
+  priv->view_proxy = view_proxy;
+  g_object_add_weak_pointer (G_OBJECT (view_proxy), (gpointer)&priv->view_proxy);
 
-/**
- * e_book_view_set_book:
- * @book_view: an #EBookView
- * @book: an #EBook
- *
- * Makes @book_view listen to changes in @book. This function apparently
- * has no effect for the time being.
- **/
-void
-e_book_view_set_book (EBookView *book_view, EBook *book)
-{
-	g_return_if_fail (book_view && E_IS_BOOK_VIEW (book_view));
-	g_return_if_fail (book && E_IS_BOOK (book));
-	g_return_if_fail (book_view->priv->book == NULL);
+  dbus_g_proxy_add_signal (view_proxy, "StatusMessage", G_TYPE_STRING, G_TYPE_INVALID);
+  dbus_g_proxy_connect_signal (view_proxy, "StatusMessage", G_CALLBACK (status_message_cb), view, NULL);
+  dbus_g_proxy_add_signal (view_proxy, "ContactsAdded", G_TYPE_STRV, G_TYPE_INVALID);
+  dbus_g_proxy_connect_signal (view_proxy, "ContactsAdded", G_CALLBACK (contacts_added_cb), view, NULL);
+  dbus_g_proxy_add_signal (view_proxy, "ContactsChanged", G_TYPE_STRV, G_TYPE_INVALID);
+  dbus_g_proxy_connect_signal (view_proxy, "ContactsChanged", G_CALLBACK (contacts_changed_cb), view, NULL);
+  dbus_g_proxy_add_signal (view_proxy, "ContactsRemoved", G_TYPE_STRV, G_TYPE_INVALID);
+  dbus_g_proxy_connect_signal (view_proxy, "ContactsRemoved", G_CALLBACK (contacts_removed_cb), view, NULL);
+  dbus_g_proxy_add_signal (view_proxy, "Complete", G_TYPE_UINT, G_TYPE_INVALID);
+  dbus_g_proxy_connect_signal (view_proxy, "Complete", G_CALLBACK (complete_cb), view, NULL);
 
-	book_view->priv->book = book;
-	g_object_ref (book);
+  return view;
 }
 
-/**
- * e_book_view_get_book:
- * @book_view: an #EBookView
- *
- * Returns the #EBook that this book view is monitoring.
- *
- * Return value: an #EBook.
- **/
-EBook*
+EBook *
 e_book_view_get_book (EBookView *book_view)
 {
-	g_return_val_if_fail (book_view && E_IS_BOOK_VIEW (book_view), NULL);
+  g_return_val_if_fail (E_IS_BOOK_VIEW (book_view), NULL);
 
-	return book_view->priv->book;
+  return book_view->priv->book;
 }
 
 /**
@@ -214,19 +257,25 @@
 void
 e_book_view_start (EBookView *book_view)
 {
-	CORBA_Environment ev;
+  GError *error = NULL;
 
-	g_return_if_fail (book_view && E_IS_BOOK_VIEW (book_view));
+  g_return_if_fail (E_IS_BOOK_VIEW (book_view));
 
-	CORBA_exception_init (&ev);
+  book_view->priv->running = TRUE;
 
-	e_book_view_listener_start (book_view->priv->listener);
+  if (book_view->priv->view_proxy) {
+    org_gnome_evolution_dataserver_addressbook_BookView_start (book_view->priv->view_proxy, &error);
+    if (error) {
+      g_warning ("Cannot start book view: %s\n", error->message);
 
-	GNOME_Evolution_Addressbook_BookView_start (book_view->priv->corba_book_view, &ev);
+      /* Fake a sequence-complete so that the application knows this failed */
+      /* TODO: use get_status_from_error */
+      g_signal_emit (book_view, signals[SEQUENCE_COMPLETE], 0,
+		     E_BOOK_ERROR_CORBA_EXCEPTION);
 
-	if (ev._major != CORBA_NO_EXCEPTION) {
-		g_warning ("corba exception._major = %d\n", ev._major);
-	}
+      g_error_free (error);
+    }
+  }
 }
 
 /**
@@ -238,154 +287,17 @@
 void
 e_book_view_stop (EBookView *book_view)
 {
-	CORBA_Environment ev;
-
-	g_return_if_fail (book_view && E_IS_BOOK_VIEW (book_view));
-
-	CORBA_exception_init (&ev);
-
-	e_book_view_listener_stop (book_view->priv->listener);
-
-	GNOME_Evolution_Addressbook_BookView_stop (book_view->priv->corba_book_view, &ev);
-
-	if (ev._major != CORBA_NO_EXCEPTION) {
-		g_warning ("corba exception._major = %d\n", ev._major);
-	}
-}
-
-static void
-e_book_view_init (EBookView *book_view)
-{
-	book_view->priv                      = g_new0 (EBookViewPrivate, 1);
-	book_view->priv->book                = NULL;
-	book_view->priv->corba_book_view     = CORBA_OBJECT_NIL;
-	book_view->priv->listener            = NULL;
-	book_view->priv->response_id = 0;
-}
-
-static void
-e_book_view_dispose (GObject *object)
-{
-	EBookView             *book_view = E_BOOK_VIEW (object);
-	CORBA_Environment  ev;
-
-	if (book_view->priv) {
-		if (book_view->priv->book) {
-			g_object_unref (book_view->priv->book);
-		}
-
-		if (book_view->priv->corba_book_view) {
-			CORBA_exception_init (&ev);
-
-			GNOME_Evolution_Addressbook_BookView_dispose (book_view->priv->corba_book_view, &ev);
-
-			bonobo_object_release_unref (book_view->priv->corba_book_view, &ev);
-
-			if (ev._major != CORBA_NO_EXCEPTION) {
-				g_warning ("EBookView: Exception while releasing BookView\n");
-			}
-
-			CORBA_exception_free (&ev);
-		}
-
-		if (book_view->priv->listener) {
-			if (book_view->priv->response_id)
-				g_signal_handler_disconnect(book_view->priv->listener,
-							    book_view->priv->response_id);
-			e_book_view_listener_stop (book_view->priv->listener);
-			bonobo_object_unref (BONOBO_OBJECT(book_view->priv->listener));
-		}
-
-		g_free (book_view->priv);
-		book_view->priv = NULL;
-	}
-
-	G_OBJECT_CLASS(parent_class)->dispose (object);
-}
-
-static void
-e_book_view_class_init (EBookViewClass *klass)
-{
-	GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
-	parent_class = g_type_class_ref (G_TYPE_OBJECT);
-
-	e_book_view_signals [CONTACTS_CHANGED] =
-		g_signal_new ("contacts_changed",
-			      G_OBJECT_CLASS_TYPE (object_class),
-			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (EBookViewClass, contacts_changed),
-			      NULL, NULL,
-			      g_cclosure_marshal_VOID__POINTER,
-			      G_TYPE_NONE, 1,
-			      G_TYPE_POINTER);
-
-	e_book_view_signals [CONTACTS_ADDED] =
-		g_signal_new ("contacts_added",
-			      G_OBJECT_CLASS_TYPE (object_class),
-			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (EBookViewClass, contacts_added),
-			      NULL, NULL,
-			      g_cclosure_marshal_VOID__POINTER,
-			      G_TYPE_NONE, 1,
-			      G_TYPE_POINTER);
-
-	e_book_view_signals [CONTACTS_REMOVED] =
-		g_signal_new ("contacts_removed",
-			      G_OBJECT_CLASS_TYPE (object_class),
-			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (EBookViewClass, contacts_removed),
-			      NULL, NULL,
-			      g_cclosure_marshal_VOID__POINTER,
-			      G_TYPE_NONE, 1,
-			      G_TYPE_POINTER);
-
-	e_book_view_signals [SEQUENCE_COMPLETE] =
-		g_signal_new ("sequence_complete",
-			      G_OBJECT_CLASS_TYPE (object_class),
-			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (EBookViewClass, sequence_complete),
-			      NULL, NULL,
-			      g_cclosure_marshal_VOID__INT,
-			      G_TYPE_NONE, 1,
-			      G_TYPE_INT);
-
-	e_book_view_signals [STATUS_MESSAGE] =
-		g_signal_new ("status_message",
-			      G_OBJECT_CLASS_TYPE (object_class),
-			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (EBookViewClass, status_message),
-			      NULL, NULL,
-			      g_cclosure_marshal_VOID__STRING,
-			      G_TYPE_NONE, 1,
-			      G_TYPE_STRING);
-
-	object_class->dispose = e_book_view_dispose;
-}
-
-/**
- * e_book_view_get_type:
- */
-GType
-e_book_view_get_type (void)
-{
-	static GType type = 0;
+  GError *error = NULL;
 
-	if (! type) {
-		GTypeInfo info = {
-			sizeof (EBookViewClass),
-			NULL, /* base_class_init */
-			NULL, /* base_class_finalize */
-			(GClassInitFunc)  e_book_view_class_init,
-			NULL, /* class_finalize */
-			NULL, /* class_data */
-			sizeof (EBookView),
-			0,    /* n_preallocs */
-			(GInstanceInitFunc) e_book_view_init
-		};
+  g_return_if_fail (E_IS_BOOK_VIEW (book_view));
 
-		type = g_type_register_static (G_TYPE_OBJECT, "EBookView", &info, 0);
-	}
+  book_view->priv->running = FALSE;
 
-	return type;
+  if (book_view->priv->view_proxy) {
+    org_gnome_evolution_dataserver_addressbook_BookView_stop (book_view->priv->view_proxy, &error);
+    if (error) {
+      g_warning ("Cannot stop book view: %s\n", error->message);
+      g_error_free (error);
+    }
+  }
 }

Modified: branches/eds-dbus/addressbook/libebook/e-book.c
==============================================================================
--- branches/eds-dbus/addressbook/libebook/e-book.c	(original)
+++ branches/eds-dbus/addressbook/libebook/e-book.c	Fri Sep 12 17:21:22 2008
@@ -1,81 +1,52 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * Copyright (C) 2006 OpenedHand Ltd
+ *
+ * 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.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Author: Ross Burton <ross openedhand com>
+ */
 
 #include <config.h>
-
+#include <unistd.h>
 #include <string.h>
-
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <dbus/dbus-glib.h>
 #include "e-book.h"
+#include "e-error.h"
+#include "e-contact.h"
 #include "e-book-view-private.h"
-#include "e-vcard.h"
-
-#include <bonobo-activation/bonobo-activation.h>
-
-#include <bonobo/bonobo-exception.h>
-#include <bonobo/bonobo-main.h>
-#include <gconf/gconf-client.h>
-
-#include <glib/gi18n-lib.h>
-#include "libedataserver/e-flag.h"
-#include "libedataserver/e-component-listener.h"
-
-#include "e-book-listener.h"
-
-#define d(x)
-
-GMainContext *_ebook_context;
+#include "e-data-book-factory-bindings.h"
+#include "e-data-book-bindings.h"
+#include "libedata-book/e-data-book-types.h"
+#include "e-book-marshal.h"
+
+#define DBUS_API_SUBJECT_TO_CHANGE
+#include <dbus/dbus-glib-lowlevel.h>
+
+#define E_DATA_BOOK_FACTORY_SERVICE_NAME "org.gnome.evolution.dataserver.AddressBook"
+
+static char** flatten_stringlist(GList *list);
+static GList *array_to_stringlist (char **list);
+static gboolean unwrap_gerror(GError *error, GError **client_error);
+static EBookStatus get_status_from_error (GError *error);
 
-static GObjectClass *parent_class;
-
-#ifdef __PRETTY_FUNCTION__
-#define e_return_error_if_fail(expr,error_code,retval)	G_STMT_START{	\
-     if G_LIKELY(expr) { } else						\
-       {								\
-	 g_log (G_LOG_DOMAIN,						\
-		G_LOG_LEVEL_CRITICAL,					\
-		"file %s: line %d (%s): assertion `%s' failed",		\
-		__FILE__,						\
-		__LINE__,						\
-		__PRETTY_FUNCTION__,					\
-		#expr);							\
-	 g_set_error (error, E_BOOK_ERROR, (error_code),                \
-		"file %s: line %d (%s): assertion `%s' failed",		\
-		__FILE__,						\
-		__LINE__,						\
-		__PRETTY_FUNCTION__,					\
-		#expr);							\
-	 return (retval);						\
-       };				}G_STMT_END
-#else
-#define e_return_error_if_fail(expr,error_code,retval)	G_STMT_START{	\
-     if G_LIKELY(expr) { } else						\
-       {								\
-	 g_log (G_LOG_DOMAIN,						\
-		G_LOG_LEVEL_CRITICAL,					\
-		"file %s: line %d: assertion `%s' failed",		\
-		__FILE__,						\
-		__LINE__,						\
-		#expr);							\
-	 g_set_error (error, E_BOOK_ERROR, (error_code),                \
-		"file %s: line %d: assertion `%s' failed",		\
-		__FILE__,						\
-		__LINE__,						\
-		#expr);							\
-	 return (retval);						\
-       };				}G_STMT_END
-#endif
-
-/* XXX we need a better error message here */
-#define E_BOOK_CHECK_STATUS(status,error) G_STMT_START{			\
-	if ((status) == E_BOOK_ERROR_OK) {				\
-		return TRUE;						\
-	}								\
-	else {								\
-		g_set_error ((error), E_BOOK_ERROR, (status), "EBookStatus returned %d", (status));	\
-		return FALSE;						\
-	}				}G_STMT_END
+G_DEFINE_TYPE(EBook, e_book, G_TYPE_OBJECT)
+#define E_BOOK_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), E_TYPE_BOOK, EBookPrivate))
 
 enum {
-	OPEN_PROGRESS,
 	WRITABLE_STATUS,
 	CONNECTION_STATUS,
 	AUTH_REQUIRED,
@@ -85,684 +56,610 @@
 
 static guint e_book_signals [LAST_SIGNAL];
 
-typedef struct {
-	gint32 opid;
-	gint idle_id;
-	gboolean synchronous;
-	EFlag *flag;
-	EBook *book;
-	EBookStatus status;
-	char *id;
-	GList *list;
-	EList *elist;
-	EContact *contact;
-
-	EBookView *view;
-	EBookViewListener *listener;
-
-	/* callbacks/closure for async calls */
-	union {
-		EBookIdCallback id;
-		EBookCallback status;
-		EBookContactCallback contact;
-		EBookListCallback list;
-		EBookBookViewCallback book_view;
-		EBookEListCallback elist;
-	} cb;
-	gpointer closure;
-} EBookOp;
-
-typedef enum {
-	E_BOOK_SOURCE_NOT_LOADED,
-	E_BOOK_SOURCE_LOADING,
-	E_BOOK_SOURCE_LOADED
-} EBookLoadState;
-
 struct _EBookPrivate {
-	/* cached capabilites */
-	char *cap;
-	gboolean cap_queried;
-
-	/* cached writable status */
-	gboolean writable;
-	gboolean connected;
-
-	EBookListener         *listener;
-	EComponentListener    *comp_listener;
-
-	GNOME_Evolution_Addressbook_Book         corba_book;
-
-	EBookLoadState         load_state;
-
-	GList *pending_idles;
-	GHashTable *id_to_op;
-	guint32 current_op_id;
-
-	GMutex *mutex;
-
-	/* Need to keep URI around, since the getter returns const */
-	gchar *uri;
-	ESource *source;
+  ESource *source;
+  char *uri;
+  DBusGProxy *proxy;
+  gboolean loaded;
+  gboolean writable;
+  gboolean connected;
+  char *cap;
+  gboolean cap_queried;
+};
 
-	gulong listener_signal;
-	gulong died_signal;
+static DBusGConnection *connection = NULL;
+static DBusGProxy *factory_proxy = NULL;
 
-	gint writable_idle_id;
-	gint connection_idle_id;
-	gint auth_idle_id;
-};
+typedef struct {
+  EBook *book;
+  void *callback; /* TODO union */
+  gpointer closure;
+  gpointer data;
+} AsyncData;
 
-
-/* Error quark */
 GQuark
 e_book_error_quark (void)
 {
   static GQuark q = 0;
   if (q == 0)
     q = g_quark_from_static_string ("e-book-error-quark");
-
   return q;
 }
 
-
-
-/* EBookOp calls */
-
-static EBookOp*
-e_book_new_op (EBook *book, gboolean sync)
+/*
+ * Called when the addressbook server dies.
+ */
+static void
+proxy_destroyed (gpointer data, GObject *object)
 {
-	EBookOp *op = g_new0 (EBookOp, 1);
+  EBook *book = data;
 
-	op->flag = e_flag_new ();
+  g_assert (E_IS_BOOK (book));
 
-	op->synchronous = sync;
-	op->opid = book->priv->current_op_id++;
+  g_warning (G_STRLOC ": e-d-s proxy died");
 
-	g_hash_table_insert (book->priv->id_to_op,
-			     &op->opid, op);
+  /* Ensure that everything relevant is NULL */
+  factory_proxy = NULL;
+  book->priv->proxy = NULL;
 
-	return op;
+  g_signal_emit (G_OBJECT (book), e_book_signals [BACKEND_DIED], 0);
 }
 
-static EBookOp*
-e_book_get_op (EBook *book, int opid)
+static void
+e_book_dispose (GObject *object)
 {
-	return (EBookOp*)g_hash_table_lookup (book->priv->id_to_op,
-					      &opid);
-}
+  EBook *book = E_BOOK (object);
 
-static EBookOp*
-e_book_get_current_sync_op (EBook *book)
-{
-	guint32 opid = 0;
-	return (EBookOp*)g_hash_table_lookup (book->priv->id_to_op,
-					      &opid);
+  book->priv->loaded = FALSE;
+
+  if (book->priv->proxy) {
+    g_object_weak_unref (G_OBJECT (book->priv->proxy), proxy_destroyed, book);
+    org_gnome_evolution_dataserver_addressbook_Book_close (book->priv->proxy, NULL);
+  }
+  if (book->priv->source) {
+    g_object_unref (book->priv->source);
+    book->priv->source = NULL;
+  }
+  if (book->priv->proxy) {
+    g_object_unref (book->priv->proxy);
+    book->priv->proxy = NULL;
+  }
+
+  if (G_OBJECT_CLASS (e_book_parent_class)->dispose)
+    G_OBJECT_CLASS (e_book_parent_class)->dispose (object);
 }
 
 static void
-e_book_op_free (EBookOp *op)
+e_book_finalize (GObject *object)
 {
-	e_flag_free (op->flag);
-	g_free (op);
+  EBook *book = E_BOOK (object);
+
+  if (book->priv->uri)
+    g_free (book->priv->uri);
+
+  if (book->priv->cap)
+    g_free (book->priv->cap);
+
+  if (G_OBJECT_CLASS (e_book_parent_class)->finalize)
+    G_OBJECT_CLASS (e_book_parent_class)->finalize (object);
 }
 
 static void
-e_book_op_remove (EBook *book,
-		  EBookOp *op)
+e_book_class_init (EBookClass *e_book_class)
 {
-	g_hash_table_remove (book->priv->id_to_op,
-			     &op->opid);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (e_book_class);
+
+  e_book_signals [WRITABLE_STATUS] =
+		g_signal_new ("writable_status",
+			      G_OBJECT_CLASS_TYPE (gobject_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (EBookClass, writable_status),
+			      NULL, NULL,
+			      e_book_marshal_NONE__BOOL,
+			      G_TYPE_NONE, 1,
+			      G_TYPE_BOOLEAN);
+  
+  e_book_signals [CONNECTION_STATUS] =
+    g_signal_new ("connection_status",
+                  G_OBJECT_CLASS_TYPE (gobject_class),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (EBookClass, connection_status),
+                  NULL, NULL,
+                  e_book_marshal_NONE__BOOL,
+                  G_TYPE_NONE, 1,
+                  G_TYPE_BOOLEAN);
+  
+  e_book_signals [AUTH_REQUIRED] =
+    g_signal_new ("auth_required",
+                  G_OBJECT_CLASS_TYPE (gobject_class),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (EBookClass, auth_required),
+                  NULL, NULL,
+                  e_book_marshal_NONE__NONE,
+                  G_TYPE_NONE, 0);
+
+  e_book_signals [BACKEND_DIED] =
+    g_signal_new ("backend_died",
+                  G_OBJECT_CLASS_TYPE (gobject_class),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (EBookClass, backend_died),
+                  NULL, NULL,
+                  e_book_marshal_NONE__NONE,
+                  G_TYPE_NONE, 0);
+  
+  gobject_class->dispose = e_book_dispose;
+  gobject_class->finalize = e_book_finalize;
+
+  g_type_class_add_private (e_book_class, sizeof (EBookPrivate));
 }
 
 static void
-e_book_clear_op (EBook *book,
-		 EBookOp *op)
+e_book_init (EBook *book)
 {
-	e_book_op_remove (book, op);
-	e_flag_clear (op->flag);
-	e_book_op_free (op);
+  EBookPrivate *priv = E_BOOK_GET_PRIVATE (book);
+  priv->source = NULL;
+  priv->uri = NULL;
+  priv->proxy = NULL;
+  priv->loaded = FALSE;
+  priv->writable = FALSE;
+  priv->connected = FALSE;
+  priv->cap = NULL;
+  priv->cap_queried = FALSE;
+  book->priv = priv;
 }
 
-
+/* one-time start up for libebook */
 static gboolean
-do_add_contact (gboolean          sync,
-		EBook            *book,
-		EContact         *contact,
-		GError          **error,  /* for sync case */
-		EBookIdCallback   cb, /* for async case */
-		gpointer          closure)
-{
-	EBookOp *our_op;
-	EBookStatus status;
-	CORBA_Environment ev;
-	char *vcard_str;
-
-	d(printf ("do_add_contact\n"));
-
-	g_mutex_lock (book->priv->mutex);
-
-	if (book->priv->load_state != E_BOOK_SOURCE_LOADED) {
-		g_mutex_unlock (book->priv->mutex);
-		if (error) {
-			g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_SOURCE_NOT_LOADED,
-				     /* translators: the placeholders will be filled by
-				      * function names, e.g.
-				      * "e_book_add_contact" on book before
-				      * "e_book_open */
-				     _("\"%s\" on book before \"%s\""),
-				     "e_book_add_contact", "e_book_open");
-		}
-		else {
-			g_warning (_("\"%s\" on book before \"%s\""),
-				   "e_book_add_contact", "e_book_open");
-		}
-		return FALSE;
-	}
-
-	if (sync && e_book_get_current_sync_op (book) != NULL) {
-		g_mutex_unlock (book->priv->mutex);
-		g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY,
-			     _("book busy"));
-		return FALSE;
-	}
-
-	our_op = e_book_new_op (book, sync);
+e_book_activate(GError **error)
+{
+  DBusError derror;
 
-	g_mutex_unlock (book->priv->mutex);
+  if (G_LIKELY (factory_proxy)) {
+    return TRUE;
+  }
 
-	vcard_str = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
+  if (!connection) {
+    connection = dbus_g_bus_get (DBUS_BUS_SESSION, error);
+    if (!connection)
+      return FALSE;
+  }
 
-	CORBA_exception_init (&ev);
+  dbus_error_init (&derror);
+  if (!dbus_bus_start_service_by_name (dbus_g_connection_get_connection (connection),
+                                       E_DATA_BOOK_FACTORY_SERVICE_NAME,
+                                       0, NULL, &derror)) {
+    dbus_set_g_error (error, &derror);
+    dbus_error_free (&derror);
+    return FALSE;
+  }
 
-	our_op->cb.id = cb;
-	our_op->closure = closure;
+  if (!factory_proxy) {
+    factory_proxy = dbus_g_proxy_new_for_name_owner (connection,
+                                                     E_DATA_BOOK_FACTORY_SERVICE_NAME,
+                                                     "/org/gnome/evolution/dataserver/addressbook/BookFactory",
+                                                     "org.gnome.evolution.dataserver.addressbook.BookFactory",
+                                                     error);
+    if (!factory_proxy) {
+      return FALSE;
+    }
+    g_object_add_weak_pointer (G_OBJECT (factory_proxy), (gpointer)&factory_proxy);
+  }
 
-	/* will eventually end up calling e_book_response_add_contact */
-	GNOME_Evolution_Addressbook_Book_addContact (book->priv->corba_book, our_op->opid,
-						     (const GNOME_Evolution_Addressbook_VCard) vcard_str, &ev);
+  return TRUE;
+}
 
-	g_free (vcard_str);
+static void
+writable_cb (DBusGProxy *proxy, gboolean writable, EBook *book)
+{
+  g_return_if_fail (E_IS_BOOK (book));
 
-	if (ev._major != CORBA_NO_EXCEPTION) {
+  book->priv->writable = writable;
 
-		g_mutex_lock (book->priv->mutex);
-		e_book_clear_op (book, our_op);
-		g_mutex_unlock (book->priv->mutex);
+  g_signal_emit (G_OBJECT (book), e_book_signals [WRITABLE_STATUS], 0, writable);
+}
 
-		CORBA_exception_free (&ev);
+static void
+connection_cb (DBusGProxy *proxy, gboolean connected, EBook *book)
+{
+  g_return_if_fail (E_IS_BOOK (book));
 
-		if (error) {
-			g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION,
-				     _("CORBA exception making \"%s\" call"),
-				     "Book::addContact");
-		}
-		else {
-			g_warning (_("CORBA exception making \"%s\" call"),
-				   "Book::addContact");
-		}
-		return FALSE;
-	}
+  book->priv->connected = connected;
 
-	CORBA_exception_free (&ev);
+  g_signal_emit (G_OBJECT (book), e_book_signals [CONNECTION_STATUS], 0, connected);
+}
 
-	if (sync) {
-		/* wait for something to happen (both cancellation and a
-		   successful response will notity us via our cv */
-		e_flag_wait (our_op->flag);
-
-		status = our_op->status;
-		e_contact_set (contact, E_CONTACT_UID, our_op->id);
-		g_free (our_op->id);
-
-		g_mutex_lock (book->priv->mutex);
-		e_book_clear_op (book, our_op);
-		g_mutex_unlock (book->priv->mutex);
+static void
+auth_required_cb (DBusGProxy *proxy, EBook *book)
+{
+  g_return_if_fail (E_IS_BOOK (book));
 
-		E_BOOK_CHECK_STATUS (status, error);
-	}
-	else {
-		return TRUE;
-	}
+  g_signal_emit (G_OBJECT (book), e_book_signals [AUTH_REQUIRED], 0);
 }
 
 /**
- * e_book_add_contact:
- * @book: an #EBook
- * @contact: an #EContact
- * @error: a #GError to set on failure
+ * e_book_get_addressbooks:
+ * @addressbook_sources: A pointer to a ESourceList* to set
+ * @error: A pointer to a GError* to set on error
  *
- * Adds @contact to @book.
+ * Populate *addressbook_sources with the list of all sources which have been
+ * added to Evolution.
  *
- * Return value: %TRUE if successful, %FALSE otherwise.
- **/
+ * Return value: %TRUE if @addressbook_sources was set, otherwise %FALSE.
+ */
 gboolean
-e_book_add_contact (EBook           *book,
-		    EContact        *contact,
-		    GError         **error)
-{
-	d(printf ("e_book_add_contact\n"));
-
-	e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG, FALSE);
-	e_return_error_if_fail (contact && E_IS_CONTACT (contact), E_BOOK_ERROR_INVALID_ARG, FALSE);
-
-	return do_add_contact (TRUE,
-			       book, contact, error,
-			       NULL, NULL);
+e_book_get_addressbooks (ESourceList **addressbook_sources, GError **error)
+{
+	GConfClient *gconf;
+	
+	e_return_error_if_fail (addressbook_sources, E_BOOK_ERROR_INVALID_ARG);
+
+	gconf = gconf_client_get_default();
+	*addressbook_sources = e_source_list_new_for_gconf (gconf, "/apps/evolution/addressbook/sources");
+	g_object_unref (gconf);
+
+	return TRUE;
 }
 
 /**
- * e_book_async_add_contact:
- * @book: an #EBook
- * @contact: an #EContact
- * @cb: function to call when the operation finishes
- * @closure: data to pass to callback function
+ * e_book_new:
+ * @source: An #ESource pointer
+ * @error: A #GError pointer
  *
- * Adds @contact to @book without blocking.
+ * Creates a new #EBook corresponding to the given source.  There are
+ * only two operations that are valid on this book at this point:
+ * e_book_open(), and e_book_remove().
  *
- * Return value: %TRUE if the operation was started, %FALSE otherwise.
- **/
-gboolean
-e_book_async_add_contact (EBook                 *book,
-			  EContact              *contact,
-			  EBookIdCallback        cb,
-			  gpointer               closure)
+ * Return value: a new but unopened #EBook.
+ */
+EBook*
+e_book_new (ESource *source, GError **error)
 {
-	d(printf ("e_book_async_add_contact\n"));
-
-	g_return_val_if_fail (book && E_IS_BOOK (book), FALSE);
-	g_return_val_if_fail (contact && E_IS_CONTACT (contact), FALSE);
+  GError *err = NULL;
+  EBook *book;
+  char *path;
+  
+  e_return_error_if_fail (E_IS_SOURCE (source), E_BOOK_ERROR_INVALID_ARG);
+  
+  if (!e_book_activate (&err)) {
+    g_warning (G_STRLOC ": cannot activate book: %s\n", err->message);
+    g_propagate_error (error, err);
+    return NULL;
+  }
+
+  book = g_object_new (E_TYPE_BOOK, NULL);
+
+  book->priv->source = g_object_ref (source);
+  book->priv->uri = e_source_get_uri (source);
+  
+  if (!org_gnome_evolution_dataserver_addressbook_BookFactory_get_book (factory_proxy, book->priv->uri, &path, &err)) {
+    g_warning (G_STRLOC ": cannot get book from factory: %s", err ? err->message : "[no error]");
+    g_propagate_error (error, err);
+    g_object_unref (book);
+    return NULL;
+  }
+  
+  book->priv->proxy = dbus_g_proxy_new_for_name_owner (connection,
+                                                       E_DATA_BOOK_FACTORY_SERVICE_NAME, path,
+                                                       "org.gnome.evolution.dataserver.addressbook.Book",
+                                                       &err);
+  if (!book->priv->proxy) {
+    g_warning (G_STRLOC ": cannot get proxy for book %s: %s", path, err->message);
+    g_propagate_error (error, err);
+    g_free (path);
+    g_object_unref (book);
+    return NULL;
+  }
+  g_free (path);
+
+  g_object_weak_ref (G_OBJECT (book->priv->proxy), proxy_destroyed, book);
+
+  dbus_g_proxy_add_signal (book->priv->proxy, "writable", G_TYPE_BOOLEAN, G_TYPE_INVALID);
+  dbus_g_proxy_connect_signal (book->priv->proxy, "writable", G_CALLBACK (writable_cb), book, NULL);
+  dbus_g_proxy_add_signal (book->priv->proxy, "connection", G_TYPE_BOOLEAN, G_TYPE_INVALID);
+  dbus_g_proxy_connect_signal (book->priv->proxy, "connection", G_CALLBACK (connection_cb), book, NULL);
+  dbus_g_proxy_add_signal (book->priv->proxy, "auth_required", G_TYPE_INVALID);
+  dbus_g_proxy_connect_signal (book->priv->proxy, "auth_required", G_CALLBACK (auth_required_cb), book, NULL);
 
-	return !do_add_contact (FALSE,
-				book, contact, NULL,
-				cb, closure);
+  return book;
 }
 
-static gboolean
-emit_async_add_contact_response (gpointer data)
+/**
+ * e_book_new_from_uri:
+ * @uri: the URI to load
+ * @error: A #GError pointer
+ *
+ * Creates a new #EBook corresponding to the given uri.  See the
+ * documentation for e_book_new for further information.
+ *
+ * Return value: a new but unopened #EBook.
+ */
+EBook*
+e_book_new_from_uri (const char *uri, GError **error)
 {
-	EBookOp *op = data;
-	EBook *book = op->book;
-
-	if (op->cb.id)
-		op->cb.id (book, op->status, op->id, op->closure);
-
-	g_mutex_lock (book->priv->mutex);
-
-	g_free (op->id);
-
-	book->priv->pending_idles = g_list_remove (book->priv->pending_idles,
-						   GINT_TO_POINTER (op->idle_id));
-
-	e_book_clear_op (book, op);
-
-	g_mutex_unlock (book->priv->mutex);
-	g_object_unref (book);
-
-	return FALSE;
+  ESource *source;
+  EBook *book;
+  
+  e_return_error_if_fail (uri, E_BOOK_ERROR_INVALID_ARG);
+  
+  source = e_source_new_with_absolute_uri ("", uri);
+  
+  book = e_book_new (source, error);
+  
+  g_object_unref (source);
+  
+  return book;
 }
 
-static void
-e_book_response_add_contact (EBook       *book,
-			     guint32      opid,
-			     EBookStatus  status,
-			     char        *id)
+/**
+ * e_book_new_system_addressbook:
+ * @uri: the URI to load
+ * @error: A #GError pointer
+ *
+ * Creates a new #EBook corresponding to the user's system
+ * addressbook.  See the documentation for e_book_new for further
+ * information.
+ *
+ * Return value: a new but unopened #EBook.
+ */
+EBook*
+e_book_new_system_addressbook (GError **error)
 {
-	EBookOp *op;
-
-	d(printf ("e_book_response_add_contact\n"));
-
-	g_mutex_lock (book->priv->mutex);
-
-	op = e_book_get_op (book, opid);
-
-	if (op == NULL) {
-		g_mutex_unlock (book->priv->mutex);
-		g_warning ("e_book_response_add_contact: Cannot find operation ");
-		return;
-	}
-
-	op->id = g_strdup (id);
-	op->status = status;
-
-	if (op->synchronous)
-		e_flag_set (op->flag);
-	else {
-		op->book = g_object_ref (book);
+	ESourceList *sources;
+	GSList *g;
+	ESource *system_source = NULL;
+	EBook *book = NULL;
 
-		op->idle_id = g_idle_add (emit_async_add_contact_response, op);
-		book->priv->pending_idles = g_list_prepend (book->priv->pending_idles,
-							    GINT_TO_POINTER (op->idle_id));
+	if (!e_book_get_addressbooks (&sources, error)) {
+		return FALSE;
 	}
 
-	g_mutex_unlock (book->priv->mutex);
-}
-
-
+	for (g = e_source_list_peek_groups (sources); g; g = g->next) {
+		ESourceGroup *group = E_SOURCE_GROUP (g->data);
+		GSList *s;
+		for (s = e_source_group_peek_sources (group); s; s = s->next) {
+			ESource *source = E_SOURCE (s->data);
 
-static gboolean
-do_commit_contact (gboolean        sync,
-		   EBook          *book,
-		   EContact       *contact,
-		   GError        **error,
-		   EBookCallback   cb,
-		   gpointer        closure)
-{
-	EBookOp *our_op;
-	EBookStatus status;
-	CORBA_Environment ev;
-	char *vcard_str;
-
-	g_mutex_lock (book->priv->mutex);
-
-	if (book->priv->load_state != E_BOOK_SOURCE_LOADED) {
-		g_mutex_unlock (book->priv->mutex);
-		if (error) {
-			g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_SOURCE_NOT_LOADED,
-				     _("\"%s\" on book before \"%s\""),
-				     "e_book_commit_contact", "e_book_open");
-		}
-		else {
-			g_warning (_("\"%s\" on book before \"%s\""),
-				   "e_book_commit_contact", "e_book_open");
+			if (e_source_get_property (source, "system")) {
+				system_source = source;
+				break;
+			}
 		}
-		return FALSE;
-	}
 
-	if (sync && e_book_get_current_sync_op (book) != NULL) {
-		g_mutex_unlock (book->priv->mutex);
-		g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY,
-			     _("book busy"));
-		return FALSE;
+		if (system_source)
+			break;
 	}
 
-	vcard_str = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
-
-	our_op = e_book_new_op (book, sync);
+	if (system_source) {
+		book = e_book_new (system_source, error);
+	}
+	else {
+		char *filename;
+		char *uri;
 
-	g_mutex_unlock (book->priv->mutex);
+		filename = g_build_filename (g_get_home_dir(),
+					     ".evolution/addressbook/local/system",
+					     NULL);
+		uri = g_strdup_printf ("file://%s", filename);
 
-	CORBA_exception_init (&ev);
+		g_free (filename);
+	
+		book = e_book_new_from_uri (uri, error);
 
-	our_op->cb.status = cb;
-	our_op->closure = closure;
+		g_free (uri);
+	}
 
-	/* will eventually end up calling _e_book_response_generic */
-	GNOME_Evolution_Addressbook_Book_modifyContact (book->priv->corba_book, our_op->opid,
-							(const GNOME_Evolution_Addressbook_VCard) vcard_str, &ev);
+	g_object_unref (sources);
 
-	g_free (vcard_str);
+	return book;
+}
 
-	if (ev._major != CORBA_NO_EXCEPTION) {
+/**
+ * e_book_new_default_addressbook:
+ * @uri: the URI to load
+ * @error: A #GError pointer
+ *
+ * Creates a new #EBook corresponding to the user's default
+ * addressbook.  See the documentation for e_book_new for further
+ * information.
+ *
+ * Return value: a new but unopened #EBook.
+ */
+EBook*
+e_book_new_default_addressbook   (GError **error)
+{
+	ESourceList *sources;
+	GSList *g;
+	ESource *default_source = NULL;
+	EBook *book;
 
-		g_mutex_lock (book->priv->mutex);
-		e_book_clear_op (book, our_op);
-		g_mutex_unlock (book->priv->mutex);
+	if (!e_book_get_addressbooks (&sources, error)) {
+		return FALSE;
+	}
 
-		CORBA_exception_free (&ev);
+	for (g = e_source_list_peek_groups (sources); g; g = g->next) {
+		ESourceGroup *group = E_SOURCE_GROUP (g->data);
+		GSList *s;
+		for (s = e_source_group_peek_sources (group); s; s = s->next) {
+			ESource *source = E_SOURCE (s->data);
 
-		if (error) {
-			g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION,
-				     _("CORBA exception making \"%s\" call"),
-				     "Book::modifyContact");
-		}
-		else {
-			g_warning (_("CORBA exception making \"%s\" call"),
-				   "Book::modifyContact");
+			if (e_source_get_property (source, "default")) {
+				default_source = source;
+				break;
+			}
 		}
-		return FALSE;
+
+		if (default_source)
+			break;
 	}
 
-	CORBA_exception_free (&ev);
+	if (default_source)
+		book = e_book_new (default_source, error);
+	else
+		book = e_book_new_system_addressbook (error);
 
-	if (sync) {
-		/* wait for something to happen (both cancellation and a
-		   successful response will notity us via our cv */
-		e_flag_wait (our_op->flag);
-
-		status = our_op->status;
-		g_free (our_op->id);
-
-		/* remove the op from the book's hash of operations */
-		g_mutex_lock (book->priv->mutex);
-		e_book_clear_op (book, our_op);
-		g_mutex_unlock (book->priv->mutex);
+	g_object_unref (sources);
 
-		E_BOOK_CHECK_STATUS (status, error);
-	}
-	else {
-		return TRUE;
-	}
+	return book;
 }
 
-
 /**
- * e_book_commit_contact:
+ * e_book_get_source:
  * @book: an #EBook
- * @contact: an #EContact
- * @error: a #GError to set on failure
  *
- * Applies the changes made to @contact to the stored version in
- * @book.
+ * Get the #ESource that this book has loaded.
  *
- * Return value: %TRUE if successful, %FALSE otherwise
- **/
-gboolean
-e_book_commit_contact (EBook           *book,
-		       EContact        *contact,
-		       GError         **error)
-{
-	e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG, FALSE);
-	e_return_error_if_fail (contact && E_IS_CONTACT (contact), E_BOOK_ERROR_INVALID_ARG, FALSE);
-
-	return do_commit_contact (TRUE,
-				  book, contact, error,
-				  NULL, NULL);
+ * Return value: The source.
+ */
+ESource*
+e_book_get_source (EBook *book)
+{
+  g_return_val_if_fail (E_IS_BOOK (book), NULL);
 
+  return book->priv->source;
 }
 
 /**
- * e_book_async_commit_contact:
+ * e_book_open:
  * @book: an #EBook
- * @contact: an #EContact
- * @cb: function to call when the operation finishes
- * @closure: data to pass to callback function
+ * @only_if_exists: if %TRUE, fail if this book doesn't already exist, otherwise create it first
+ * @error: a #GError to set on failure
  *
- * Applies the changes made to @contact to the stored version in
- * @book without blocking.
+ * Opens the addressbook, making it ready for queries and other operations.
  *
- * Return value: %TRUE if the operation was started, %FALSE otherwise.
- **/
-guint
-e_book_async_commit_contact (EBook                 *book,
-			     EContact              *contact,
-			     EBookCallback          cb,
-			     gpointer               closure)
-{
-	return !do_commit_contact (FALSE,
-				   book, contact, NULL,
-				   cb, closure);
-}
-
-static gboolean
-do_get_required_fields (gboolean             sync,
-			 EBook               *book,
-			 GList              **fields,
-			 GError             **error,
-			 EBookEListCallback   cb,
-			 gpointer             closure)
-{
-	EBookOp *our_op;
-	EBookStatus status;
-	CORBA_Environment ev;
-
-	g_mutex_lock (book->priv->mutex);
-
-	if (book->priv->load_state != E_BOOK_SOURCE_LOADED) {
-		g_mutex_unlock (book->priv->mutex);
-		if (error) {
-			g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_SOURCE_NOT_LOADED,
-				     _("\"%s\" on book before \"%s\""),
-				     "e_book_get_required_fields", "e_book_open");
-		}
-		else {
-			g_warning (_("\"%s\" on book before \"%s\""),
-				   "e_book_get_required_fields", "e_book_open");
-		}
-		return FALSE;
-	}
-
-	if (sync && e_book_get_current_sync_op (book) != NULL) {
-		g_mutex_unlock (book->priv->mutex);
-		g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY,
-			     _("book busy"));
-		return FALSE;
-	}
-
-	our_op = e_book_new_op (book, sync);
-
-	g_mutex_unlock (book->priv->mutex);
-
-	CORBA_exception_init (&ev);
-
-	our_op->cb.elist = cb;
-	our_op->closure = closure;
-
-	/* will eventually end up calling
-	   _e_book_response_get_supported_fields */
-	GNOME_Evolution_Addressbook_Book_getRequiredFields(book->priv->corba_book, our_op->opid, &ev);
-
-	if (ev._major != CORBA_NO_EXCEPTION) {
-
-		g_mutex_lock (book->priv->mutex);
-		e_book_clear_op (book, our_op);
-		g_mutex_unlock (book->priv->mutex);
-
-		CORBA_exception_free (&ev);
-
-		if (error) {
-			g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION,
-				     _("CORBA exception making \"%s\" call"),
-				     "Book::getRequiredFields");
-		}
-		else {
-			g_warning (_("CORBA exception making \"%s\" call"),
-				   "Book::getRequiredFields");
-		}
-
-		return FALSE;
-	}
-
-
-	CORBA_exception_free (&ev);
-
-	if (sync) {
-		/* wait for something to happen (both cancellation and a
-		   successful response will notify us via our cv */
-		e_flag_wait (our_op->flag);
-
-		status = our_op->status;
-		*fields = our_op->list;
+ * Return value: %TRUE if the book was successfully opened, %FALSE otherwise.
+ */
+gboolean
+e_book_open (EBook *book, gboolean only_if_exists, GError **error)
+{
+  GError *err = NULL;
+  EBookStatus status;
 
-		g_mutex_lock (book->priv->mutex);
-		e_book_clear_op (book, our_op);
-		g_mutex_unlock (book->priv->mutex);
+  e_return_error_if_fail (E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
+  e_return_error_if_fail (book->priv->proxy, E_BOOK_ERROR_REPOSITORY_OFFLINE);
+  
+  if (!org_gnome_evolution_dataserver_addressbook_Book_open (book->priv->proxy, only_if_exists, &err)) {
+    g_propagate_error (error, err);
+    return FALSE;
+  }
 
-		E_BOOK_CHECK_STATUS (status, error);
-	}
-	else {
-		return TRUE;
-	}
+  status = get_status_from_error (err);
+  
+  if (status == E_BOOK_ERROR_OK) {
+    book->priv->loaded = TRUE;
+    return TRUE;
+  } else {
+    g_propagate_error (error, err);
+    return FALSE;
+  }
 }
 
-static gboolean
-do_get_supported_fields (gboolean             sync,
-			 EBook               *book,
-			 GList              **fields,
-			 GError             **error,
-			 EBookEListCallback   cb,
-			 gpointer             closure)
-{
-	EBookOp *our_op;
-	EBookStatus status;
-	CORBA_Environment ev;
-
-	g_mutex_lock (book->priv->mutex);
-
-	if (book->priv->load_state != E_BOOK_SOURCE_LOADED) {
-		g_mutex_unlock (book->priv->mutex);
-		if (error) {
-			g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_SOURCE_NOT_LOADED,
-				     _("\"%s\" on book before \"%s\""),
-				     "e_book_get_supported_fields", "e_book_open");
-		}
-		else {
-			g_warning (_("\"%s\" on book before \"%s\""),
-				   "e_book_get_supported_fields", "e_book_open");
-		}
-		return FALSE;
-	}
-
-	if (sync && e_book_get_current_sync_op (book) != NULL) {
-		g_mutex_unlock (book->priv->mutex);
-		g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY,
-			     _("book busy"));
-		return FALSE;
-	}
+static void
+open_reply(DBusGProxy *proxy, GError *error, gpointer user_data)
+{
+  AsyncData *data = user_data;
+  EBookCallback cb = data->callback;
+  EDataBookStatus status;
 
-	our_op = e_book_new_op (book, sync);
+  status = get_status_from_error (error);
 
-	g_mutex_unlock (book->priv->mutex);
+  data->book->priv->loaded = (status == E_BOOK_ERROR_OK);
 
-	CORBA_exception_init (&ev);
+  if (cb)
+    cb (data->book, status, data->closure);
 
-	our_op->cb.elist = cb;
-	our_op->closure = closure;
+  g_object_unref (data->book);
+  g_slice_free (AsyncData, data);
+}
 
-	/* will eventually end up calling
-	   _e_book_response_get_supported_fields */
-	GNOME_Evolution_Addressbook_Book_getSupportedFields(book->priv->corba_book, our_op->opid, &ev);
+/**
+ * e_book_async_open:
+ * @book: an #EBook
+ * @only_if_exists: if %TRUE, fail if this book doesn't already exist, otherwise create it first
+ * @open_response: a function to call when the operation finishes
+ * @closure: data to pass to callback function
+ *
+ * Opens the addressbook, making it ready for queries and other operations.
+ * This function does not block.
+ *
+ * Return value: %FALSE if successful, %TRUE otherwise.
+ **/
+guint
+e_book_async_open (EBook *book, gboolean only_if_exists, EBookCallback cb, gpointer closure)
+{
+  AsyncData *data;
 
-	if (ev._major != CORBA_NO_EXCEPTION) {
+  e_return_async_error_if_fail (E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
+  e_return_async_error_if_fail (book->priv->proxy, E_BOOK_ERROR_REPOSITORY_OFFLINE);
 
-		g_mutex_lock (book->priv->mutex);
-		e_book_clear_op (book, our_op);
-		g_mutex_unlock (book->priv->mutex);
+  data = g_slice_new0 (AsyncData);
+  data->book = g_object_ref (book);
+  data->callback = cb;
+  data->closure = closure;
 
-		CORBA_exception_free (&ev);
+  org_gnome_evolution_dataserver_addressbook_Book_open_async (book->priv->proxy, only_if_exists, open_reply, data);
+  return 0;
+}
 
-		if (error) {
-			g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION,
-				     _("CORBA exception making \"%s\" call"),
-				     "Book::getSupportedFields");
-		}
-		else {
-			g_warning (_("CORBA exception making \"%s\" call"),
-				   "Book::getSupportedFields");
-		}
+/**
+ * e_book_remove:
+ * @book: an #EBook
+ * @error: a #GError to set on failure
+ *
+ * Removes the backing data for this #EBook. For example, with the file backend this
+ * deletes the database file. You cannot get it back!
+ *
+ * Return value: %TRUE on success, %FALSE on failure.
+ */
+gboolean
+e_book_remove (EBook *book, GError **error)
+{
+  GError *err = NULL;
 
-		return FALSE;
-	}
+  e_return_error_if_fail (E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
+  e_return_error_if_fail (book->priv->proxy, E_BOOK_ERROR_REPOSITORY_OFFLINE);
+  
+  org_gnome_evolution_dataserver_addressbook_Book_remove (book->priv->proxy, &err);
+  return unwrap_gerror (err, error);
+}
 
+static void
+remove_reply(DBusGProxy *proxy, GError *error, gpointer user_data)
+{
+  AsyncData *data = user_data;
+  EBookCallback cb = data->callback;
+  if (cb)
+    cb (data->book, get_status_from_error (error), data->closure);
 
-	CORBA_exception_free (&ev);
+  g_object_unref (data->book);
+  g_slice_free (AsyncData, data);
+}
 
-	if (sync) {
-		/* wait for something to happen (both cancellation and a
-		   successful response will notify us via our cv */
-		e_flag_wait (our_op->flag);
+/**
+ * e_book_async_remove:
+ * @book: an #EBook
+ * @cb: a function to call when the operation finishes
+ * @closure: data to pass to callback function
+ *
+ * Remove the backing data for this #EBook. For example, with the file backend this
+ * deletes the database file. You cannot get it back!
+ *
+ * Return value: %FALSE if successful, %TRUE otherwise.
+ **/
+guint
+e_book_async_remove (EBook *book, EBookCallback cb, gpointer closure)
+{
+  AsyncData *data;
 
-		status = our_op->status;
-		*fields = our_op->list;
+  e_return_async_error_if_fail (E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
+  e_return_async_error_if_fail (book->priv->proxy, E_BOOK_ERROR_REPOSITORY_OFFLINE);
 
-		g_mutex_lock (book->priv->mutex);
-		e_book_clear_op (book, our_op);
-		g_mutex_unlock (book->priv->mutex);
+  data = g_slice_new0 (AsyncData);
+  data->book = g_object_ref (book);
+  data->callback = cb;
+  data->closure = closure;
 
-		E_BOOK_CHECK_STATUS (status, error);
-	}
-	else {
-		return TRUE;
-	}
+  org_gnome_evolution_dataserver_addressbook_Book_remove_async (book->priv->proxy, remove_reply, data);
+  return 0;
 }
 
 /**
@@ -779,16 +676,44 @@
  * Return value: %TRUE if successful, %FALSE otherwise.
  **/
 gboolean
-e_book_get_required_fields  (EBook            *book,
-			      GList           **fields,
-			      GError          **error)
-{
-	e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG, FALSE);
-	e_return_error_if_fail (fields,                   E_BOOK_ERROR_INVALID_ARG, FALSE);
-
-	return do_get_required_fields (TRUE,
-					book, fields, error,
-					NULL, NULL);
+e_book_get_required_fields (EBook *book, GList **fields, GError **error)
+{
+  GError *err = NULL;
+  char **list = NULL;
+
+  e_return_error_if_fail (E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
+  e_return_error_if_fail (book->priv->proxy, E_BOOK_ERROR_REPOSITORY_OFFLINE);
+
+  org_gnome_evolution_dataserver_addressbook_Book_get_required_fields (book->priv->proxy, &list, &err);
+  if (list) {
+    *fields = array_to_stringlist (list);
+    return TRUE;
+  } else {
+    return unwrap_gerror (err, error);
+  }
+}
+
+static void
+get_required_fields_reply(DBusGProxy *proxy, char **fields, GError *error, gpointer user_data)
+{
+  AsyncData *data = user_data;
+  EBookEListCallback cb = data->callback;
+  char **i = fields;
+  EList *efields = e_list_new (NULL, 
+                               (EListFreeFunc) g_free,
+                               NULL);
+  
+  while (*i != NULL) {
+    e_list_append (efields, (*i++));
+  }
+  
+  if (cb)
+    cb (data->book, get_status_from_error (error), efields, data->closure);
+
+  g_object_unref (efields);
+  g_free (fields);
+  g_object_unref (data->book);
+  g_slice_free (AsyncData, data);
 }
 
 /**
@@ -803,15 +728,20 @@
  * Return value: %TRUE if the operation was started, %FALSE otherwise.
  **/
 guint
-e_book_async_get_required_fields (EBook              *book,
-				   EBookEListCallback  cb,
-				   gpointer            closure)
-{
-	g_return_val_if_fail (E_IS_BOOK (book), FALSE);
-
-	return !do_get_required_fields (FALSE,
-					 book, NULL, NULL,
-					 cb, closure);
+e_book_async_get_required_fields (EBook *book, EBookEListCallback cb, gpointer closure)
+{
+  AsyncData *data;
+
+  e_return_async_error_val_if_fail (E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
+  e_return_async_error_val_if_fail (book->priv->proxy, E_BOOK_ERROR_REPOSITORY_OFFLINE);
+
+  data = g_slice_new0 (AsyncData);
+  data->book = g_object_ref (book);
+  data->callback = cb;
+  data->closure = closure;
+
+  org_gnome_evolution_dataserver_addressbook_Book_get_required_fields_async (book->priv->proxy, get_required_fields_reply, data);
+  return 0;
 }
 
 /**
@@ -828,16 +758,43 @@
  * Return value: %TRUE if successful, %FALSE otherwise
  **/
 gboolean
-e_book_get_supported_fields  (EBook            *book,
-			      GList           **fields,
-			      GError          **error)
-{
-	e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG, FALSE);
-	e_return_error_if_fail (fields,                   E_BOOK_ERROR_INVALID_ARG, FALSE);
-
-	return do_get_supported_fields (TRUE,
-					book, fields, error,
-					NULL, NULL);
+e_book_get_supported_fields (EBook *book, GList **fields, GError **error)
+{
+  GError *err = NULL;
+  char **list = NULL;
+
+  e_return_error_if_fail (E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
+  e_return_error_if_fail (book->priv->proxy, E_BOOK_ERROR_REPOSITORY_OFFLINE);
+
+  org_gnome_evolution_dataserver_addressbook_Book_get_supported_fields (book->priv->proxy, &list, &err);
+  if (list) {
+    *fields = array_to_stringlist (list);
+    return TRUE;
+  } else {
+    return unwrap_gerror (err, error);
+  }
+}
+
+static void
+get_supported_fields_reply(DBusGProxy *proxy, char **fields, GError *error, gpointer user_data)
+{
+  AsyncData *data = user_data;
+  EBookEListCallback cb = data->callback;
+  char **i = fields;
+  EList *efields = e_list_new (NULL,  (EListFreeFunc) g_free, NULL);
+  
+  while (*i != NULL) {
+    e_list_append (efields, (*i++));
+  }
+  
+  if (cb)
+    cb (data->book, get_status_from_error (error), efields, data->closure);
+
+  g_object_unref (efields);
+  g_free (fields);
+
+  g_object_unref (data->book);
+  g_slice_free (AsyncData, data);
 }
 
 /**
@@ -853,215 +810,20 @@
  * Return value: %TRUE if successful, %FALSE otherwise.
  **/
 guint
-e_book_async_get_supported_fields (EBook              *book,
-				   EBookEListCallback  cb,
-				   gpointer            closure)
-{
-	g_return_val_if_fail (E_IS_BOOK (book), FALSE);
-
-	return !do_get_supported_fields (FALSE,
-					 book, NULL, NULL,
-					 cb, closure);
-}
-
-static gboolean
-emit_async_elist_response (gpointer data)
-{
-	EBookOp *op = data;
-	EBook *book = op->book;
-
-	if (op->cb.elist)
-		op->cb.elist (book, op->status, op->elist, op->closure);
-
-	g_mutex_lock (book->priv->mutex);
-
-	g_object_unref (op->elist);
-
-	book->priv->pending_idles = g_list_remove (book->priv->pending_idles,
-						   GINT_TO_POINTER (op->idle_id));
-
-	e_book_clear_op (book, op);
-
-	g_mutex_unlock (book->priv->mutex);
-	g_object_unref (book);
-
-	return FALSE;
-}
-
-static void
-e_book_response_get_required_fields (EBook       *book,
-				      guint32      opid,
-				      EBookStatus  status,
-				      GList       *fields)
-
-{
-	EBookOp *op;
-
-	g_mutex_lock (book->priv->mutex);
-
-	op = e_book_get_op (book, opid);
-
-	if (op == NULL) {
-		g_mutex_unlock (book->priv->mutex);
-		g_warning ("e_book_response_get_required_fields: Cannot find operation ");
-		return;
-	}
-
-	op->status = status;
-	if (op->synchronous) {
-		op->list = fields;
-		e_flag_set (op->flag);
-	} else {
-		GList *l;
-		EList *efields = e_list_new ((EListCopyFunc) g_strdup,
-					     (EListFreeFunc) g_free,
-					     NULL);
-
-		for (l = fields; l; l = l->next)
-			e_list_append (efields, l->data);
-
-		op->book = g_object_ref (book);
-		op->elist = efields;
-
-		op->idle_id = g_idle_add (emit_async_elist_response, op);
-		book->priv->pending_idles = g_list_prepend (book->priv->pending_idles,
-							    GINT_TO_POINTER (op->idle_id));
-	}
-
-	g_mutex_unlock (book->priv->mutex);
-}
-
-static void
-e_book_response_get_supported_fields (EBook       *book,
-				      guint32      opid,
-				      EBookStatus  status,
-				      GList       *fields)
+e_book_async_get_supported_fields (EBook *book, EBookEListCallback cb, gpointer closure)
 {
-	EBookOp *op;
-
-	g_mutex_lock (book->priv->mutex);
-
-	op = e_book_get_op (book, opid);
-
-	if (op == NULL) {
-		g_mutex_unlock (book->priv->mutex);
-		g_warning ("e_book_response_get_supported_fields: Cannot find operation ");
-		return;
-	}
-
-	op->status = status;
-	if (op->synchronous) {
-		op->list = fields;
-		e_flag_set (op->flag);
-	} else {
-		GList *l;
-		EList *efields = e_list_new ((EListCopyFunc) g_strdup,
-					     (EListFreeFunc) g_free,
-					     NULL);
-
-		for (l = fields; l; l = l->next)
-			e_list_append (efields, l->data);
-
-		op->book = g_object_ref (book);
-		op->elist = efields;
-
-		op->idle_id = g_idle_add (emit_async_elist_response, op);
-		book->priv->pending_idles = g_list_prepend (book->priv->pending_idles,
-							    GINT_TO_POINTER (op->idle_id));
-	}
-
-	g_mutex_unlock (book->priv->mutex);
-}
-
-
-static gboolean
-do_get_supported_auth_methods (gboolean             sync,
-			       EBook               *book,
-			       GList              **auth_methods,
-			       GError             **error,
-			       EBookEListCallback   cb,
-			       gpointer             closure)
-{
-	EBookOp *our_op;
-	EBookStatus status;
-	CORBA_Environment ev;
-
-	g_mutex_lock (book->priv->mutex);
-
-	if (book->priv->load_state != E_BOOK_SOURCE_LOADED) {
-		g_mutex_unlock (book->priv->mutex);
-		if (error) {
-			g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_SOURCE_NOT_LOADED,
-				     _("\"%s\" on book before \"%s\""),
-				     "e_book_get_supported_auth_methods",
-				     "e_book_open");
-		}
-		else {
-			g_warning (_("\"%s\" on book before \"%s\""),
-				   "e_book_get_supported_auth_methods",
-				   "e_book_open");
-		}
-		return FALSE;
-	}
-
-	if (sync && e_book_get_current_sync_op (book) != NULL) {
-		g_mutex_unlock (book->priv->mutex);
-		g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY,
-			     _("book busy"));
-		return FALSE;
-	}
-
-	our_op = e_book_new_op (book, sync);
-
-	g_mutex_unlock (book->priv->mutex);
-
-	CORBA_exception_init (&ev);
-
-	our_op->cb.elist = cb;
-	our_op->closure = closure;
-
-	/* will eventually end up calling
-	   e_book_response_get_supported_fields */
-	GNOME_Evolution_Addressbook_Book_getSupportedAuthMethods(book->priv->corba_book, our_op->opid, &ev);
-
-	if (ev._major != CORBA_NO_EXCEPTION) {
-
-		g_mutex_lock (book->priv->mutex);
-		e_book_clear_op (book, our_op);
-		g_mutex_unlock (book->priv->mutex);
-
-		CORBA_exception_free (&ev);
-
-		if (error)
-			g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION,
-				     _("CORBA exception making \"%s\" call"),
-				     "Book::getSupportedAuthMethods");
-		else
-			g_warning (_("CORBA exception making \"%s\" call"),
-				   "Book::getSupportedAuthMethods");
-		return FALSE;
-	}
-
-
-	CORBA_exception_free (&ev);
-
-	if (sync) {
-		/* wait for something to happen (both cancellation and a
-		   successful response will notity us via our cv */
-		e_flag_wait (our_op->flag);
+  AsyncData *data;
 
-		status = our_op->status;
-		*auth_methods = our_op->list;
+  e_return_async_error_val_if_fail (E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
+  e_return_async_error_val_if_fail (book->priv->proxy, E_BOOK_ERROR_REPOSITORY_OFFLINE);
 
-		g_mutex_lock (book->priv->mutex);
-		e_book_clear_op (book, our_op);
-		g_mutex_unlock (book->priv->mutex);
+  data = g_slice_new0 (AsyncData);
+  data->book = g_object_ref (book);
+  data->callback = cb;
+  data->closure = closure;
 
-		E_BOOK_CHECK_STATUS (status, error);
-	}
-	else {
-		return TRUE;
-	}
+  org_gnome_evolution_dataserver_addressbook_Book_get_supported_fields_async (book->priv->proxy, get_supported_fields_reply, data);
+  return 0;
 }
 
 /**
@@ -1077,16 +839,45 @@
  * Return value: %TRUE if successful, %FALSE otherwise
  **/
 gboolean
-e_book_get_supported_auth_methods (EBook            *book,
-				   GList           **auth_methods,
-				   GError          **error)
-{
-	e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG, FALSE);
-	e_return_error_if_fail (auth_methods,             E_BOOK_ERROR_INVALID_ARG, FALSE);
-
-	return do_get_supported_auth_methods (TRUE,
-					      book, auth_methods, error,
-					      NULL, NULL);
+e_book_get_supported_auth_methods (EBook *book, GList **auth_methods, GError **error)
+{
+  GError *err = NULL;
+  char **list = NULL;
+
+  e_return_error_if_fail (E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
+  e_return_error_if_fail (book->priv->proxy, E_BOOK_ERROR_REPOSITORY_OFFLINE);
+
+  org_gnome_evolution_dataserver_addressbook_Book_get_supported_auth_methods (book->priv->proxy, &list, &err);
+  if (list) {
+    *auth_methods = array_to_stringlist (list);
+    return TRUE;
+  } else {
+    return unwrap_gerror (err, error);
+  }
+}
+
+static void
+get_supported_auth_methods_reply(DBusGProxy *proxy, char **methods, GError *error, gpointer user_data)
+{
+  AsyncData *data = user_data;
+  EBookEListCallback cb = data->callback;
+  char **i = methods;
+  EList *emethods = e_list_new (NULL, 
+                                (EListFreeFunc) g_free,
+                                NULL);
+
+  while (*i != NULL) {
+    e_list_append (emethods, (*i++));
+  }
+  
+  if (cb)
+    cb (data->book, get_status_from_error (error), emethods, data->closure);
+
+  g_object_unref (emethods);
+  g_free (methods);
+
+  g_object_unref (data->book);
+  g_slice_free (AsyncData, data);
 }
 
 /**
@@ -1099,154 +890,21 @@
  * This function does not block.
  *
  * Return value: %TRUE if successful, %FALSE otherwise.
- **/
-guint
-e_book_async_get_supported_auth_methods (EBook              *book,
-					 EBookEListCallback  cb,
-					 gpointer            closure)
-{
-	g_return_val_if_fail (book && E_IS_BOOK (book), TRUE);
-
-	return !do_get_supported_auth_methods (FALSE,
-					       book, NULL, NULL,
-					       cb, closure);
-}
-
-static void
-e_book_response_get_supported_auth_methods (EBook                 *book,
-					    guint32                opid,
-					    EBookStatus            status,
-					    GList                 *auth_methods)
+ **/guint
+e_book_async_get_supported_auth_methods (EBook *book, EBookEListCallback cb, gpointer closure)
 {
-	EBookOp *op;
-
-	g_mutex_lock (book->priv->mutex);
-
-	op = e_book_get_op (book, opid);
-
-	if (op == NULL) {
-		g_mutex_unlock (book->priv->mutex);
-		g_warning ("e_book_response_get_supported_auth_methods: Cannot find operation ");
-		return;
-	}
-
-	op->status = status;
-	if (op->synchronous) {
-		op->list = auth_methods;
-		e_flag_set (op->flag);
-	} else {
-		GList *l;
-		EList *emethods = e_list_new ((EListCopyFunc) g_strdup,
-					      (EListFreeFunc) g_free,
-					      NULL);
-
-		for (l = auth_methods; l; l = l->next)
-			e_list_append (emethods, l->data);
-
-		op->book = g_object_ref (book);
-		op->elist = emethods;
-
-		op->idle_id = g_idle_add (emit_async_elist_response, op);
-		book->priv->pending_idles = g_list_prepend (book->priv->pending_idles,
-							    GINT_TO_POINTER (op->idle_id));
-	}
-
-	g_mutex_unlock (book->priv->mutex);
-}
-
-
-
-static gboolean
-do_authenticate_user (gboolean        sync,
-		      EBook          *book,
-		      const char     *user,
-		      const char     *passwd,
-		      const char     *auth_method,
-		      GError        **error,
-		      EBookCallback   cb,
-		      gpointer        closure)
-{
-	EBookOp *our_op;
-	EBookStatus status;
-	CORBA_Environment ev;
-
-	g_mutex_lock (book->priv->mutex);
-
-	if (book->priv->load_state != E_BOOK_SOURCE_LOADED) {
-		g_mutex_unlock (book->priv->mutex);
-		if (error) {
-			g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_SOURCE_NOT_LOADED,
-				     _("\"%s\" on book before \"%s\""),
-				     "e_book_authenticate_user", "e_book_open");
-		}
-		else {
-			g_warning (_("\"%s\" on book before \"%s\""),
-				   "e_book_authenticate_user", "e_book_open");
-		}
-
-		return FALSE;
-	}
-
-	if (sync && e_book_get_current_sync_op (book) != NULL) {
-		g_mutex_unlock (book->priv->mutex);
-		g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY,
-			     _("book busy"));
-		return FALSE;
-	}
-
-	our_op = e_book_new_op (book, sync);
-
-	g_mutex_unlock (book->priv->mutex);
-
-	CORBA_exception_init (&ev);
-
-	our_op->cb.status = cb;
-	our_op->closure = closure;
-
-	/* will eventually end up calling
-	   e_book_response_generic */
-	GNOME_Evolution_Addressbook_Book_authenticateUser (book->priv->corba_book, our_op->opid,
-							   user, passwd,
-							   auth_method,
-							   &ev);
-
-	if (ev._major != CORBA_NO_EXCEPTION) {
-
-		g_mutex_lock (book->priv->mutex);
-		e_book_clear_op (book, our_op);
-		g_mutex_unlock (book->priv->mutex);
-
-		CORBA_exception_free (&ev);
-
-		if (error)
-			g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION,
-				     _("CORBA exception making \"%s\" call"),
-				     "Book::authenticateUser");
-		else
-			g_warning (_("CORBA exception making \"%s\" call"),
-				   "Book::authenticateUser");
+  AsyncData *data;
 
-		return FALSE;
-	}
-
-	CORBA_exception_free (&ev);
-
-	if (sync) {
-		/* wait for something to happen (both cancellation and a
-		   successful response will notity us via our cv */
-		e_flag_wait (our_op->flag);
+  e_return_async_error_val_if_fail (E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
+  e_return_async_error_val_if_fail (book->priv->proxy, E_BOOK_ERROR_REPOSITORY_OFFLINE);
 
-		status = our_op->status;
+  data = g_slice_new0 (AsyncData);
+  data->book = g_object_ref (book);
+  data->callback = cb;
+  data->closure = closure;
 
-		g_mutex_lock (book->priv->mutex);
-		e_book_clear_op (book, our_op);
-		g_mutex_unlock (book->priv->mutex);
-
-		E_BOOK_CHECK_STATUS (status, error);
-	}
-	else {
-		return TRUE;
-	}
+  org_gnome_evolution_dataserver_addressbook_Book_get_supported_auth_methods_async (book->priv->proxy, get_supported_auth_methods_reply, data);
+  return 0;
 }
 
 /**
@@ -1264,27 +922,35 @@
  * Return value: %TRUE if successful, %FALSE otherwise
  **/
 gboolean
-e_book_authenticate_user (EBook         *book,
-			  const char    *user,
-			  const char    *passwd,
-			  const char    *auth_method,
-			  GError       **error)
-{
-	e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG, FALSE);
-	e_return_error_if_fail (user,                     E_BOOK_ERROR_INVALID_ARG, FALSE);
-	e_return_error_if_fail (passwd,                   E_BOOK_ERROR_INVALID_ARG, FALSE);
-	e_return_error_if_fail (auth_method,              E_BOOK_ERROR_INVALID_ARG, FALSE);
-
-	return do_authenticate_user (TRUE,
-				     book, user, passwd, auth_method, error,
-				     NULL, NULL);
+e_book_authenticate_user (EBook *book, const char *user, const char *passwd, const char *auth_method, GError **error)
+{
+  GError *err = NULL;
+
+  e_return_error_if_fail (E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
+  e_return_error_if_fail (book->priv->proxy, E_BOOK_ERROR_REPOSITORY_OFFLINE);
+
+  org_gnome_evolution_dataserver_addressbook_Book_authenticate_user (book->priv->proxy, user, passwd, auth_method, &err);
+  return unwrap_gerror (err, error);
 }
 
-/**
- * e_book_async_authenticate_user:
- * @book: an #EBook
- * @user: user name
- * @passwd: password
+static void
+authenticate_user_reply(DBusGProxy *proxy, GError *error, gpointer user_data)
+{
+  AsyncData *data = user_data;
+  EBookCallback cb = data->callback;
+
+  if (cb)
+    cb (data->book, get_status_from_error (error), data->closure);
+
+  g_object_unref (data->book);
+  g_slice_free (AsyncData, data);
+}
+
+/**
+ * e_book_async_authenticate_user:
+ * @book: an #EBook
+ * @user: user name
+ * @passwd: password
  * @auth_method: string indicating authentication method
  * @cb: function to call when the operation finishes
  * @closure: data to pass to callback function
@@ -1297,114 +963,23 @@
  * Return value: %FALSE if successful, %TRUE otherwise.
  **/
 guint
-e_book_async_authenticate_user (EBook                 *book,
-				const char            *user,
-				const char            *passwd,
-				const char            *auth_method,
-				EBookCallback         cb,
-				gpointer              closure)
-{
-	g_return_val_if_fail (book && E_IS_BOOK (book), TRUE);
-	g_return_val_if_fail (user,                     TRUE);
-	g_return_val_if_fail (passwd,                   TRUE);
-	g_return_val_if_fail (auth_method,              TRUE);
-
-	return !do_authenticate_user (FALSE,
-				      book, user, passwd, auth_method, NULL,
-				      cb, closure);
-}
-
-
-
-static gboolean
-do_get_contact (gboolean sync,
-		EBook *book,
-		const char *id,
-		EContact **contact,
-		GError **error,
-		EBookContactCallback cb,
-		gpointer closure)
-{
-	EBookOp *our_op;
-	EBookStatus status;
-	CORBA_Environment ev;
-
-	g_mutex_lock (book->priv->mutex);
-
-	if (book->priv->load_state != E_BOOK_SOURCE_LOADED) {
-		g_mutex_unlock (book->priv->mutex);
-		if (error) {
-			g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_SOURCE_NOT_LOADED,
-				     _("\"%s\" on book before \"%s\""),
-				     "e_book_get_contact", "e_book_open");
-		}
-		else {
-			g_warning (_("\"%s\" on book before \"%s\""),
-				   "e_book_get_contact", "e_book_open");
-		}
-
-		return FALSE;
-	}
-
-	if (sync && e_book_get_current_sync_op (book) != NULL) {
-		g_mutex_unlock (book->priv->mutex);
-		g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY,
-			     _("book busy"));
-		return FALSE;
-	}
-
-	our_op = e_book_new_op (book, sync);
-
-	g_mutex_unlock (book->priv->mutex);
-
-	CORBA_exception_init (&ev);
-
-	our_op->cb.contact = cb;
-	our_op->closure = closure;
-
-	/* will eventually end up calling e_book_response_generic */
-	GNOME_Evolution_Addressbook_Book_getContact (book->priv->corba_book, our_op->opid,
-						     (const GNOME_Evolution_Addressbook_VCard) id, &ev);
-
-	if (ev._major != CORBA_NO_EXCEPTION) {
-
-		g_mutex_lock (book->priv->mutex);
-		e_book_clear_op (book, our_op);
-		g_mutex_unlock (book->priv->mutex);
-
-		CORBA_exception_free (&ev);
-
-		if (error) {
-			g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION,
-				     _("CORBA exception making \"%s\" call"),
-				     "Book::getContact");
-		}
-		else {
-			g_warning (_("CORBA exception making \"%s\" call"),
-				   "Book::getContact");
-		}
-		return FALSE;
-	}
-
-	CORBA_exception_free (&ev);
-
-	if (sync) {
-		/* wait for something to happen (both cancellation and a
-		   successful response will notity us via our cv */
-		e_flag_wait (our_op->flag);
-
-		status = our_op->status;
-		*contact = our_op->contact;
+e_book_async_authenticate_user (EBook *book, const char *user, const char *passwd, const char *auth_method, EBookCallback cb, gpointer closure)
+{
+  AsyncData *data;
 
-		g_mutex_lock (book->priv->mutex);
-		e_book_clear_op (book, our_op);
-		g_mutex_unlock (book->priv->mutex);
+  e_return_async_error_if_fail (E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
+  e_return_async_error_if_fail (book->priv->proxy, E_BOOK_ERROR_REPOSITORY_OFFLINE);
+  e_return_async_error_if_fail (user, E_BOOK_ERROR_INVALID_ARG);
+  e_return_async_error_if_fail (passwd, E_BOOK_ERROR_INVALID_ARG);
+  e_return_async_error_if_fail (auth_method, E_BOOK_ERROR_INVALID_ARG);
+
+  data = g_slice_new0 (AsyncData);
+  data->book = g_object_ref (book);
+  data->callback = cb;
+  data->closure = closure;
 
-		E_BOOK_CHECK_STATUS (status, error);
-	}
-	else {
-		return TRUE;
-	}
+  org_gnome_evolution_dataserver_addressbook_Book_authenticate_user_async (book->priv->proxy, user, passwd, auth_method, authenticate_user_reply, data);
+  return 0;
 }
 
 /**
@@ -1420,18 +995,48 @@
  * Return value: %TRUE if successful, %FALSE otherwise
  **/
 gboolean
-e_book_get_contact (EBook       *book,
-		    const char  *id,
-		    EContact   **contact,
-		    GError     **error)
-{
-	e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG, FALSE);
-	e_return_error_if_fail (id,                       E_BOOK_ERROR_INVALID_ARG, FALSE);
-	e_return_error_if_fail (contact,                  E_BOOK_ERROR_INVALID_ARG, FALSE);
-
-	return do_get_contact (TRUE,
-			       book, id, contact, error,
-			       NULL, NULL);
+e_book_get_contact (EBook *book, const char  *id, EContact **contact, GError **error)
+{
+  GError *err = NULL;
+  char *vcard = NULL;
+
+  e_return_error_if_fail (E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
+  e_return_error_if_fail (book->priv->proxy, E_BOOK_ERROR_REPOSITORY_OFFLINE);
+  
+  org_gnome_evolution_dataserver_addressbook_Book_get_contact (book->priv->proxy, id, &vcard, &err);
+  if (vcard) {
+    *contact = e_contact_new_from_vcard (vcard);
+    g_free (vcard);
+  }
+  return unwrap_gerror (err, error);
+}
+
+static void
+get_contact_reply(DBusGProxy *proxy, char *vcard, GError *error, gpointer user_data)
+{
+  AsyncData *data = user_data;
+  EBookContactCallback cb = data->callback;
+  EBookStatus status = get_status_from_error (error);
+
+  /* Protect against garbage return values on error */
+  if (error)
+	  vcard = NULL;
+
+  if (cb) {
+    if (error == NULL) {
+      cb (data->book, status, e_contact_new_from_vcard (vcard), data->closure);
+    } else {
+      cb (data->book, status, NULL, data->closure);
+    }
+  } else {
+    g_warning (G_STRLOC ": cannot get contact: %s", error->message);
+  }
+
+  if (error)
+	  g_error_free (error);
+  g_free (vcard);
+  g_object_unref (data->book);
+  g_slice_free (AsyncData, data);
 }
 
 /**
@@ -1446,1972 +1051,721 @@
  * Return value: %FALSE if successful, %TRUE otherwise
  **/
 guint
-e_book_async_get_contact (EBook                 *book,
-			  const char            *id,
-			  EBookContactCallback   cb,
-			  gpointer               closure)
-{
-	g_return_val_if_fail (book && E_IS_BOOK (book), TRUE);
-	g_return_val_if_fail (id,                       TRUE);
-
-	return !do_get_contact (FALSE,
-				book, id, NULL, NULL,
-				cb, closure);
-}
-
-static gboolean
-emit_async_get_contact_response (gpointer data)
-{
-	EBookOp *op = data;
-	EBook *book = op->book;
-
-	if (op->cb.contact)
-		op->cb.contact (book, op->status, op->contact, op->closure);
-
-	g_mutex_lock (book->priv->mutex);
-
-	g_object_unref (op->contact);
-
-	book->priv->pending_idles = g_list_remove (book->priv->pending_idles,
-						   GINT_TO_POINTER (op->idle_id));
-
-	e_book_clear_op (book, op);
-
-	g_mutex_unlock (book->priv->mutex);
-	g_object_unref (book);
-
-	return FALSE;
-}
-
-static void
-e_book_response_get_contact (EBook       *book,
-			     guint32      opid,
-			     EBookStatus  status,
-			     EContact    *contact)
+e_book_async_get_contact (EBook *book, const char *id, EBookContactCallback cb, gpointer closure)
 {
-	EBookOp *op;
-
-	d(printf ("e_book_response_get_contact\n"));
-
-	g_mutex_lock (book->priv->mutex);
+  AsyncData *data;
 
-	op = e_book_get_op (book, opid);
+  e_return_async_error_val_if_fail (E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
+  e_return_async_error_val_if_fail (book->priv->proxy, E_BOOK_ERROR_REPOSITORY_OFFLINE);
+  e_return_async_error_val_if_fail (id, E_BOOK_ERROR_INVALID_ARG);
 
-	if (op == NULL) {
-		g_mutex_unlock (book->priv->mutex);
-		g_warning ("e_book_response_get_contact: Cannot find operation ");
-		return;
-	}
-
-	op->status = status;
-	op->contact = contact;
-
-	if (op->synchronous)
-		e_flag_set (op->flag);
-	else {
-		op->book = g_object_ref (book);
-
-		op->idle_id = g_idle_add (emit_async_get_contact_response, op);
-		book->priv->pending_idles = g_list_prepend (book->priv->pending_idles,
-							    GINT_TO_POINTER (op->idle_id));
-	}
-
-	g_mutex_unlock (book->priv->mutex);
-}
-
-
-static gboolean
-do_remove_contacts (gboolean sync,
-		    EBook *book,
-		    GList *ids,
-		    GError **error,
-		    EBookCallback cb,
-		    gpointer closure)
-{
-	GNOME_Evolution_Addressbook_ContactIdList idlist;
-	CORBA_Environment ev;
-	GList *iter;
-	int num_ids, i;
-	EBookOp *our_op;
-	EBookStatus status;
-
-	g_mutex_lock (book->priv->mutex);
-
-	if (book->priv->load_state != E_BOOK_SOURCE_LOADED) {
-		g_mutex_unlock (book->priv->mutex);
-		if (error) {
-			g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_SOURCE_NOT_LOADED,
-				     _("\"%s\" on book before \"%s\""),
-				     "e_book_remove_contacts", "e_book_open");
-		}
-		else {
-			g_warning (_("\"%s\" on book before \"%s\""),
-				   "e_book_remove_contacts", "e_book_open");
-		}
-		return FALSE;
-	}
-
-	if (sync && e_book_get_current_sync_op (book) != NULL) {
-		g_mutex_unlock (book->priv->mutex);
-		g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY,
-			     _("book busy"));
-		return FALSE;
-	}
-
-	our_op = e_book_new_op (book, sync);
-
-	g_mutex_unlock (book->priv->mutex);
-
-	CORBA_exception_init (&ev);
-
-	num_ids = g_list_length (ids);
-	idlist._buffer = CORBA_sequence_GNOME_Evolution_Addressbook_ContactId_allocbuf (num_ids);
-	idlist._maximum = num_ids;
-	idlist._length = num_ids;
-
-	for (iter = ids, i = 0; iter; iter = iter->next)
-		idlist._buffer[i++] = CORBA_string_dup (iter->data);
-
-	our_op->cb.status = cb;
-	our_op->closure = closure;
-
-	/* will eventually end up calling e_book_response_generic */
-	GNOME_Evolution_Addressbook_Book_removeContacts (book->priv->corba_book, our_op->opid, &idlist, &ev);
-
-	CORBA_free(idlist._buffer);
-
-	if (ev._major != CORBA_NO_EXCEPTION) {
-
-		g_mutex_lock (book->priv->mutex);
-		e_book_clear_op (book, our_op);
-		g_mutex_unlock (book->priv->mutex);
-
-		CORBA_exception_free (&ev);
-
-		if (error) {
-			g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION,
-				     _("CORBA exception making \"%s\" call"),
-				     "Book::removeContacts");
-		}
-		else {
-			g_warning (_("CORBA exception making \"%s\" call"),
-				   "Book::removeContacts");
-		}
-		return FALSE;
-	}
-
-	CORBA_exception_free (&ev);
-
-	if (sync) {
-		/* wait for something to happen (both cancellation and a
-		   successful response will notity us via our cv */
-		e_flag_wait (our_op->flag);
-
-		status = our_op->status;
+  data = g_slice_new0 (AsyncData);
+  data->book = g_object_ref (book);
+  data->callback = cb;
+  data->closure = closure;
 
-		g_mutex_lock (book->priv->mutex);
-		e_book_clear_op (book, our_op);
-		g_mutex_unlock (book->priv->mutex);
-
-		E_BOOK_CHECK_STATUS (status, error);
-	}
-	else {
-		return TRUE;
-	}
+  org_gnome_evolution_dataserver_addressbook_Book_get_contact_async (book->priv->proxy, id, get_contact_reply, data);
+  return 0;
 }
 
 /**
- * e_book_remove_contact:
+ * e_book_get_contacts:
  * @book: an #EBook
- * @id: a string
+ * @query: an #EBookQuery
+ * @contacts: a #GList pointer, will be set to the list of contacts
  * @error: a #GError to set on failure
  *
- * Removes the contact with id @id from @book.
+ * Query @book with @query, setting @contacts to the list of contacts which
+ * matched. On failed, @error will be set and %FALSE returned.
  *
- * Return value: %TRUE if successful, %FALSE otherwise
+ * Return value: %TRUE on success, %FALSE otherwise
  **/
 gboolean
-e_book_remove_contact (EBook       *book,
-		       const char  *id,
-		       GError     **error)
+e_book_get_contacts (EBook *book, EBookQuery *query, GList **contacts, GError **error)
 {
-	GList *list;
-	gboolean rv;
-
-	e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG, FALSE);
-	e_return_error_if_fail (id,                       E_BOOK_ERROR_INVALID_ARG, FALSE);
-
-	list = g_list_append (NULL, (char*)id);
-
-	rv = e_book_remove_contacts (book, list, error);
-
-	g_list_free (list);
-
-	return rv;
+  GError *err = NULL;
+  char **list = NULL;
+  char *sexp;
+
+  e_return_error_if_fail (E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
+  e_return_error_if_fail (book->priv->proxy, E_BOOK_ERROR_REPOSITORY_OFFLINE);
+
+  sexp = e_book_query_to_string (query);
+  org_gnome_evolution_dataserver_addressbook_Book_get_contact_list (book->priv->proxy, sexp, &list, &err);
+  g_free (sexp);
+  if (!err) {
+    GList *l = NULL;
+    char **i = list;
+    while (*i != NULL) {
+      l = g_list_prepend (l, e_contact_new_from_vcard (*i++));
+    }
+    *contacts = g_list_reverse (l);
+    g_strfreev (list);
+    return TRUE;
+  } else {
+    return unwrap_gerror (err, error);
+  }
 }
 
-/**
- * e_book_remove_contacts:
- * @book: an #EBook
- * @ids: an #GList of const char *id's
- * @error: a #GError to set on failure
- *
- * Removes the contacts with ids from the list @ids from @book.  This is
- * always more efficient than calling e_book_remove_contact_by_id if you
- * have more than one id to remove, as some backends can implement it
- * as a batch request.
- *
- * Return value: %TRUE if successful, %FALSE otherwise
- **/
-gboolean
-e_book_remove_contacts (EBook    *book,
-			GList    *ids,
-			GError  **error)
-{
-	e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG, FALSE);
-	e_return_error_if_fail (ids,                      E_BOOK_ERROR_INVALID_ARG, FALSE);
-
-	return do_remove_contacts (TRUE,
-				   book, ids, error,
-				   NULL, NULL);
+static void
+get_contacts_reply(DBusGProxy *proxy, char **vcards, GError *error, gpointer user_data)
+{
+  AsyncData *data = user_data;
+  GList *list = NULL;
+  EBookListCallback cb = data->callback;
+  if (vcards) {
+    char **i = vcards;
+    while (*i != NULL) {
+      list = g_list_prepend (list, e_contact_new_from_vcard (*i++));
+    }
+  }
+  list = g_list_reverse (list);
+
+  if (cb)
+    cb (data->book, get_status_from_error (error), list, data->closure);
+  g_strfreev (vcards);
+
+  g_object_unref (data->book);
+  g_slice_free (AsyncData, data);
 }
 
 /**
- * e_book_async_remove_contact:
+ * e_book_async_get_contacts:
  * @book: an #EBook
- * @contact: an #EContact
+ * @query: an #EBookQuery
  * @cb: a function to call when the operation finishes
  * @closure: data to pass to callback function
  *
- * Removes @contact from @book.
+ * Query @book with @query.
  *
- * Return value: %TRUE if successful, %FALSE otherwise
+ * Return value: %FALSE on success, %TRUE otherwise
  **/
 guint
-e_book_async_remove_contact (EBook                 *book,
-			     EContact              *contact,
-			     EBookCallback          cb,
-			     gpointer               closure)
+e_book_async_get_contacts (EBook *book, EBookQuery *query, EBookListCallback cb, gpointer closure)
 {
-	const char *id;
+  AsyncData *data;
+  char *sexp;
+
+  e_return_async_error_val_if_fail (E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
+  e_return_async_error_val_if_fail (book->priv->proxy, E_BOOK_ERROR_REPOSITORY_OFFLINE);
+  e_return_async_error_val_if_fail (query, E_BOOK_ERROR_INVALID_ARG);
+
+  sexp = e_book_query_to_string (query);
+
+  data = g_slice_new0 (AsyncData);
+  data->book = g_object_ref (book);
+  data->callback = cb;
+  data->closure = closure;
 
-	g_return_val_if_fail (E_IS_BOOK (book), TRUE);
-	g_return_val_if_fail (E_IS_CONTACT (contact), TRUE);
+  org_gnome_evolution_dataserver_addressbook_Book_get_contact_list_async (book->priv->proxy, sexp, get_contacts_reply, data);
+  g_free (sexp);
+  return 0;
+}
 
-	id = e_contact_get_const (contact, E_CONTACT_UID);
+static GList *
+parse_changes_array (GPtrArray *array)
+{
+  GList *l = NULL;
+  int i;
+  
+  if (array == NULL)
+    return NULL;
+
+  for (i = 0; i < array->len; i++) {
+    EBookChange *change;
+    GValueArray *vals;
+
+    vals = g_ptr_array_index (array, i);
+
+    change = g_slice_new (EBookChange);
+    change->change_type = g_value_get_uint (g_value_array_get_nth (vals, 0));
+    change->contact = e_contact_new_from_vcard
+      (g_value_get_string (g_value_array_get_nth (vals, 1)));
+
+    l = g_list_prepend (l, change);
+  }
+  
+  g_ptr_array_foreach (array, (GFunc)g_value_array_free, NULL);
+  g_ptr_array_free (array, TRUE);
 
-	return e_book_async_remove_contact_by_id (book, id, cb, closure);
+  return g_list_reverse (l);
 }
 
 /**
- * e_book_async_remove_contact_by_id:
+ * e_book_get_changes:
  * @book: an #EBook
- * @id: a unique ID string specifying the contact
- * @cb: a function to call when the operation finishes
- * @closure: data to pass to callback function
+ * @changeid:  the change ID
+ * @changes: return location for a #GList of #EBookChange items
+ * @error: a #GError to set on failure.
  *
- * Removes the contact with id @id from @book.
+ * Get the set of changes since the previous call to #e_book_get_changes for a
+ * given change ID.
  *
- * Return value: %TRUE if successful, %FALSE otherwise
- **/
-guint
-e_book_async_remove_contact_by_id (EBook                 *book,
-				   const char            *id,
-				   EBookCallback          cb,
-				   gpointer               closure)
+ * Return value: TRUE on success, FALSE otherwise
+ */
+gboolean
+e_book_get_changes (EBook *book, char *changeid, GList **changes, GError **error)
 {
-	GList *list;
+  GError *err = NULL;
+  GPtrArray *array = NULL;
 
-	g_return_val_if_fail (E_IS_BOOK (book), TRUE);
-	g_return_val_if_fail (id != NULL, TRUE);
+  e_return_error_if_fail (E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
+  e_return_error_if_fail (book->priv->proxy, E_BOOK_ERROR_REPOSITORY_OFFLINE);
 
-	list = g_list_append (NULL, g_strdup (id));
+  org_gnome_evolution_dataserver_addressbook_Book_get_changes (book->priv->proxy, changeid, &array, &err);
+  if (!err) {
+    *changes = parse_changes_array (array);
+    return TRUE;
+  } else {
+    return unwrap_gerror (err, error);
+  }
+}
+
+static void
+get_changes_reply (DBusGProxy *proxy, GPtrArray *changes, GError *error, gpointer user_data)
+{
+  AsyncData *data = user_data;
+  EBookListCallback cb = data->callback;
+  GList *list = NULL;
+  
+  if (changes)
+    list = parse_changes_array (changes);
 
-	return e_book_async_remove_contacts (book, list, cb, closure);
+  if (cb)
+    cb (data->book, get_status_from_error (error), list, data->closure);
+
+  g_object_unref (data->book);
+  g_slice_free (AsyncData, data);
 }
 
 /**
- * e_book_async_remove_contacts:
+ * e_book_async_get_changes:
  * @book: an #EBook
- * @ids: a #GList of const char *id's
- * @cb: a function to call when the operation finishes
+ * @changeid:  the change ID
+ * @cb: function to call when operation finishes
  * @closure: data to pass to callback function
  *
- * Removes the contacts with ids from the list @ids from @book.  This is
- * always more efficient than calling e_book_remove_contact_by_id() if you
- * have more than one id to remove, as some backends can implement it
- * as a batch request.
+ * Get the set of changes since the previous call to #e_book_async_get_changes
+ * for a given change ID.
  *
- * Return value: %TRUE if successful, %FALSE otherwise
- **/
+ * Return value: TRUE on success, FALSE otherwise
+ */
 guint
-e_book_async_remove_contacts (EBook                 *book,
-			      GList                 *ids,
-			      EBookCallback          cb,
-			      gpointer               closure)
+e_book_async_get_changes (EBook *book, char *changeid, EBookListCallback cb, gpointer closure)
 {
-	g_return_val_if_fail (book && E_IS_BOOK (book), TRUE);
-	g_return_val_if_fail (ids,                      TRUE);
-
-	return !do_remove_contacts (FALSE,
-				    book, ids, NULL,
-				    cb, closure);
-}
-
-
-static gboolean
-do_get_book_view (gboolean sync,
-		  EBook *book,
-		  EBookQuery *query,
-		  GList *requested_fields,
-		  int max_results,
-		  EBookView **book_view,
-		  GError **error,
-		  EBookBookViewCallback cb,
-		  gpointer closure)
-{
-	GNOME_Evolution_Addressbook_stringlist stringlist;
-	CORBA_Environment ev;
-	EBookOp *our_op;
-	EBookStatus status;
-	int num_fields, i;
-	GList *iter;
-	char *query_string;
-
-	g_mutex_lock (book->priv->mutex);
-
-	if (book->priv->load_state != E_BOOK_SOURCE_LOADED) {
-		g_mutex_unlock (book->priv->mutex);
-		if (error) {
-			g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_SOURCE_NOT_LOADED,
-				     _("\"%s\" on book before \"%s\""),
-				     "e_book_get_book_view", "e_book_open");
-		}
-		else {
-			g_warning (_("\"%s\" on book before \"%s\""),
-				   "e_book_get_book_view", "e_book_open");
-		}
-		return FALSE;
-	}
-
-	if (sync && e_book_get_current_sync_op (book) != NULL) {
-		g_mutex_unlock (book->priv->mutex);
-		g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY,
-			     _("book busy"));
-		return FALSE;
-	}
+  AsyncData *data;
 
-	our_op = e_book_new_op (book, sync);
+  e_return_async_error_val_if_fail (E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
+  e_return_async_error_val_if_fail (book->priv->proxy, E_BOOK_ERROR_REPOSITORY_OFFLINE);
 
-	g_mutex_unlock (book->priv->mutex);
+  data = g_slice_new0 (AsyncData);
+  data->book = g_object_ref (book);
+  data->callback = cb;
+  data->closure = closure;
 
-	CORBA_exception_init (&ev);
-
-	our_op->listener = e_book_view_listener_new();
-
-	num_fields = g_list_length (requested_fields);
+  org_gnome_evolution_dataserver_addressbook_Book_get_changes_async (book->priv->proxy, changeid, get_changes_reply, data);
+  return 0;
+}
 
-	stringlist._buffer = CORBA_sequence_CORBA_string_allocbuf (num_fields);
-	stringlist._maximum = num_fields;
-	stringlist._length = num_fields;
+/**
+ * e_book_free_change_list:
+ * @change_list: a #GList of #EBookChange items
+ *
+ * Free the contents of #change_list, and the list itself.
+ */
+void
+e_book_free_change_list (GList *change_list)
+{
+	GList *l;
+	for (l = change_list; l; l = l->next) {
+		EBookChange *change = l->data;
 
-	for (i = 0, iter = requested_fields; iter; iter = iter->next, i ++) {
-		stringlist._buffer[i] = CORBA_string_dup ((char*)iter->data);
+		g_object_unref (change->contact);
+		g_slice_free (EBookChange, change);
 	}
 
-	query_string = e_book_query_to_string (query);
-
-	our_op->cb.book_view = cb;
-	our_op->closure = closure;
-
-	/* will eventually end up calling e_book_response_get_book_view */
-	GNOME_Evolution_Addressbook_Book_getBookView (book->priv->corba_book,
-						      our_op->opid,
-						      bonobo_object_corba_objref(BONOBO_OBJECT(our_op->listener)),
-						      query_string,
-						      &stringlist, max_results, &ev);
-
-	CORBA_free(stringlist._buffer);
-	g_free (query_string);
-
-	if (ev._major != CORBA_NO_EXCEPTION) {
-
-		g_mutex_lock (book->priv->mutex);
-		e_book_clear_op (book, our_op);
-		g_mutex_unlock (book->priv->mutex);
+	g_list_free (change_list);
+}
 
-		CORBA_exception_free (&ev);
+/**
+ * e_book_add_contact:
+ * @book: an #EBook
+ * @contact: an #EContact
+ * @error: a #GError to set on failure
+ *
+ * Adds @contact to @book.
+ *
+ * Return value: %TRUE if successful, %FALSE otherwise.
+ **/
+gboolean
+e_book_add_contact (EBook *book, EContact *contact, GError **error)
+{
+  GError *err = NULL;
+  char *vcard, *uid = NULL;
 
-		if (error) {
-			g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION,
-				     _("CORBA exception making \"%s\" call"),
-				     "Book::authenticateUser");
-		}
-		else {
-			g_warning (_("CORBA exception making \"%s\" call"),
-				   "Book::authenticateUser");
-		}
+  e_return_error_if_fail (E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
+  e_return_error_if_fail (book->priv->proxy, E_BOOK_ERROR_REPOSITORY_OFFLINE);
+  e_return_error_if_fail (E_IS_CONTACT (contact), E_BOOK_ERROR_INVALID_ARG);
 
-		return FALSE;
-	}
+  vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
+  org_gnome_evolution_dataserver_addressbook_Book_add_contact (book->priv->proxy, vcard, &uid, &err);
+  g_free (vcard);
+  if (uid) {
+    e_contact_set (contact, E_CONTACT_UID, uid);
+    g_free (uid);
+  }
+  return unwrap_gerror (err, error);
+}
 
-	CORBA_exception_free (&ev);
+static void
+add_contact_reply (DBusGProxy *proxy, char *uid, GError *error, gpointer user_data)
+{
+  AsyncData *data = user_data;
+  EBookIdCallback cb = data->callback;
 
-	if (sync) {
-		/* wait for something to happen (both cancellation and a
-		   successful response will notity us via our cv */
-		e_flag_wait (our_op->flag);
+  /* If there is an error returned the GLib bindings currently return garbage
+     for the OUT values. This is bad. */
+  if (error)
+    uid = NULL;
 
-		status = our_op->status;
-		*book_view = our_op->view;
+  if (cb)
+    cb (data->book, get_status_from_error (error), uid, data->closure);
 
-		g_mutex_lock (book->priv->mutex);
-		e_book_clear_op (book, our_op);
-		g_mutex_unlock (book->priv->mutex);
+  if (uid)
+    g_free (uid);
 
-		E_BOOK_CHECK_STATUS (status, error);
-	}
-	else {
-		return TRUE;
-	}
+  g_object_unref (data->book);
+  g_slice_free (AsyncData, data);
 }
 
 /**
- * e_book_get_book_view:
+ * e_book_async_add_contact:
  * @book: an #EBook
- * @query: an #EBookQuery
- * @requested_fields: a #GList containing the names of fields to return, or NULL for all
- * @max_results: the maximum number of contacts to show (or 0 for all)
- * @book_view: A #EBookView pointer, will be set to the view
- * @error: a #GError to set on failure
+ * @contact: an #EContact
+ * @cb: function to call when the operation finishes
+ * @closure: data to pass to callback function
  *
- * Query @book with @query, creating a #EBookView in @book_view with the fields
- * specified by @requested_fields and limited at @max_results records. On an
- * error, @error is set and %FALSE returned.
- *
- * Return value: %TRUE if successful, %FALSE otherwise
- **/
-gboolean
-e_book_get_book_view (EBook       *book,
-		      EBookQuery  *query,
-		      GList       *requested_fields,
-		      int          max_results,
-		      EBookView  **book_view,
-		      GError     **error)
-{
-	e_return_error_if_fail (book && E_IS_BOOK (book),       E_BOOK_ERROR_INVALID_ARG, FALSE);
-	e_return_error_if_fail (query,                          E_BOOK_ERROR_INVALID_ARG, FALSE);
-	e_return_error_if_fail (book_view,                      E_BOOK_ERROR_INVALID_ARG, FALSE);
-
-	return do_get_book_view (TRUE,
-				 book, query, requested_fields, max_results, book_view, error,
-				 NULL, NULL);
-}
-
-/**
- * e_book_async_get_book_view:
- * @book: an #EBook
- * @query: an #EBookQuery
- * @requested_fields: a #GList containing the names of fields to return, or NULL for all
- * @max_results: the maximum number of contacts to show (or 0 for all)
- * @cb: a function to call when the operation finishes
- * @closure: data to pass to callback function
- *
- * Query @book with @query, creating a #EBookView with the fields
- * specified by @requested_fields and limited at @max_results records.
- *
- * Return value: %FALSE if successful, %TRUE otherwise
- **/
-guint
-e_book_async_get_book_view (EBook                 *book,
-			    EBookQuery            *query,
-			    GList                 *requested_fields,
-			    int                    max_results,
-			    EBookBookViewCallback  cb,
-			    gpointer               closure)
-{
-	g_return_val_if_fail (book && E_IS_BOOK (book),       TRUE);
-	g_return_val_if_fail (query,                          TRUE);
-
-	return !do_get_book_view (FALSE,
-				  book, query, requested_fields, max_results, NULL, NULL,
-				  cb, closure);
-}
-
-static gboolean
-emit_async_get_book_view_response (gpointer data)
-{
-	EBookOp *op = data;
-	EBook *book = op->book;
-
-	if (op->cb.book_view)
-		op->cb.book_view (book, op->status, op->view, op->closure);
-
-	g_mutex_lock (book->priv->mutex);
-
-	g_object_unref (op->view);
-
-	book->priv->pending_idles = g_list_remove (book->priv->pending_idles,
-						   GINT_TO_POINTER (op->idle_id));
-
-	e_book_clear_op (book, op);
-
-	g_mutex_unlock (book->priv->mutex);
-	g_object_unref (book);
-
-	return FALSE;
-}
-
-static void
-e_book_response_get_book_view (EBook       *book,
-			       guint32      opid,
-			       EBookStatus  status,
-			       GNOME_Evolution_Addressbook_BookView corba_book_view)
-{
-
-	EBookOp *op;
-
-	d(printf ("e_book_response_get_book_view\n"));
-
-	g_mutex_lock (book->priv->mutex);
-
-	op = e_book_get_op (book, opid);
-
-	if (op == NULL) {
-		g_mutex_unlock (book->priv->mutex);
-		g_warning ("e_book_response_get_book_view: Cannot find operation ");
-		return;
-	}
-
-	op->status = status;
-	op->view = e_book_view_new (corba_book_view, op->listener);
-	e_book_view_set_book (op->view, book);
-
-	bonobo_object_unref(BONOBO_OBJECT(op->listener));
-
-	if (op->synchronous)
-		e_flag_set (op->flag);
-	else {
-		op->book = g_object_ref (book);
-
-		op->idle_id = g_idle_add (emit_async_get_book_view_response, op);
-		book->priv->pending_idles = g_list_prepend (book->priv->pending_idles,
-							    GINT_TO_POINTER (op->idle_id));
-	}
-
-	g_mutex_unlock (book->priv->mutex);
-}
-
-static gboolean
-do_get_contacts (gboolean sync,
-		 EBook *book,
-		 EBookQuery *query,
-		 GList **contacts,
-		 GError **error,
-		 EBookListCallback cb,
-		 gpointer closure)
-{
-	CORBA_Environment ev;
-	EBookOp *our_op;
-	EBookStatus status;
-	char *query_string;
-
-	g_mutex_lock (book->priv->mutex);
-
-	if (book->priv->load_state != E_BOOK_SOURCE_LOADED) {
-		g_mutex_unlock (book->priv->mutex);
-		if (error) {
-			g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_SOURCE_NOT_LOADED,
-				     _("\"%s\" on book before \"%s\""),
-				     "e_book_get_contacts", "e_book_open");
-		}
-		else {
-			g_warning (_("\"%s\" on book before \"%s\""),
-				   "e_book_get_contacts", "e_book_open");
-		}
-
-		return FALSE;
-	}
-
-	if (sync && e_book_get_current_sync_op (book) != NULL) {
-		g_mutex_unlock (book->priv->mutex);
-		g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY,
-			     _("book busy"));
-		return FALSE;
-	}
-
-	our_op = e_book_new_op (book, sync);
-
-	g_mutex_unlock (book->priv->mutex);
-
-	CORBA_exception_init (&ev);
-
-	query_string = e_book_query_to_string (query);
-
-	our_op->cb.list = cb;
-	our_op->closure = closure;
-
-	/* will eventually end up calling e_book_response_get_contacts */
-	GNOME_Evolution_Addressbook_Book_getContactList (book->priv->corba_book, our_op->opid, query_string, &ev);
-
-	g_free (query_string);
-
-	if (ev._major != CORBA_NO_EXCEPTION) {
-
-		g_mutex_lock (book->priv->mutex);
-		e_book_clear_op (book, our_op);
-		g_mutex_unlock (book->priv->mutex);
-
-		CORBA_exception_free (&ev);
-
-		if (error) {
-			g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION,
-				     _("CORBA exception making \"%s\" call"),
-				     "Book::getContactList");
-		}
-		else {
-			g_warning (_("CORBA exception making \"%s\" call"),
-				   "Book::getContactList");
-		}
-
-		return FALSE;
-	}
-
-	CORBA_exception_free (&ev);
-
-	if (sync) {
-		/* wait for something to happen (both cancellation and a
-		   successful response will notity us via our cv */
-		e_flag_wait (our_op->flag);
-
-		status = our_op->status;
-		*contacts = our_op->list;
-
-		g_mutex_lock (book->priv->mutex);
-		e_book_clear_op (book, our_op);
-		g_mutex_unlock (book->priv->mutex);
-
-		E_BOOK_CHECK_STATUS (status, error);
-	}
-	else {
-		return TRUE;
-	}
-}
-
-/**
- * e_book_get_contacts:
- * @book: an #EBook
- * @query: an #EBookQuery
- * @contacts: a #GList pointer, will be set to the list of contacts
- * @error: a #GError to set on failure
- *
- * Query @book with @query, setting @contacts to the list of contacts which
- * matched. On failed, @error will be set and %FALSE returned.
- *
- * Return value: %TRUE on success, %FALSE otherwise
- **/
-gboolean
-e_book_get_contacts (EBook       *book,
-		     EBookQuery  *query,
-		     GList      **contacts,
-		     GError     **error)
-{
-	e_return_error_if_fail (book && E_IS_BOOK (book),       E_BOOK_ERROR_INVALID_ARG, FALSE);
-	e_return_error_if_fail (query,                          E_BOOK_ERROR_INVALID_ARG, FALSE);
-	e_return_error_if_fail (contacts,                       E_BOOK_ERROR_INVALID_ARG, FALSE);
-
-	return do_get_contacts (TRUE,
-				book, query, contacts, error,
-				NULL, NULL);
-}
-
-/**
- * e_book_async_get_contacts:
- * @book: an #EBook
- * @query: an #EBookQuery
- * @cb: a function to call when the operation finishes
- * @closure: data to pass to callback function
- *
- * Query @book with @query.
- *
- * Return value: %FALSE on success, %TRUE otherwise
- **/
-guint
-e_book_async_get_contacts (EBook             *book,
-			   EBookQuery        *query,
-			   EBookListCallback  cb,
-			   gpointer           closure)
-{
-	g_return_val_if_fail (book && E_IS_BOOK (book),       TRUE);
-	g_return_val_if_fail (query,                          TRUE);
-
-	return !do_get_contacts (FALSE,
-				 book, query, NULL, NULL,
-				 cb, closure);
-}
-
-static gboolean
-emit_async_get_contacts_response (gpointer data)
-{
-	EBookOp *op = data;
-	EBook *book = op->book;
-
-	if (op->cb.list)
-		op->cb.list (book, op->status, op->list, op->closure);
-
-	g_mutex_lock (book->priv->mutex);
-
-	g_list_foreach (op->list, (GFunc)g_object_unref, NULL);
-	g_list_free (op->list);
-
-	book->priv->pending_idles = g_list_remove (book->priv->pending_idles,
-						   GINT_TO_POINTER (op->idle_id));
-
-	e_book_clear_op (book, op);
-
-	g_mutex_unlock (book->priv->mutex);
-	g_object_unref (book);
-
-	return FALSE;
-}
-
-
-static void
-e_book_response_get_contacts (EBook       *book,
-			      guint32      opid,
-			      EBookStatus  status,
-			      GList       *contact_list)
-{
-
-	EBookOp *op;
-
-	g_mutex_lock (book->priv->mutex);
-
-	op = e_book_get_op (book, opid);
-
-	if (op == NULL) {
-		g_mutex_unlock (book->priv->mutex);
-		g_warning ("e_book_response_get_contacts: Cannot find operation ");
-		return;
-	}
-
-	op->list = g_list_copy (contact_list);
-	g_list_foreach (op->list, (GFunc)g_object_ref, NULL);
-	op->status = status;
-
-	if (op->synchronous)
-		e_flag_set (op->flag);
-	else {
-		op->book = g_object_ref (book);
-		op->idle_id = g_idle_add (emit_async_get_contacts_response, op);
-		book->priv->pending_idles = g_list_prepend (book->priv->pending_idles,
-							    GINT_TO_POINTER (op->idle_id));
-	}
-
-	g_mutex_unlock (book->priv->mutex);
-}
-
-
-static gboolean
-do_get_changes (gboolean sync,
-		EBook *book,
-		char *changeid,
-		GList **changes,
-		GError **error,
-		EBookListCallback cb,
-		gpointer closure)
-{
-	CORBA_Environment ev;
-	EBookOp *our_op;
-	EBookStatus status;
-
-	g_mutex_lock (book->priv->mutex);
-
-	if (book->priv->load_state != E_BOOK_SOURCE_LOADED) {
-		g_mutex_unlock (book->priv->mutex);
-		if (error) {
-			g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_SOURCE_NOT_LOADED,
-				     _("\"%s\" on book before \"%s\""),
-				     "e_book_get_changes", "e_book_open");
-		}
-		else {
-			g_warning (_("\"%s\" on book before \"%s\""),
-				   "e_book_get_changes", "e_book_open");
-		}
-		return FALSE;
-	}
-
-	if (sync && e_book_get_current_sync_op (book) != NULL) {
-		g_mutex_unlock (book->priv->mutex);
-		g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY,
-			     _("book busy"));
-		return FALSE;
-	}
-
-	our_op = e_book_new_op (book, sync);
-
-	g_mutex_unlock (book->priv->mutex);
-
-	CORBA_exception_init (&ev);
-
-	our_op->cb.list = cb;
-	our_op->closure = closure;
-
-	/* will eventually end up calling e_book_response_get_changes */
-	GNOME_Evolution_Addressbook_Book_getChanges (book->priv->corba_book, our_op->opid, changeid, &ev);
-
-	if (ev._major != CORBA_NO_EXCEPTION) {
-
-		g_mutex_lock (book->priv->mutex);
-		e_book_clear_op (book, our_op);
-		g_mutex_unlock (book->priv->mutex);
-
-		CORBA_exception_free (&ev);
-
-		if (error) {
-			g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION,
-				     _("CORBA exception making \"%s\" call"),
-				     "Book::getChanges");
-		}
-		else {
-			g_warning (_("CORBA exception making \"%s\" call"),
-				   "Book::getChanges");
-		}
-
-		return FALSE;
-	}
-
-	CORBA_exception_free (&ev);
-
-	if (sync) {
-		/* wait for something to happen (both cancellation and a
-		   successful response will notity us via our cv */
-		e_flag_wait (our_op->flag);
-
-		status = our_op->status;
-		*changes = our_op->list;
-
-		g_mutex_lock (book->priv->mutex);
-		e_book_clear_op (book, our_op);
-		g_mutex_unlock (book->priv->mutex);
-
-		E_BOOK_CHECK_STATUS (status, error);
-	}
-	else {
-		return TRUE;
-	}
-}
-
-/**
- * e_book_get_changes:
- * @book: an #EBook
- * @changeid:  the change ID
- * @changes: return location for a #GList of #EBookChange items
- * @error: a #GError to set on failure.
- *
- * Get the set of changes since the previous call to #e_book_get_changes for a
- * given change ID.
- *
- * Return value: TRUE on success, FALSE otherwise
- */
-gboolean
-e_book_get_changes (EBook       *book,
-		    char        *changeid,
-		    GList      **changes,
-		    GError     **error)
-{
-	e_return_error_if_fail (book && E_IS_BOOK (book),       E_BOOK_ERROR_INVALID_ARG, FALSE);
-	e_return_error_if_fail (changeid,                       E_BOOK_ERROR_INVALID_ARG, FALSE);
-	e_return_error_if_fail (changes,                        E_BOOK_ERROR_INVALID_ARG, FALSE);
-
-	return do_get_changes (TRUE,
-			       book, changeid, changes, error,
-			       NULL, NULL);
-}
-
-/**
- * e_book_async_get_changes:
- * @book: an #EBook
- * @changeid:  the change ID
- * @cb: function to call when operation finishes
- * @closure: data to pass to callback function
- *
- * Get the set of changes since the previous call to #e_book_async_get_changes
- * for a given change ID.
- *
- * Return value: TRUE on success, FALSE otherwise
- */
-guint
-e_book_async_get_changes (EBook             *book,
-			  char              *changeid,
-			  EBookListCallback  cb,
-			  gpointer           closure)
-{
-	g_return_val_if_fail (book && E_IS_BOOK (book),       TRUE);
-	g_return_val_if_fail (changeid,                       TRUE);
-
-	return !do_get_changes (FALSE,
-				book, changeid, NULL, NULL,
-				cb, closure);
-}
-
-static gboolean
-emit_async_get_changes_response (gpointer data)
-{
-	EBookOp *op = data;
-	EBook *book = op->book;
-
-	if (op->cb.list)
-		op->cb.list (book, op->status, op->list, op->closure);
-
-	g_mutex_lock (book->priv->mutex);
-
-	e_book_free_change_list (op->list);
-
-	book->priv->pending_idles = g_list_remove (book->priv->pending_idles,
-						   GINT_TO_POINTER (op->idle_id));
-
-	e_book_clear_op (book, op);
-
-	g_mutex_unlock (book->priv->mutex);
-	g_object_unref (book);
-
-	return FALSE;
-}
-
-static void
-e_book_response_get_changes (EBook       *book,
-			     guint32      opid,
-			     EBookStatus  status,
-			     GList       *change_list)
-{
-
-	EBookOp *op;
-
-	g_mutex_lock (book->priv->mutex);
-
-	op = e_book_get_op (book, opid);
-
-	if (op == NULL) {
-		g_mutex_unlock (book->priv->mutex);
-		g_warning ("e_book_response_get_changes: Cannot find operation ");
-		return;
-	}
-
-	op->status = status;
-	op->list = change_list;
-
-	if (op->synchronous)
-		e_flag_set (op->flag);
-	else {
-		op->book = g_object_ref (book);
-		op->idle_id = g_idle_add (emit_async_get_changes_response, op);
-		book->priv->pending_idles = g_list_prepend (book->priv->pending_idles,
-							    GINT_TO_POINTER (op->idle_id));
-	}
-
-	g_mutex_unlock (book->priv->mutex);
-}
-
-/**
- * e_book_free_change_list:
- * @change_list: a #GList of #EBookChange items
- *
- * Free the contents of #change_list, and the list itself.
- */
-void
-e_book_free_change_list (GList *change_list)
-{
-	GList *l;
-	for (l = change_list; l; l = l->next) {
-		EBookChange *change = l->data;
-
-		g_object_unref (change->contact);
-		g_free (change);
-	}
-
-	g_list_free (change_list);
-}
-
-
-
-static gboolean
-emit_async_generic_response (gpointer data)
-{
-	EBookOp *op = data;
-	EBook *book = op->book;
-
-	if (op->cb.status)
-		op->cb.status (book, op->status, op->closure);
-
-	g_mutex_lock (book->priv->mutex);
-
-	book->priv->pending_idles = g_list_remove (book->priv->pending_idles,
-						   GINT_TO_POINTER (op->idle_id));
-
-	e_book_clear_op (book, op);
-
-	g_mutex_unlock (book->priv->mutex);
-	g_object_unref (book);
-
-	return FALSE;
-}
-
-static void
-e_book_response_generic (EBook       *book,
-			 guint32      opid,
-			 EBookStatus  status)
-{
-	EBookOp *op;
-	d(printf("e_book_response_generic\n"));
-	g_mutex_lock (book->priv->mutex);
-
-	op = e_book_get_op (book, opid);
-
-	if (op == NULL) {
-		g_mutex_unlock (book->priv->mutex);
-		g_warning ("e_book_response_generic: Cannot find operation ");
-		return;
-	}
-
-	op->status = status;
-	if (op->synchronous)
-		e_flag_set (op->flag);
-	else {
-		op->book = g_object_ref (book);
-		op->idle_id = g_idle_add (emit_async_generic_response, op);
-		book->priv->pending_idles = g_list_prepend (book->priv->pending_idles,
-							    GINT_TO_POINTER (op->idle_id));
-	}
-
-	g_mutex_unlock (book->priv->mutex);
-}
-
-/**
- * e_book_cancel:
- * @book: an #EBook
- * @error: a #GError to set on failure
+ * Adds @contact to @book without blocking. 
  *
- * Used to cancel an already running operation on @book.  This
- * function makes a synchronous CORBA to the backend telling it to
- * cancel the operation.  If the operation wasn't cancellable (either
- * transiently or permanently) or had already comopleted on the server
- * side, this function will return E_BOOK_STATUS_COULD_NOT_CANCEL, and
- * the operation will continue uncancelled.  If the operation could be
- * cancelled, this function will return E_BOOK_ERROR_OK, and the
- * blocked e_book function corresponding to current operation will
- * return with a status of E_BOOK_STATUS_CANCELLED.
- *
- * Return value: %TRUE on success, %FALSE otherwise
+ * Return value: %TRUE if the operation was started, %FALSE otherwise.
  **/
 gboolean
-e_book_cancel (EBook   *book,
-	       GError **error)
-{
-	EBookOp *op;
-	EBookStatus status;
-	gboolean rv;
-	CORBA_Environment ev;
-
-	e_return_error_if_fail (book && E_IS_BOOK (book),       E_BOOK_ERROR_INVALID_ARG, FALSE);
-
-	g_mutex_lock (book->priv->mutex);
-
-	if (e_book_get_current_sync_op (book) == NULL) {
-		g_mutex_unlock (book->priv->mutex);
-		g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_COULD_NOT_CANCEL,
-			     _("%s: there is no current operation"), "e_book_cacnel");
-		return FALSE;
-	}
-
-	op = e_book_get_current_sync_op (book);
-
-	g_mutex_unlock (book->priv->mutex);
-
-	status = GNOME_Evolution_Addressbook_Book_cancelOperation(book->priv->corba_book, &ev);
-
-	if (ev._major != CORBA_NO_EXCEPTION) {
-
-		CORBA_exception_free (&ev);
-
-		g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION,
-			     _("CORBA exception making \"%s\" call"),
-			     "Book::cancelOperation");
-		return FALSE;
-	}
-
-	CORBA_exception_free (&ev);
-
-	if (status == E_BOOK_ERROR_OK) {
-		op->status = E_BOOK_ERROR_CANCELLED;
-		e_flag_set (op->flag);
-		rv = TRUE;
-	}
-	else {
-		g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_COULD_NOT_CANCEL,
-			     _("%s: could not cancel"), "e_book_cancel");
-		rv = FALSE;
-	}
-
-	return rv;
-}
-
-
-
-static gboolean
-do_open (gboolean sync,
-	 EBook *book,
-	 gboolean only_if_exists,
-	 GError **error,
-	 EBookCallback cb,
-	 gpointer closure)
-{
-	CORBA_Environment ev;
-	EBookOp *our_op;
-	EBookStatus status;
-
-	g_mutex_lock (book->priv->mutex);
-
-	if (book->priv->load_state != E_BOOK_SOURCE_NOT_LOADED) {
-		g_mutex_unlock (book->priv->mutex);
-		if (error) {
-			g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_SOURCE_ALREADY_LOADED,
-				     _("\"%s\" on book after \"%s\""),
-				     "e_book_open", "e_book_open");
-		}
-		else {
-			g_warning (_("\"%s\" on book after \"%s\""),
-				   "e_book_open", "e_book_open");
-		}
-
-		return FALSE;
-	}
-
-	if (sync && e_book_get_current_sync_op (book) != NULL) {
-		g_mutex_unlock (book->priv->mutex);
-		g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY,
-			     _("book busy"));
-		return FALSE;
-	}
-
-	our_op = e_book_new_op (book, sync);
-
-	g_mutex_unlock (book->priv->mutex);
-
-	CORBA_exception_init (&ev);
-
-	our_op->cb.status = cb;
-	our_op->closure = closure;
-
-	/* will eventually end up calling e_book_response_remove */
-	GNOME_Evolution_Addressbook_Book_open (book->priv->corba_book, our_op->opid, only_if_exists, &ev);
-
-	if (ev._major != CORBA_NO_EXCEPTION) {
-
-		g_mutex_lock (book->priv->mutex);
-		e_book_clear_op (book, our_op);
-		g_mutex_unlock (book->priv->mutex);
-
-		CORBA_exception_free (&ev);
-
-		if (error) {
-			g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION,
-				     _("CORBA exception making \"%s\" call"),
-				     "Book::open");
-		}
-		else {
-			g_warning (_("CORBA exception making \"%s\" call"),
-				   "Book::open");
-		}
-
-		return FALSE;
-	}
-
-	CORBA_exception_free (&ev);
-
-	if (sync) {
-		/* wait for something to happen (both cancellation and a
-		   successful response will notity us via our cv */
-		e_flag_wait (our_op->flag);
-
-		status = our_op->status;
-
-		g_mutex_lock (book->priv->mutex);
-		e_book_clear_op (book, our_op);
-		g_mutex_unlock (book->priv->mutex);
-
-		if (status == E_BOOK_ERROR_CANCELLED) {
-			/* Cancelled */
-			book->priv->load_state = E_BOOK_SOURCE_NOT_LOADED;
-			g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CANCELLED,
-				     _("%s: canceled"), "e_book_open");
-			return FALSE;
-		}
-		else if (status == E_BOOK_ERROR_OK) {
-			book->priv->load_state = E_BOOK_SOURCE_LOADED;
-			return TRUE;
-		}
-		else {
-			E_BOOK_CHECK_STATUS (status, error);
-		}
-	}
-	else {
-		return TRUE;
-	}
-}
-
-/**
- * e_book_open:
- * @book: an #EBook
- * @only_if_exists: if %TRUE, fail if this book doesn't already exist, otherwise create it first
- * @error: a #GError to set on failure
- *
- * Opens the addressbook, making it ready for queries and other operations.
- *
- * Return value: %TRUE if the book was successfully opened, %FALSE otherwise.
- */
-gboolean
-e_book_open (EBook     *book,
-	     gboolean   only_if_exists,
-	     GError   **error)
-{
-	e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG, FALSE);
-
-	return do_open (TRUE,
-			book, only_if_exists, error,
-			NULL, NULL);
-}
-
-/**
- * e_book_async_open:
- * @book: an #EBook
- * @only_if_exists: if %TRUE, fail if this book doesn't already exist, otherwise create it first
- * @open_response: a function to call when the operation finishes
- * @closure: data to pass to callback function
- *
- * Opens the addressbook, making it ready for queries and other operations.
- * This function does not block.
- *
- * Return value: %FALSE if successful, %TRUE otherwise.
- **/
-guint
-e_book_async_open (EBook                 *book,
-		   gboolean               only_if_exists,
-		   EBookCallback          open_response,
-		   gpointer               closure)
-{
-	g_return_val_if_fail (book && E_IS_BOOK (book), FALSE);
-
-	return !do_open (FALSE,
-			 book, only_if_exists, NULL,
-			 open_response, closure);
-}
-
-static gboolean
-emit_async_open_response (gpointer data)
+e_book_async_add_contact (EBook *book, EContact *contact, EBookIdCallback cb, gpointer closure)
 {
-	EBookOp *op = data;
-	EBook *book = op->book;
+  char *vcard;
+  AsyncData *data;
 
-	d(printf ("in async_open_response\n"));
-
-	g_mutex_lock (book->priv->mutex);
-
-	if (op->status == E_BOOK_ERROR_OK)
-		book->priv->load_state = E_BOOK_SOURCE_LOADED;
-	else
-		book->priv->load_state = E_BOOK_SOURCE_NOT_LOADED;
-
-	g_mutex_unlock (book->priv->mutex);
-
-	if (op->cb.status)
-		op->cb.status (book, op->status, op->closure);
-
-	g_mutex_lock (book->priv->mutex);
-
-	book->priv->pending_idles = g_list_remove (book->priv->pending_idles,
-						   GINT_TO_POINTER (op->idle_id));
-
-	e_book_clear_op (book, op);
-
-	g_mutex_unlock (book->priv->mutex);
-	g_object_unref (book);
-
-	return FALSE;
-}
-
-static void
-e_book_response_open (EBook       *book,
-		      guint32      opid,
-		      EBookStatus  status)
-{
-	EBookOp *op;
-
-	d(printf ("in e_book_response_open\n"));
-
-	g_mutex_lock (book->priv->mutex);
-
-	op = e_book_get_op (book, opid);
-
-	if (op == NULL) {
-		g_mutex_unlock (book->priv->mutex);
-		g_warning ("e_book_response_open: Cannot find operation ");
-		return;
-	}
-
-	op->status = status;
-	if (op->synchronous)
-		e_flag_set (op->flag);
-	else {
-		op->book = g_object_ref (book);
-		op->idle_id = g_idle_add (emit_async_open_response, op);
-		book->priv->pending_idles = g_list_prepend (book->priv->pending_idles,
-							    GINT_TO_POINTER (op->idle_id));
-	}
-
-	g_mutex_unlock (book->priv->mutex);
-}
-
-
-static gboolean
-do_remove (gboolean sync,
-	   EBook *book,
-	   GError **error,
-	   EBookCallback cb,
-	   gpointer closure)
-{
-	CORBA_Environment ev;
-	EBookOp *our_op;
-	EBookStatus status;
-
-	g_mutex_lock (book->priv->mutex);
-
-	if (sync && e_book_get_current_sync_op (book) != NULL) {
-		g_mutex_unlock (book->priv->mutex);
-		g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_BUSY,
-			     _("book busy"));
-		return FALSE;
-	}
-
-	our_op = e_book_new_op (book, sync);
-
-	g_mutex_unlock (book->priv->mutex);
-
-	CORBA_exception_init (&ev);
-
-	our_op->cb.status = cb;
-	our_op->closure = closure;
-
-	/* will eventually end up calling e_book_response_remove */
-	GNOME_Evolution_Addressbook_Book_remove (book->priv->corba_book, our_op->opid, &ev);
-
-	if (ev._major != CORBA_NO_EXCEPTION) {
-
-		g_mutex_lock (book->priv->mutex);
-		e_book_clear_op (book, our_op);
-		g_mutex_unlock (book->priv->mutex);
-
-		CORBA_exception_free (&ev);
-
-		if (error) {
-			g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION,
-				     _("CORBA exception making \"%s\" call"),
-				     "Book::remove");
-		}
-		else {
-			g_warning (_("CORBA exception making \"%s\" call"),
-				   "Book::remove");
-		}
-
-		return FALSE;
-	}
-
-	CORBA_exception_free (&ev);
-
-	if (sync) {
-		/* wait for something to happen (both cancellation and a
-		   successful response will notity us via our cv */
-		e_flag_wait (our_op->flag);
-
-		status = our_op->status;
-
-		g_mutex_lock (book->priv->mutex);
-		e_book_clear_op (book, our_op);
-		g_mutex_unlock (book->priv->mutex);
-
-		E_BOOK_CHECK_STATUS (status, error);
-	}
-	else {
-		return TRUE;
-	}
-}
-
-/**
- * e_book_remove:
- * @book: an #EBook
- * @error: a #GError to set on failure
- *
- * Removes the backing data for this #EBook. For example, with the file backend this
- * deletes the database file. You cannot get it back!
- *
- * Return value: %TRUE on success, %FALSE on failure.
- */
-gboolean
-e_book_remove (EBook   *book,
-	       GError **error)
-{
-	e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG, FALSE);
-
-	return do_remove (TRUE,
-			  book, error,
-			  NULL, NULL);
-
-}
-
-/**
- * e_book_async_remove:
- * @book: an #EBook
- * @cb: a function to call when the operation finishes
- * @closure: data to pass to callback function
- *
- * Remove the backing data for this #EBook. For example, with the file backend this
- * deletes the database file. You cannot get it back!
- *
- * Return value: %FALSE if successful, %TRUE otherwise.
- **/
-guint
-e_book_async_remove (EBook   *book,
-		     EBookCallback cb,
-		     gpointer closure)
-{
-	g_return_val_if_fail (book && E_IS_BOOK (book), TRUE);
-
-	return !do_remove (FALSE,
-			   book, NULL,
-			   cb, closure);
-
-}
-
-static void
-e_book_response_remove (EBook       *book,
-			guint32      opid,
-			EBookStatus  status)
-{
-	EBookOp *op;
-
-	d(printf ("e_book_response_remove\n"));
-
-	g_mutex_lock (book->priv->mutex);
-
-	op = e_book_get_op (book, opid);
-
-	if (op == NULL) {
-		g_mutex_unlock (book->priv->mutex);
-		g_warning ("e_book_response_remove: Cannot find operation ");
-		return;
-	}
-
-	op->status = status;
-	if (op->synchronous)
-		e_flag_set (op->flag);
-	else {
-		op->book = g_object_ref (book);
-		op->idle_id = g_idle_add (emit_async_generic_response, op);
-		book->priv->pending_idles = g_list_prepend (book->priv->pending_idles,
-							    GINT_TO_POINTER (op->idle_id));
-	}
-
-	g_mutex_unlock (book->priv->mutex);
-}
-
-static gboolean
-e_book_idle_writable (gpointer data)
-{
-	EBook *book = data;
-	gboolean writable;
-
-	g_mutex_lock (book->priv->mutex);
-	writable = book->priv->writable;
-	book->priv->writable_idle_id = 0;
-	g_mutex_unlock (book->priv->mutex);
-
-	g_signal_emit (G_OBJECT (book), e_book_signals [WRITABLE_STATUS], 0, writable);
-
-	g_object_unref (book);
-
-	return FALSE;
-}
-
-static gboolean
-e_book_idle_connection (gpointer data)
-{
-	EBook *book = data;
-	gboolean connected;
-
-	if (!book->priv)
-		return FALSE;
-
-	g_mutex_lock (book->priv->mutex);
-	connected = book->priv->connected;
-	book->priv->connection_idle_id = 0;
-	g_mutex_unlock (book->priv->mutex);
-
-	g_signal_emit (G_OBJECT (book), e_book_signals [CONNECTION_STATUS], 0, connected);
-
-	g_object_unref (book);
-
-	return FALSE;
-}
-
-static gboolean
-e_book_idle_auth_required (gpointer data)
-{
-	EBook *book = data;
-	gboolean connected;
-
-	if (!book->priv)
-		return FALSE;
-
-	g_mutex_lock (book->priv->mutex);
-	connected = book->priv->connected;
-	book->priv->auth_idle_id = 0;
-	g_mutex_unlock (book->priv->mutex);
-
-	g_signal_emit (G_OBJECT (book), e_book_signals [AUTH_REQUIRED], 0);
-
-	g_object_unref (book);
-
-	return FALSE;
-
-
-}
+  e_return_async_error_val_if_fail (E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
+  e_return_async_error_val_if_fail (book->priv->proxy, E_BOOK_ERROR_REPOSITORY_OFFLINE);
+  e_return_async_error_val_if_fail (E_IS_CONTACT (contact), E_BOOK_ERROR_INVALID_ARG);
 
-static void
-e_book_handle_response (EBookListener *listener, EBookListenerResponse *resp, EBook *book)
-{
-	EContact *contact;
-
-	switch (resp->op) {
-	case CreateContactResponse:
-		e_book_response_add_contact (book, resp->opid, resp->status, resp->id);
-		break;
-	case RemoveContactResponse:
-	case ModifyContactResponse:
-	case AuthenticationResponse:
-		e_book_response_generic (book, resp->opid, resp->status);
-		break;
-	case GetContactResponse:
-		contact = e_contact_new_from_vcard (resp->vcard);
-		e_book_response_get_contact (book, resp->opid, resp->status, contact);
-		break;
-	case GetContactListResponse:
-		e_book_response_get_contacts (book, resp->opid, resp->status, resp->list);
-		break;
-	case GetBookViewResponse:
-		e_book_response_get_book_view(book, resp->opid, resp->status, resp->book_view);
-		break;
-	case GetChangesResponse:
-		e_book_response_get_changes(book, resp->opid, resp->status, resp->list);
-		break;
-	case OpenBookResponse:
-		e_book_response_open (book, resp->opid, resp->status);
-		break;
-	case RemoveBookResponse:
-		e_book_response_remove (book, resp->opid, resp->status);
-		break;
-	case GetSupportedFieldsResponse:
-		e_book_response_get_supported_fields (book, resp->opid, resp->status, resp->list);
-		break;
-	case GetRequiredFieldsResponse:
-		e_book_response_get_required_fields (book, resp->opid, resp->status, resp->list);
-		break;
-	case GetSupportedAuthMethodsResponse:
-		e_book_response_get_supported_auth_methods (book, resp->opid, resp->status, resp->list);
-		break;
-	case WritableStatusEvent:
-		book->priv->writable = resp->writable;
-
-		g_mutex_lock (book->priv->mutex);
-		if (book->priv->writable_idle_id == 0) {
-			g_object_ref (book);
-			book->priv->writable_idle_id = g_idle_add (e_book_idle_writable, book);
-		}
-		g_mutex_unlock (book->priv->mutex);
+  vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
 
-		break;
-	case LinkStatusEvent:
-		book->priv->connected = resp->connected;
-		g_mutex_lock (book->priv->mutex);
-		if (book->priv->connection_idle_id == 0) {
-			g_object_ref (book);
-			book->priv->connection_idle_id = g_idle_add (e_book_idle_connection, book);
-		}
-		g_mutex_unlock (book->priv->mutex);
-		break;
-	case AuthRequiredEvent:
-		g_mutex_lock (book->priv->mutex);
-		if (book->priv->auth_idle_id == 0) {
-			g_object_ref (book);
-			book->priv->auth_idle_id = g_idle_add (e_book_idle_auth_required, book);
-		}
-		g_mutex_unlock (book->priv->mutex);
-		break;
+  data = g_slice_new0 (AsyncData);
+  data->book = g_object_ref (book);
+  data->callback = cb;
+  data->closure = closure;
 
-	default:
-		g_error ("EBook: Unknown response code %d!\n",
-			 resp->op);
-	}
+  org_gnome_evolution_dataserver_addressbook_Book_add_contact_async (book->priv->proxy, vcard, add_contact_reply, data);
+  g_free (vcard);
+  return 0;
 }
 
-
-
 /**
- * e_book_unload_uri:
+ * e_book_commit_contact:
  * @book: an #EBook
- * @error: an #GError to set on failure
+ * @contact: an #EContact
+ * @error: a #GError to set on failure
  *
- * Unload the URI that this book had previously loaded.
+ * Applies the changes made to @contact to the stored version in
+ * @book.
  *
- * Return value: %TRUE on success, %FALSE otherwise.
- */
-static gboolean
-e_book_unload_uri (EBook   *book,
-		   GError **error)
+ * Return value: %TRUE if successful, %FALSE otherwise
+ **/
+gboolean
+e_book_commit_contact (EBook *book, EContact *contact, GError **error)
 {
-	CORBA_Environment ev;
-
-	e_return_error_if_fail (book && E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG, FALSE);
-	e_return_error_if_fail (book->priv->load_state != E_BOOK_SOURCE_NOT_LOADED, E_BOOK_ERROR_SOURCE_NOT_LOADED, FALSE);
-
-	if (book->priv->load_state == E_BOOK_SOURCE_LOADED) {
-		/* Release the remote GNOME_Evolution_Addressbook_Book in the PAS. */
-		CORBA_exception_init (&ev);
-
-		bonobo_object_release_unref  (book->priv->corba_book, &ev);
-		if (ev._major != CORBA_NO_EXCEPTION) {
-			g_warning ("e_book_unload_uri: Exception releasing "
-				   "remote book interface!\n");
-		}
+  GError *err = NULL;
+  char *vcard;
 
-		CORBA_exception_free (&ev);
+  e_return_error_if_fail (E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
+  e_return_error_if_fail (book->priv->proxy, E_BOOK_ERROR_REPOSITORY_OFFLINE);
+  e_return_error_if_fail (E_IS_CONTACT (contact), E_BOOK_ERROR_INVALID_ARG);
 
-		book->priv->corba_book = CORBA_OBJECT_NIL;
-		e_book_listener_stop (book->priv->listener);
-		bonobo_object_unref (BONOBO_OBJECT (book->priv->listener));
-
-		book->priv->listener   = NULL;
-		book->priv->load_state = E_BOOK_SOURCE_NOT_LOADED;
-		g_free (book->priv->cap);
-		book->priv->cap = NULL;
-		book->priv->cap_queried = FALSE;
-		book->priv->writable = FALSE;
-	}
-	else if (book->priv->load_state == E_BOOK_SOURCE_LOADING) {
-		e_book_cancel (book, error);
-	}
-
-	return TRUE;
+  vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
+  org_gnome_evolution_dataserver_addressbook_Book_modify_contact (book->priv->proxy, vcard, &err);
+  g_free (vcard);
+  return unwrap_gerror (err, error);
 }
 
-
-
-
-/* Set a flag for operation from the operation hash table */
 static void
-find_key_value (gpointer key, gpointer value, gpointer data)
+modify_contact_reply (DBusGProxy *proxy, GError *error, gpointer user_data)
 {
-	EBookOp *op;
+  AsyncData *data = user_data;
+  EBookCallback cb = data->callback;
 
-	op = value;
-
-	if (op == NULL) {
-		g_warning ("find_key_value: Cannot find operation ");
-		return;
-	}
+  if (cb)
+    cb (data->book, get_status_from_error (error), data->closure);
 
-	op->status = E_BOOK_ERROR_SOURCE_NOT_LOADED;
-	if (op->synchronous)
-		e_flag_set (op->flag);
+  g_object_unref (data->book);
+  g_slice_free (AsyncData, data);
 }
 
 /**
- * e_book_load_uri:
- */
-
-static void
-backend_died_cb (EComponentListener *cl, gpointer user_data)
+ * e_book_async_commit_contact:
+ * @book: an #EBook
+ * @contact: an #EContact
+ * @cb: function to call when the operation finishes
+ * @closure: data to pass to callback function
+ *
+ * Applies the changes made to @contact to the stored version in
+ * @book without blocking.
+ *
+ * Return value: %TRUE if the operation was started, %FALSE otherwise.
+ **/
+guint
+e_book_async_commit_contact (EBook *book, EContact *contact, EBookCallback cb, gpointer closure)
 {
-	EBook *book = (EBook *)user_data;
-	
-	d(printf ("backend_died_cb\n"));	
+  char *vcard;
+  AsyncData *data;
 
-	g_mutex_lock (book->priv->mutex);
-	g_hash_table_foreach (book->priv->id_to_op, find_key_value, NULL);
-	g_mutex_unlock (book->priv->mutex);
+  e_return_async_error_if_fail (E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
+  e_return_async_error_if_fail (book->priv->proxy, E_BOOK_ERROR_REPOSITORY_OFFLINE);
+  e_return_async_error_if_fail (E_IS_CONTACT (contact), E_BOOK_ERROR_INVALID_ARG);
 
-	book->priv->load_state = E_BOOK_SOURCE_NOT_LOADED;
-        g_signal_emit (book, e_book_signals [BACKEND_DIED], 0);
-}
+  vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
 
-static GList *
-activate_factories_for_uri (EBook *book, const char *uri)
-{
-	CORBA_Environment ev;
-	Bonobo_ServerInfoList *info_list = NULL;
-	int i;
-	char *query;
-	GList *factories = NULL;
-
-	query = "repo_ids.has ('IDL:GNOME/Evolution/DataServer/BookFactory:" API_VERSION "')";
-
-	CORBA_exception_init (&ev);
-
-	info_list = bonobo_activation_query (query, NULL, &ev);
-
-	if (ev._major != CORBA_NO_EXCEPTION) {
-		char *exc_text = bonobo_exception_get_text (&ev);
-		g_warning ("Cannot perform bonobo-activation query for book factories: %s", exc_text);
-		g_free (exc_text);
-		CORBA_exception_free (&ev);
-		goto done;
-		return NULL;
-	}
+  data = g_slice_new0 (AsyncData);
+  data->book = g_object_ref (book);
+  data->callback = cb;
+  data->closure = closure;
 
-	if (info_list->_length == 0) {
-		g_warning ("Can't find installed BookFactories");
-		CORBA_exception_free (&ev);
-		goto done;
-	}
+  org_gnome_evolution_dataserver_addressbook_Book_modify_contact_async (book->priv->proxy, vcard, modify_contact_reply, data);
+  g_free (vcard);
+  return 0;
+}
 
-	CORBA_exception_free (&ev);
+/**
+ * e_book_remove_contact:
+ * @book: an #EBook
+ * @id: a string
+ * @error: a #GError to set on failure
+ *
+ * Removes the contact with id @id from @book.
+ *
+ * Return value: %TRUE if successful, %FALSE otherwise
+ **/
+gboolean
+e_book_remove_contact (EBook *book, const char *id, GError **error)
+{
+  GError *err = NULL;
+  const char *l[2];
 
-	for (i = 0; i < info_list->_length; i ++) {
-		const Bonobo_ServerInfo *info;
-		GNOME_Evolution_Addressbook_BookFactory factory;
+  e_return_error_if_fail (E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
+  e_return_error_if_fail (book->priv->proxy, E_BOOK_ERROR_REPOSITORY_OFFLINE);
+  e_return_error_if_fail (id, E_BOOK_ERROR_INVALID_ARG);
 
-		info = info_list->_buffer + i;
+  l[0] = id;
+  l[1] = NULL;
 
-		factory = bonobo_activation_activate_from_id (info->iid, 0, NULL, NULL);
+  org_gnome_evolution_dataserver_addressbook_Book_remove_contacts (book->priv->proxy, l, &err);
+  return unwrap_gerror (err, error);
+}
 
-		if (factory == CORBA_OBJECT_NIL)
-			g_warning ("e_book_construct: Could not obtain a handle "
-				   "to the Personal Addressbook Server with IID `%s'\n", info->iid);
-		else
-			factories = g_list_append (factories, factory);
-	}
+static void
+remove_contact_reply (DBusGProxy *proxy, GError *error, gpointer user_data)
+{
+  AsyncData *data = user_data;
+  EBookCallback cb = data->callback;
 
- done:
-	if (info_list)
-		CORBA_free (info_list);
+  if (cb)
+    cb (data->book, get_status_from_error (error), data->closure);
 
-	return factories;
+  g_object_unref (data->book);
+  g_slice_free (AsyncData, data);
 }
 
-/* XXX hm, should this function hold a lock on book->priv->mutex?  It
-   doesn't seem to require it, but there are unlocked writes to
-   book->priv->load_state, which other functions read.. */
-static gboolean
-fetch_corba_book (EBook       *book,
-		  ESource     *source,
-		  GError     **error)
-{
-	GNOME_Evolution_Addressbook_Book corba_book = CORBA_OBJECT_NIL;
-	gchar *uri;
-	gchar *source_xml;
-	GList *factories;
-	GList *l;
-	gboolean rv = FALSE;
-
-	uri = e_source_get_uri (source);
-	if (!uri) {
-		g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_OTHER_ERROR,
-			     _("%s: Invalid source."), "e_book_load_uri");
-		return FALSE;
-	}
-
-	/* try to find a list of factories that can handle the protocol */
-	factories = activate_factories_for_uri (book, uri);
-	if (!factories) {
-		g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_PROTOCOL_NOT_SUPPORTED,
-			     _("%s: no factories available for URI `%s'"), "e_book_load_uri", uri);
-		return FALSE;
-	}
+/**
+ * e_book_async_remove_contact:
+ * @book: an #EBook
+ * @contact: an #EContact
+ * @cb: a function to call when the operation finishes
+ * @closure: data to pass to callback function
+ *
+ * Removes @contact from @book.
+ *
+ * Return value: %TRUE if successful, %FALSE otherwise
+ **/guint
+e_book_async_remove_contact (EBook *book, EContact *contact, EBookCallback cb, gpointer closure)
+{
+  AsyncData *data;
+  const char *l[2];
 
+  e_return_async_error_if_fail (E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
+  e_return_async_error_if_fail (book->priv->proxy, E_BOOK_ERROR_REPOSITORY_OFFLINE);
+  e_return_async_error_if_fail (E_IS_CONTACT (contact), E_BOOK_ERROR_INVALID_ARG);
 
-	/*
-	 * Create our local BookListener interface.
-	 */
-	book->priv->listener = e_book_listener_new ();
-	if (book->priv->listener == NULL) {
-		g_warning ("e_book_load_uri: Could not create EBookListener!\n");
-		g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_OTHER_ERROR,
-			     _("%s: Could not create EBookListener"), "e_book_load_uri");
-		return FALSE;
-	}
-	book->priv->listener_signal = g_signal_connect_object (book->priv->listener, "response",
-							       G_CALLBACK (e_book_handle_response),
-							       book, 0);
+  l[0] = e_contact_get_const (contact, E_CONTACT_UID);
+  l[1] = NULL;
 
-	g_free (book->priv->uri);
-	book->priv->uri = uri;
+  data = g_slice_new0 (AsyncData);
+  data->book = g_object_ref (book);
+  data->callback = cb;
+  data->closure = closure;
 
-	g_object_ref (source);
-	if (book->priv->source)
-		g_object_unref (book->priv->source);
-	book->priv->source = source;
+  org_gnome_evolution_dataserver_addressbook_Book_remove_contacts_async (book->priv->proxy, l, remove_contact_reply, data);
+  return 0;
+}
 
-	source_xml = e_source_to_standalone_xml (source);
+static void
+remove_contact_by_id_reply (DBusGProxy *proxy, GError *error, gpointer user_data)
+{
+  AsyncData *data = user_data;
+  EBookCallback cb = data->callback;
 
-	for (l = factories; l; l = l->next) {
-		GNOME_Evolution_Addressbook_BookFactory factory = l->data;
-		CORBA_Environment ev;
+  if (cb)
+    cb (data->book, get_status_from_error (error), data->closure);
 
-		CORBA_exception_init (&ev);
+  g_object_unref (data->book);
+  g_slice_free (AsyncData, data);
+}
 
-		corba_book = GNOME_Evolution_Addressbook_BookFactory_getBook (factory, source_xml,
-									      bonobo_object_corba_objref (BONOBO_OBJECT (book->priv->listener)),
-									      &ev);
+/**
+ * e_book_async_remove_contact_by_id:
+ * @book: an #EBook
+ * @id: a unique ID string specifying the contact
+ * @cb: a function to call when the operation finishes
+ * @closure: data to pass to callback function
+ *
+ * Removes the contact with id @id from @book.
+ *
+ * Return value: %TRUE if successful, %FALSE otherwise
+ **/
+guint
+e_book_async_remove_contact_by_id (EBook *book, const char *id, EBookCallback cb, gpointer closure)
+{
+  AsyncData *data;
+  const char *l[2];
 
-		if (ev._major != CORBA_NO_EXCEPTION) {
-			CORBA_exception_free (&ev);
-			continue;
-		}
-		else if (corba_book != CORBA_OBJECT_NIL) {
-			rv = TRUE;
-			break;
-		}
-	}
+  e_return_async_error_if_fail (E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
+  e_return_async_error_if_fail (book->priv->proxy, E_BOOK_ERROR_REPOSITORY_OFFLINE);
+  e_return_async_error_if_fail (id, E_BOOK_ERROR_INVALID_ARG);
 
-	g_free (source_xml);
+  l[0] = id;
+  l[1] = NULL;
 
-	/* free up the factories */
-	for (l = factories; l; l = l->next)
-		CORBA_Object_release ((CORBA_Object)l->data, NULL);
-
-	g_list_free (factories);
-
-	if (rv == TRUE) {
-		book->priv->corba_book = corba_book;
-		book->priv->comp_listener = e_component_listener_new (book->priv->corba_book);
-		book->priv->died_signal = g_signal_connect (book->priv->comp_listener,
-							    "component_died",
-							    G_CALLBACK (backend_died_cb), book);
-	}
-	else {
-		g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_PROTOCOL_NOT_SUPPORTED,
-			     _("%s: no factories available for URI `%s'"), "e_book_new", uri);
-	}
+  data = g_slice_new0 (AsyncData);
+  data->book = g_object_ref (book);
+  data->callback = cb;
+  data->closure = closure;
 
-	return rv;
+  org_gnome_evolution_dataserver_addressbook_Book_remove_contacts_async (book->priv->proxy, l, remove_contact_by_id_reply, data);
+  return 0;
 }
 
 /**
- * e_book_get_uri:
+ * e_book_remove_contacts:
  * @book: an #EBook
+ * @ids: an #GList of const char *id's
+ * @error: a #GError to set on failure
  *
- * Get the URI that this book has loaded. This string should not be freed.
+ * Removes the contacts with ids from the list @ids from @book.  This is
+ * always more efficient than calling e_book_remove_contact_by_id if you
+ * have more than one id to remove, as some backends can implement it
+ * as a batch request.
  *
- * Return value: The URI.
- */
-const char *
-e_book_get_uri (EBook *book)
+ * Return value: %TRUE if successful, %FALSE otherwise
+ **/
+gboolean
+e_book_remove_contacts (EBook *book, GList *ids, GError **error)
 {
-	g_return_val_if_fail (book && E_IS_BOOK (book), NULL);
+  GError *err = NULL;
+  char **l;
 
-	return book->priv->uri;
+  e_return_error_if_fail (E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
+  e_return_error_if_fail (book->priv->proxy, E_BOOK_ERROR_REPOSITORY_OFFLINE);
+  e_return_error_if_fail (ids, E_BOOK_ERROR_INVALID_ARG);
+
+  l = flatten_stringlist (ids);
+
+  org_gnome_evolution_dataserver_addressbook_Book_remove_contacts (book->priv->proxy, (const char **) l, &err);
+  g_free (l);
+  return unwrap_gerror (err, error);
+}
+
+static void
+remove_contacts_reply (DBusGProxy *proxy, GError *error, gpointer user_data)
+{
+  AsyncData *data = user_data;
+  EBookCallback cb = data->callback;
+
+  if (cb)
+    cb (data->book, get_status_from_error (error), data->closure);
+
+  g_object_unref (data->book);
+  g_slice_free (AsyncData, data);
 }
 
 /**
- * e_book_get_source:
+ * e_book_async_remove_contacts:
  * @book: an #EBook
+ * @ids: a #GList of const char *id's
+ * @cb: a function to call when the operation finishes
+ * @closure: data to pass to callback function
  *
- * Get the #ESource that this book has loaded.
+ * Removes the contacts with ids from the list @ids from @book.  This is
+ * always more efficient than calling e_book_remove_contact_by_id() if you
+ * have more than one id to remove, as some backends can implement it
+ * as a batch request.
  *
- * Return value: The source.
- */
-ESource *
-e_book_get_source (EBook *book)
+ * Return value: %TRUE if successful, %FALSE otherwise
+ **/
+guint
+e_book_async_remove_contacts (EBook *book, GList *id_list, EBookCallback cb, gpointer closure)
 {
-	g_return_val_if_fail (book && E_IS_BOOK (book), NULL);
+  AsyncData *data;
+  char **l;
 
-	return book->priv->source;
+  e_return_async_error_if_fail (E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
+  e_return_async_error_if_fail (book->priv->proxy, E_BOOK_ERROR_REPOSITORY_OFFLINE);
+
+  if (id_list == NULL) {
+    if (cb)
+      cb (book, E_BOOK_ERROR_OK, closure);
+    return 0;
+  }
+
+  l = flatten_stringlist (id_list);
+
+  data = g_slice_new0 (AsyncData);
+  data->book = g_object_ref (book);
+  data->callback = cb;
+  data->closure = closure;
+
+  org_gnome_evolution_dataserver_addressbook_Book_remove_contacts_async (book->priv->proxy, (const char **) l, remove_contacts_reply, data);
+  g_free (l);
+  return 0;
 }
 
 /**
- * e_book_get_static_capabilities:
+ * e_book_get_book_view:
  * @book: an #EBook
- * @error: an #GError to set on failure
+ * @query: an #EBookQuery
+ * @requested_fields: a #GList containing the names of fields to return, or NULL for all
+ * @max_results: the maximum number of contacts to show (or 0 for all)
+ * @book_view: A #EBookView pointer, will be set to the view
+ * @error: a #GError to set on failure
  *
- * Get the list of capabilities which the backend for this address book
- * supports. This string should not be freed.
+ * Query @book with @query, creating a #EBookView in @book_view with the fields
+ * specified by @requested_fields and limited at @max_results records. On an
+ * error, @error is set and %FALSE returned.
  *
- * Return value: The capabilities list
- */
-const char *
-e_book_get_static_capabilities (EBook   *book,
-				GError **error)
+ * Return value: %TRUE if successful, %FALSE otherwise
+ **/
+gboolean
+e_book_get_book_view (EBook *book, EBookQuery *query, GList *requested_fields, int max_results, EBookView **book_view, GError **error)
 {
-	g_return_val_if_fail (book && E_IS_BOOK (book), NULL);
-
-	if (!book->priv->cap_queried) {
-		CORBA_Environment ev;
-		char *temp;
-
-		CORBA_exception_init (&ev);
-
-		if (book->priv->load_state != E_BOOK_SOURCE_LOADED) {
-			g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_SOURCE_NOT_LOADED,
-				     _("\"%s\" on book before \"%s\""),
-				     "e_book_get_static_capabilities", "e_book_open");
-			return g_strdup ("");
-		}
-
-		temp = GNOME_Evolution_Addressbook_Book_getStaticCapabilities(book->priv->corba_book, &ev);
-
-		if (ev._major != CORBA_NO_EXCEPTION) {
-			g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION,
-				     _("CORBA exception making \"%s\" call"),
-				     "Book::getStaticCapabilities");
-			CORBA_exception_free (&ev);
-			return g_strdup ("");
-		}
-
-		book->priv->cap = g_strdup(temp);
-		book->priv->cap_queried = TRUE;
-
-		CORBA_free(temp);
-
-		CORBA_exception_free (&ev);
-	}
+  GError *err = NULL;
+  DBusGProxy *view_proxy;
+  char *sexp, *view_path;
+  gboolean ret = TRUE;
+
+  e_return_error_if_fail (E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
+  e_return_error_if_fail (book->priv->proxy, E_BOOK_ERROR_REPOSITORY_OFFLINE);
+
+  sexp = e_book_query_to_string (query);
+  
+  if (!org_gnome_evolution_dataserver_addressbook_Book_get_book_view (book->priv->proxy, sexp, max_results, &view_path, &err)) {
+    *book_view = NULL;
+    g_free (sexp);
+    return unwrap_gerror (err, error);
+  }
+  view_proxy = dbus_g_proxy_new_for_name_owner (connection,
+                                                E_DATA_BOOK_FACTORY_SERVICE_NAME, view_path,
+                                                "org.gnome.evolution.dataserver.addressbook.BookView", error);
+
+  if (view_proxy) {
+    *book_view = _e_book_view_new (book, view_proxy);
+  } else {
+    *book_view = NULL;
+    g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_CORBA_EXCEPTION,
+                 "Cannot get connection to view");
+    ret = FALSE;
+  }
+  
+  g_free (view_path);
+  g_free (sexp);
+
+  return ret;
+}
+
+static void
+get_book_view_reply (DBusGProxy *proxy, char *view_path, GError *error, gpointer user_data)
+{
+  AsyncData *data = user_data;
+  GError *err = NULL;
+  EBookView *view = NULL;
+  EBookBookViewCallback cb = data->callback;
+  DBusGProxy *view_proxy;
+  EBookStatus status;
+
+  if (view_path) {
+    view_proxy = dbus_g_proxy_new_for_name_owner (connection, E_DATA_BOOK_FACTORY_SERVICE_NAME, view_path,
+                                                  "org.gnome.evolution.dataserver.addressbook.BookView", &err);
+    if (view_proxy) {
+      view = _e_book_view_new (data->book, view_proxy);
+      status = E_BOOK_ERROR_OK;
+    } else {
+      g_warning (G_STRLOC ": cannot get connection to view: %s", err->message);
+      g_error_free (err);
+      status = E_BOOK_ERROR_CORBA_EXCEPTION;
+    }
+  } else {
+    status = get_status_from_error (error);
+  }
+  
+  if (cb)
+    cb (data->book, status, view, data->closure);
 
-	return book->priv->cap;
+  g_object_unref (data->book);
+  g_slice_free (AsyncData, data);
 }
 
 /**
- * e_book_check_static_capability:
+ * e_book_async_get_book_view:
  * @book: an #EBook
- * @cap: A capability string
+ * @query: an #EBookQuery
+ * @requested_fields: a #GList containing the names of fields to return, or NULL for all
+ * @max_results: the maximum number of contacts to show (or 0 for all)
+ * @cb: a function to call when the operation finishes
+ * @closure: data to pass to callback function
  *
- * Check to see if the backend for this address book supports the capability
- * @cap.
+ * Query @book with @query, creating a #EBookView with the fields
+ * specified by @requested_fields and limited at @max_results records.
  *
- * Return value: %TRUE if the backend supports @cap, %FALSE otherwise.
- */
-gboolean
-e_book_check_static_capability (EBook *book,
-				const char  *cap)
+ * Return value: %FALSE if successful, %TRUE otherwise
+ **/
+guint
+e_book_async_get_book_view (EBook *book, EBookQuery *query, GList *requested_fields, int max_results, EBookBookViewCallback cb, gpointer closure)
 {
-	const char *caps;
+  AsyncData *data;
+  char *sexp;
+
+  e_return_async_error_val_if_fail (E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
+  e_return_async_error_val_if_fail (book->priv->proxy, E_BOOK_ERROR_REPOSITORY_OFFLINE);
+  e_return_async_error_val_if_fail (query, E_BOOK_ERROR_INVALID_ARG);
 
-	g_return_val_if_fail (book && E_IS_BOOK (book), FALSE);
+  data = g_slice_new0 (AsyncData);
+  data->book = g_object_ref (book);
+  data->callback = cb;
+  data->closure = closure;
 
-	caps = e_book_get_static_capabilities (book, NULL);
+  sexp = e_book_query_to_string (query);
 
-	/* XXX this is an inexact test but it works for our use */
-	if (caps && strstr (caps, cap))
-		return TRUE;
+  org_gnome_evolution_dataserver_addressbook_Book_get_book_view_async (book->priv->proxy, sexp, max_results, get_book_view_reply, data);
 
-	return FALSE;
+  g_free (sexp);
+  return 0;
 }
 
 /**
@@ -3425,28 +1779,24 @@
 gboolean
 e_book_is_opened (EBook *book)
 {
-	g_return_val_if_fail (E_IS_BOOK (book), FALSE);
+  g_return_val_if_fail (E_IS_BOOK (book), FALSE);
 
-	if (book->priv->load_state != E_BOOK_SOURCE_LOADED)
-		return FALSE;
-
-	return TRUE;
+  return book->priv->loaded;
 }
 
 /**
  * e_book_is_writable:
  * @book: an #EBook
- *
+ * 
  * Check if this book is writable.
- *
+ * 
  * Return value: %TRUE if this book is writable, otherwise %FALSE.
  */
 gboolean
 e_book_is_writable (EBook *book)
 {
-	g_return_val_if_fail (book && E_IS_BOOK (book), FALSE);
-
-	return book->priv->writable;
+  g_return_val_if_fail (E_IS_BOOK (book), FALSE);
+  return book->priv->writable;
 }
 
 /**
@@ -3457,13 +1807,84 @@
  *
  * Return value: %TRUE if this book is connected, otherwise %FALSE.
  **/
-gboolean
+gboolean 
 e_book_is_online (EBook *book)
 {
-	g_return_val_if_fail (book && E_IS_BOOK (book), FALSE);
-
-	return book->priv->connected;
-
+  g_return_val_if_fail (E_IS_BOOK (book), FALSE);
+  
+  return book->priv->connected;
+}
+
+/**
+ * e_book_cancel:
+ * @book: an #EBook
+ * @error: a #GError to set on failure
+ *
+ * Used to cancel an already running operation on @book.  This
+ * function makes a synchronous CORBA to the backend telling it to
+ * cancel the operation.  If the operation wasn't cancellable (either
+ * transiently or permanently) or had already comopleted on the server
+ * side, this function will return E_BOOK_STATUS_COULD_NOT_CANCEL, and
+ * the operation will continue uncancelled.  If the operation could be
+ * cancelled, this function will return E_BOOK_ERROR_OK, and the
+ * blocked e_book function corresponding to current operation will
+ * return with a status of E_BOOK_STATUS_CANCELLED.
+ *
+ * Return value: %TRUE on success, %FALSE otherwise
+ **/
+gboolean
+e_book_cancel (EBook *book, GError **error)
+{
+  e_return_error_if_fail (E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
+  e_return_error_if_fail (book->priv->proxy, E_BOOK_ERROR_REPOSITORY_OFFLINE);
+
+  return org_gnome_evolution_dataserver_addressbook_Book_cancel_operation (book->priv->proxy, error);
+}
+
+/**
+ * e_book_get_uri:
+ * @book: an #EBook
+ *
+ * Get the URI that this book has loaded. This string should not be freed.
+ *
+ * Return value: The URI.
+ */
+const char *
+e_book_get_uri (EBook *book)
+{
+  g_return_val_if_fail (E_IS_BOOK (book), NULL);
+
+  return book->priv->uri;
+}
+
+/**
+ * e_book_get_static_capabilities:
+ * @book: an #EBook
+ * @error: an #GError to set on failure
+ *
+ * Get the list of capabilities which the backend for this address book
+ * supports. This string should not be freed.
+ *
+ * Return value: The capabilities list
+ */
+const char *
+e_book_get_static_capabilities (EBook *book, GError **error)
+{
+  e_return_error_if_fail (E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
+  e_return_error_if_fail (book->priv->proxy, E_BOOK_ERROR_REPOSITORY_OFFLINE);
+  
+  if (!book->priv->cap_queried) {
+    char *cap = NULL;
+    
+    if (!org_gnome_evolution_dataserver_addressbook_Book_get_static_capabilities (book->priv->proxy, &cap, error)) {
+      return NULL;
+    }
+
+    book->priv->cap = cap;
+    book->priv->cap_queried = TRUE;
+  }
+  
+  return book->priv->cap;
 }
 
 #define SELF_UID_KEY "/apps/evolution/addressbook/self/self_uid"
@@ -3482,25 +1903,18 @@
 gboolean
 e_book_get_self (EContact **contact, EBook **book, GError **error)
 {
-	GError *e = NULL;
 	GConfClient *gconf;
 	gboolean status;
 	char *uid;
 
-	*book = e_book_new_system_addressbook (&e);
+	*book = e_book_new_system_addressbook (error);
 
 	if (!*book) {
-		if (error)
-			g_propagate_error (error, e);
 		return FALSE;
 	}
 
-	status = e_book_open (*book, FALSE, &e);
+	status = e_book_open (*book, FALSE, error);
 	if (status == FALSE) {
-		g_object_unref (*book);
-		*book = NULL;
-		if (error)
-			g_propagate_error (error, e);
 		return FALSE;
 	}
 
@@ -3512,21 +1926,16 @@
 		g_object_unref (*book);
 		*book = NULL;
 		g_set_error (error, E_BOOK_ERROR, E_BOOK_ERROR_NO_SELF_CONTACT,
-			     _("%s: there was no self contact UID stored in gconf"), "e_book_get_self");
+			     _("%s: there was no self contact uid stored in gconf"), "e_book_get_self");
 		return FALSE;
 	}
 
-	if (!e_book_get_contact (*book, uid, contact, &e)) {
+	if (!e_book_get_contact (*book, uid, contact, error)) {
 		g_object_unref (*book);
 		*book = NULL;
-		g_free (uid);
-		if (error)
-			g_propagate_error (error, e);
 		return FALSE;
 	}
 
-	g_free (uid);
-
 	return TRUE;
 }
 
@@ -3546,8 +1955,8 @@
 {
 	GConfClient *gconf;
 
-	e_return_error_if_fail (book && E_IS_BOOK (book),          E_BOOK_ERROR_INVALID_ARG, FALSE);
-	e_return_error_if_fail (contact && E_IS_CONTACT (contact), E_BOOK_ERROR_INVALID_ARG, FALSE);
+	e_return_error_if_fail (E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
+	e_return_error_if_fail (E_IS_CONTACT (contact), E_BOOK_ERROR_INVALID_ARG);
 
 	gconf = gconf_client_get_default();
 	gconf_client_set_string (gconf, SELF_UID_KEY, e_contact_get_const (contact, E_CONTACT_UID), NULL);
@@ -3586,29 +1995,27 @@
 	return rv;
 }
 
-
-
 /**
  * e_book_set_default_addressbook:
  * @book: An #EBook pointer
  * @error: A #GError pointer
- *
+ * 
  * sets the #ESource of the #EBook as the "default" addressbook.  This is the source
  * that will be loaded in the e_book_get_default_addressbook call.
- *
+ * 
  * Return value: %TRUE if the setting was stored in libebook's ESourceList, otherwise %FALSE.
  */
 gboolean
 e_book_set_default_addressbook (EBook *book, GError **error)
 {
-	ESource *source;
-
-	e_return_error_if_fail (book && E_IS_BOOK (book),                        E_BOOK_ERROR_INVALID_ARG, FALSE);
-	e_return_error_if_fail (book->priv->load_state == E_BOOK_SOURCE_NOT_LOADED, E_BOOK_ERROR_SOURCE_ALREADY_LOADED, FALSE);
-
-	source = e_book_get_source (book);
-
-	return e_book_set_default_source (source, error);
+  ESource *source;
+  
+  e_return_error_if_fail (E_IS_BOOK (book), E_BOOK_ERROR_INVALID_ARG);
+  e_return_error_if_fail (book->priv->loaded == FALSE, E_BOOK_ERROR_SOURCE_ALREADY_LOADED);
+  
+  source = e_book_get_source (book);
+  
+  return e_book_set_default_source (source, error);
 }
 
 
@@ -3616,10 +2023,10 @@
  * e_book_set_default_source:
  * @source: An #ESource pointer
  * @error: A #GError pointer
- *
+ * 
  * sets @source as the "default" addressbook.  This is the source that
  * will be loaded in the e_book_get_default_addressbook call.
- *
+ * 
  * Return value: %TRUE if the setting was stored in libebook's ESourceList, otherwise %FALSE.
  */
 gboolean
@@ -3627,16 +2034,13 @@
 {
 	ESourceList *sources;
 	const char *uid;
-	GError *err = NULL;
 	GSList *g;
 
-	e_return_error_if_fail (source && E_IS_SOURCE (source), E_BOOK_ERROR_INVALID_ARG, FALSE);
+	e_return_error_if_fail (source && E_IS_SOURCE (source), E_BOOK_ERROR_INVALID_ARG);
 
 	uid = e_source_peek_uid (source);
 
-	if (!e_book_get_addressbooks (&sources, &err)) {
-		if (error)
-			g_propagate_error (error, err);
+	if (!e_book_get_addressbooks (&sources, error)) {
 		return FALSE;
 	}
 
@@ -3663,9 +2067,7 @@
 	/* set the "default" property on the source */
 	e_source_set_property (source, "default", "true");
 
-	if (!e_source_list_sync (sources, &err)) {
-		if (error)
-			g_propagate_error (error, err);
+	if (!e_source_list_sync (sources, error)) {
 		return FALSE;
 	}
 
@@ -3673,398 +2075,123 @@
 }
 
 /**
- * e_book_get_addressbooks:
- * @addressbook_sources: A pointer to a ESourceList* to set
- * @error: A pointer to a GError* to set on error
+ * e_book_check_static_capability:
+ * @book: an #EBook
+ * @cap: A capability string
  *
- * Populate *addressbook_sources with the list of all sources which have been
- * added to Evolution.
+ * Check to see if the backend for this address book supports the capability
+ * @cap.
  *
- * Return value: %TRUE if @addressbook_sources was set, otherwise %FALSE.
+ * Return value: %TRUE if the backend supports @cap, %FALSE otherwise.
  */
 gboolean
-e_book_get_addressbooks (ESourceList **addressbook_sources, GError **error)
-{
-	GConfClient *gconf;
-
-	e_return_error_if_fail (addressbook_sources, E_BOOK_ERROR_INVALID_ARG, FALSE);
-
-	gconf = gconf_client_get_default();
-	*addressbook_sources = e_source_list_new_for_gconf (gconf, "/apps/evolution/addressbook/sources");
-	g_object_unref (gconf);
-
-	return TRUE;
-}
-
-
-static void*
-startup_mainloop (void *arg)
-{
-	GMainLoop *loop = g_main_loop_new (_ebook_context, FALSE);
-	g_main_loop_run (loop);
-	return NULL;
-}
-
-/* one-time start up for libebook */
-static void
-e_book_activate(void)
-{
-	static GStaticMutex e_book_lock = G_STATIC_MUTEX_INIT;
-	static gboolean activated = FALSE;
-
-	g_static_mutex_lock (&e_book_lock);
-	if (!activated) {
-		GThread *ebook_mainloop_thread;
-		activated = TRUE;
-
-		_ebook_context = g_main_context_new ();
-
-		if (!bonobo_is_initialized ())
-			bonobo_init (NULL, NULL);
-
-		ebook_mainloop_thread = g_thread_create(startup_mainloop, NULL, FALSE, NULL);
-	}
-	g_static_mutex_unlock (&e_book_lock);
-}
-
-
-/**
- * e_book_new:
- * @source: An #ESource pointer
- * @error: A #GError pointer
- *
- * Creates a new #EBook corresponding to the given source.  There are
- * only two operations that are valid on this book at this point:
- * e_book_open(), and e_book_remove().
- *
- * Return value: a new but unopened #EBook.
- */
-EBook*
-e_book_new (ESource *source, GError **error)
-{
-	EBook *book;
-
-	e_return_error_if_fail (source && E_IS_SOURCE (source), E_BOOK_ERROR_INVALID_ARG, NULL);
-
-	e_book_activate ();
-
-	book = g_object_new (E_TYPE_BOOK, NULL);
-
-	book->priv->source = g_object_ref (source);
-
-	if (!fetch_corba_book (book, source, error)) {
-		g_object_unref (book);
-		return NULL;
-	}
-
-	return book;
-}
-
-/**
- * e_book_new_from_uri:
- * @uri: the URI to load
- * @error: A #GError pointer
- *
- * Creates a new #EBook corresponding to the given uri.  See the
- * documentation for e_book_new for further information.
- *
- * Return value: a new but unopened #EBook.
- */
-EBook*
-e_book_new_from_uri (const char *uri, GError **error)
-{
-	ESourceGroup *group;
-	ESource *source;
-	EBook *book;
-
-	e_return_error_if_fail (uri, E_BOOK_ERROR_INVALID_ARG, NULL);
-
-	group = e_source_group_new ("", uri);
-	source = e_source_new ("", "");
-	e_source_set_group (source, group);
-	e_source_set_relative_uri (source, NULL);
-
-	book = e_book_new (source, error);
-
-	g_object_unref (source);
-	g_object_unref (group);
-
-	return book;
-}
-
-/**
- * e_book_new_system_addressbook:
- * @error: A #GError pointer
- *
- * Creates a new #EBook corresponding to the user's system
- * addressbook.  See the documentation for e_book_new for further
- * information.
- *
- * Return value: a new but unopened #EBook.
- */
-EBook*
-e_book_new_system_addressbook    (GError **error)
-{
-	ESourceList *sources;
-	GSList *g;
-	GError *err = NULL;
-	ESource *system_source = NULL;
-	EBook *book;
-
-	if (!e_book_get_addressbooks (&sources, &err)) {
-		if (error)
-			g_propagate_error (error, err);
-		return NULL;
-	}
-
-	for (g = e_source_list_peek_groups (sources); g; g = g->next) {
-		ESourceGroup *group = E_SOURCE_GROUP (g->data);
-		GSList *s;
-		for (s = e_source_group_peek_sources (group); s; s = s->next) {
-			ESource *source = E_SOURCE (s->data);
-
-			if (e_source_get_property (source, "system")) {
-				system_source = source;
-				break;
-			}
-		}
-
-		if (system_source)
-			break;
-	}
-
-	if (system_source) {
-		book = e_book_new (system_source, &err);
-	}
-	else {
-		char *filename;
-		char *uri;
-
-		filename = g_build_filename (g_get_home_dir(),
-					     ".evolution/addressbook/local/system",
-					     NULL);
-		uri = g_filename_to_uri (filename, NULL, NULL);
-
-		g_free (filename);
-
-		book = e_book_new_from_uri (uri, error);
-
-		g_free (uri);
-	}
-
-	if (!book) {
-		if (error)
-			g_propagate_error (error, err);
-	}
-
-	g_object_unref (sources);
-
-	return book;
-}
-
-/**
- * e_book_new_default_addressbook:
- * @error: A #GError pointer
- *
- * Creates a new #EBook corresponding to the user's default
- * addressbook.  See the documentation for e_book_new for further
- * information.
- *
- * Return value: a new but unopened #EBook.
- */
-EBook*
-e_book_new_default_addressbook   (GError **error)
-{
-	ESourceList *sources;
-	GSList *g;
-	GError *err = NULL;
-	ESource *default_source = NULL;
-	EBook *book;
-
-	if (!e_book_get_addressbooks (&sources, &err)) {
-		if (error)
-			g_propagate_error (error, err);
-		return NULL;
-	}
-
-	for (g = e_source_list_peek_groups (sources); g; g = g->next) {
-		ESourceGroup *group = E_SOURCE_GROUP (g->data);
-		GSList *s;
-		for (s = e_source_group_peek_sources (group); s; s = s->next) {
-			ESource *source = E_SOURCE (s->data);
-
-			if (e_source_get_property (source, "default")) {
-				default_source = source;
-				break;
-			}
-		}
-
-		if (default_source)
-			break;
-	}
-
-	if (default_source)
-		book = e_book_new (default_source, &err);
-	else
-		book = e_book_new_system_addressbook (&err);
-
-	if (!book) {
-		if (error)
-			g_propagate_error (error, err);
-	}
-
-	g_object_unref (sources);
-
-	return book;
-}
-
-static void
-e_book_init (EBook *book)
-{
-	book->priv                = g_new0 (EBookPrivate, 1);
-	book->priv->load_state    = E_BOOK_SOURCE_NOT_LOADED;
-	book->priv->uri           = NULL;
-	book->priv->source        = NULL;
-	book->priv->mutex         = g_mutex_new ();
-	book->priv->id_to_op      = g_hash_table_new (g_int_hash, g_int_equal);
-	book->priv->current_op_id = 1;
-}
-
-static void
-e_book_dispose (GObject *object)
-{
-	EBook             *book = E_BOOK (object);
-
-	if (book->priv) {
-		if (book->priv->comp_listener) {
-			g_signal_handler_disconnect (book->priv->comp_listener, book->priv->died_signal);
-			g_object_unref (book->priv->comp_listener);
-			book->priv->comp_listener = NULL;
-		}
-
-		if (book->priv->load_state == E_BOOK_SOURCE_LOADED)
-			e_book_unload_uri (book, NULL);
-
-		if (book->priv->corba_book) {
-			CORBA_Environment  ev;
-
-			CORBA_exception_init (&ev);
-			bonobo_object_release_unref  (book->priv->corba_book, &ev);
-			if (ev._major != CORBA_NO_EXCEPTION)
-				g_warning ("%s: Exception releasing remote book interface!\n", G_STRFUNC);
-			CORBA_exception_free (&ev);
-		}
-
-		if (book->priv->listener) {
-			e_book_listener_stop (book->priv->listener);
-
-			/* GLib bug compatibility */
-			if (g_signal_handler_is_connected (book->priv->listener, book->priv->listener_signal))
-				g_signal_handler_disconnect (book->priv->listener, book->priv->listener_signal);
-			bonobo_object_unref (book->priv->listener);
-			book->priv->listener = NULL;
-		}
-
-		g_free (book->priv->cap);
-
-		g_free (book->priv->uri);
-
-		if (book->priv->source)
-			g_object_unref (book->priv->source);
-
-		/* XXX free up the remaining ops? */
-		g_hash_table_destroy (book->priv->id_to_op);
-
-		g_mutex_free (book->priv->mutex);
-
-		if (book->priv->connection_idle_id)
-			g_source_remove (book->priv->connection_idle_id);
-
-		if (book->priv->auth_idle_id)
-			g_source_remove (book->priv->auth_idle_id);
-
-		if (book->priv->writable_idle_id)
-			g_source_remove (book->priv->writable_idle_id);
-
-		g_free (book->priv);
-		book->priv = NULL;
-	}
-
-	if (G_OBJECT_CLASS (parent_class)->dispose)
-		G_OBJECT_CLASS (parent_class)->dispose (object);
-}
-
-static void
-e_book_class_init (EBookClass *klass)
+e_book_check_static_capability (EBook *book, const char *cap)
 {
-	GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
-	parent_class = g_type_class_ref (G_TYPE_OBJECT);
-
-	e_book_signals [WRITABLE_STATUS] =
-		g_signal_new ("writable_status",
-			      G_OBJECT_CLASS_TYPE (object_class),
-			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (EBookClass, writable_status),
-			      NULL, NULL,
-			      g_cclosure_marshal_VOID__BOOLEAN,
-			      G_TYPE_NONE, 1,
-			      G_TYPE_BOOLEAN);
-
-	e_book_signals [CONNECTION_STATUS] =
-		g_signal_new ("connection_status",
-			      G_OBJECT_CLASS_TYPE (object_class),
-			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (EBookClass, connection_status),
-			      NULL, NULL,
-			      g_cclosure_marshal_VOID__BOOLEAN,
-			      G_TYPE_NONE, 1,
-			      G_TYPE_BOOLEAN);
+  const char *caps;
 
-	e_book_signals [AUTH_REQUIRED] =
-		g_signal_new ("auth_required",
-			      G_OBJECT_CLASS_TYPE (object_class),
-			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (EBookClass, auth_required),
-			      NULL, NULL,
-			      g_cclosure_marshal_VOID__VOID,
-			      G_TYPE_NONE, 0);
+  g_return_val_if_fail (E_IS_BOOK (book), FALSE);
 
-	e_book_signals [BACKEND_DIED] =
-		g_signal_new ("backend_died",
-			      G_OBJECT_CLASS_TYPE (object_class),
-			      G_SIGNAL_RUN_LAST,
-			      G_STRUCT_OFFSET (EBookClass, backend_died),
-			      NULL, NULL,
-			      g_cclosure_marshal_VOID__VOID,
-			      G_TYPE_NONE, 0);
+  caps = e_book_get_static_capabilities (book, NULL);
 
-	object_class->dispose = e_book_dispose;
+  /* XXX this is an inexact test but it works for our use */
+  if (caps && strstr (caps, cap))
+    return TRUE;
+
+  return FALSE;
+}
+
+/**
+ * If the specified GError is a remote error, then create a new error
+ * representing the remote error.  If the error is anything else, then leave it
+ * alone.
+ */
+static gboolean
+unwrap_gerror (GError *error, GError **client_error)
+{
+  if (error == NULL)
+    return TRUE;
+  
+  if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_REMOTE_EXCEPTION) {
+    GError *new;
+    gint code;
+    if (client_error) {
+      code = get_status_from_error (error);
+      new = g_error_new_literal (E_BOOK_ERROR, code, error->message);
+      *client_error = new;
+    }
+    g_error_free (error);
+  } else {
+    if (client_error)
+      *client_error = error;
+  }
+  return FALSE;
+}
+
+/**
+ * If the GError is a remote error, extract the EBookStatus embedded inside.
+ * Otherwise return CORBA_EXCEPTION (I know this is DBus...).
+ */
+static EBookStatus
+get_status_from_error (GError *error)
+{
+  if G_LIKELY (error == NULL)
+    return E_BOOK_ERROR_OK;
+  if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_REMOTE_EXCEPTION) {
+    const char *name;
+    name = dbus_g_error_get_name (error);
+    if (strcmp (name, "org.gnome.evolution.dataserver.addressbook.Book.contactnotfound") == 0) {
+      return E_BOOK_ERROR_CONTACT_NOT_FOUND;
+    } else if (strcmp (name, "org.gnome.evolution.dataserver.addressbook.Book.invalidquery") == 0) {
+      return E_BOOK_ERROR_INVALID_ARG;
+    } else if (strcmp (name, "org.gnome.evolution.dataserver.addressbook.Book.cancelled") == 0) {
+      return E_BOOK_ERROR_CANCELLED;
+    } else if (strcmp (name, "org.gnome.evolution.dataserver.addressbook.Book.permissiondenied") == 0) {
+      return E_BOOK_ERROR_PERMISSION_DENIED;
+    } else if (strcmp (name, "org.gnome.evolution.dataserver.addressbook.Book.nospace") == 0) {
+      return E_BOOK_ERROR_NO_SPACE;
+    } else if (strcmp (name, "org.gnome.evolution.dataserver.addressbook.Book.repositoryoffline") == 0) {
+      return E_BOOK_ERROR_REPOSITORY_OFFLINE;
+    } else if (strcmp (name, "org.gnome.evolution.dataserver.addressbook.Book.othererror") == 0) {
+      return E_BOOK_ERROR_OTHER_ERROR;
+    } else {
+      g_warning (G_STRLOC ": unmatched error name %s", name);
+      return E_BOOK_ERROR_OTHER_ERROR;
+    }
+  } else {
+    /* In this case the error was caused by DBus. Dump the message to the
+       console as otherwise we have no idea what the problem is. */
+    g_warning ("DBus error: %s", error->message);
+    return E_BOOK_ERROR_CORBA_EXCEPTION;
+  }
+}
+
+/**
+ * Turn a GList of strings into an array of strings.
+ */
+static char **
+flatten_stringlist (GList *list)
+{
+  char **array = g_new0 (char *, g_list_length (list) + 1);
+  GList *l = list;
+  int i = 0;
+  while (l != NULL) {
+    array[i++] = l->data;
+    l = l->next;
+  }
+  return array;
 }
 
 /**
- * e_book_get_type:
+ * Turn an array of strings into a GList.
  */
-GType
-e_book_get_type (void)
+static GList *
+array_to_stringlist (char **list)
 {
-	static GType type = 0;
-
-	if (! type) {
-		GTypeInfo info = {
-			sizeof (EBookClass),
-			NULL, /* base_class_init */
-			NULL, /* base_class_finalize */
-			(GClassInitFunc)  e_book_class_init,
-			NULL, /* class_finalize */
-			NULL, /* class_data */
-			sizeof (EBook),
-			0,    /* n_preallocs */
-			(GInstanceInitFunc) e_book_init
-		};
-
-		type = g_type_register_static (G_TYPE_OBJECT, "EBook", &info, 0);
-	}
-
-	return type;
+  GList *l = NULL;
+  char **i = list;
+  while (*i != NULL) {
+    l = g_list_prepend (l, (*i++));
+  }
+  g_free (list);
+  return g_list_reverse(l);
 }

Modified: branches/eds-dbus/addressbook/libebook/libebook.pc.in
==============================================================================
--- branches/eds-dbus/addressbook/libebook/libebook.pc.in	(original)
+++ branches/eds-dbus/addressbook/libebook/libebook.pc.in	Fri Sep 12 17:21:22 2008
@@ -6,13 +6,13 @@
 datadir= datadir@
 
 idldir= idldir@
-IDL_INCLUDES=-I${idldir} @IDL_INCLUDES@
+IDL_INCLUDES=-I ${idldir} @IDL_INCLUDES@
 
 privincludedir= privincludedir@
 
 Name: libebook
 Description: Client library for evolution address books
 Version: @VERSION@
-Requires: libbonobo-2.0 >= @LIBBONOBO_REQUIRED@ libgnome-2.0 libedataserver-1.2
+Requires: libedataserver-1.2 dbus-glib-1
 Libs: -L${libdir} -lebook-1.2
 Cflags: -I${privincludedir}

Modified: branches/eds-dbus/addressbook/libedata-book/Makefile.am
==============================================================================
--- branches/eds-dbus/addressbook/libedata-book/Makefile.am	(original)
+++ branches/eds-dbus/addressbook/libedata-book/Makefile.am	Fri Sep 12 17:21:22 2008
@@ -1,62 +1,53 @@
 INCLUDES =						\
 	-DG_LOG_DOMAIN=\"libedata-book\"		\
+	-DLIBEXECDIR=\"$(libexecdir)\"			\
 	-I$(top_srcdir)					\
 	-I$(top_builddir)				\
 	-I$(top_srcdir)/addressbook			\
 	-I$(top_builddir)/addressbook			\
-	$(DB_CFLAGS)					\
-        $(EVOLUTION_ADDRESSBOOK_CFLAGS)
-
-# The corba stubs and skels
-CORBA_GENERATED_C =				\
-	Evolution-DataServer-Addressbook-common.c		\
-	Evolution-DataServer-Addressbook-skels.c		\
-	Evolution-DataServer-Addressbook-stubs.c
-CORBA_GENERATED_H =			\
-	Evolution-DataServer-Addressbook.h
-
-CORBA_GENERATED = $(CORBA_GENERATED_C) $(CORBA_GENERATED_H)
-
-idls =						\
-	$(srcdir)/../idl/Evolution-DataServer-Addressbook.idl
-
-idl_flags = $(IDL_INCLUDES)
-
-$(CORBA_GENERATED_H): $(idls)
-	$(ORBIT_IDL) $(idl_flags) $(srcdir)/../idl/Evolution-DataServer-Addressbook.idl
-$(CORBA_GENERATED_C): $(CORBA_GENERATED_H)
+	$(EVOLUTION_ADDRESSBOOK_CFLAGS)		\
+	$(DBUS_GLIB_CFLAGS)				\
+	-DDBUS_API_SUBJECT_TO_CHANGE
 
 # The library
 lib_LTLIBRARIES = libedata-book-1.2.la
 
+DBUS_GENERATED_H = e-data-book-glue.h e-data-book-factory-glue.h e-data-book-view-glue.h
+
+include glib-gen.mak
+glib_enum_headers=e-data-book-types.h
+glib_enum_define=E_DATA_BOOK
+glib_enum_prefix=e_data_book
+
+ENUM_GENERATED = e-data-book-enumtypes.h e-data-book-enumtypes.c
+
 libedata_book_1_2_la_SOURCES =				\
-	$(CORBA_GENERATED_C)				\
+	$(DBUS_GENERATED_H)				\
 	e-book-backend-factory.c			\
 	e-book-backend-sexp.c				\
 	e-book-backend-summary.c			\
 	e-book-backend-cache.c                          \
-	e-book-backend-db-cache.c                       \
-	e-book-backend-sync.c				\
 	e-book-backend.c				\
-	e-data-book-factory.c				\
 	e-data-book-view.c				\
 	e-data-book.c					\
-	ximian-vcard.h
+	ximian-vcard.h					\
+	e-book-backend-sync.c \
+	opid.c opid.h \
+	$(ENUM_GENERATED)
 
 libedata_book_1_2_la_LIBADD =					\
-	$(top_builddir)/addressbook/libebook/libebook-1.2.la	\
-	$(top_builddir)/libedataserver/libedataserver-1.2.la	\
-	$(top_builddir)/libebackend/libebackend-1.2.la	\
-	$(DB_LIBS) \
-	$(EVOLUTION_ADDRESSBOOK_LIBS)
+	$(EVOLUTION_ADDRESSBOOK_LIBS)				\
+	$(top_builddir)/addressbook/libebook/libebook-$(API_VERSION).la	\
+	$(top_builddir)/libedataserver/libedataserver-$(API_VERSION).la \
+	$(top_builddir)/libebackend/libebackend-$(API_VERSION).la
+
+libedata_book_1_2_la_LDFLAGS = 									\
+	-version-info $(LIBEDATABOOK_CURRENT):$(LIBEDATABOOK_REVISION):$(LIBEDATABOOK_AGE)
 
-libedata_book_1_2_la_LDFLAGS = \
-	-version-info $(LIBEDATABOOK_CURRENT):$(LIBEDATABOOK_REVISION):$(LIBEDATABOOK_AGE) $(NO_UNDEFINED)
 
 libedata_bookincludedir = $(privincludedir)/libedata-book
 
 libedata_bookinclude_HEADERS =				\
-	$(CORBA_GENERATED_H)				\
 	e-book-backend-factory.h			\
 	e-book-backend-sexp.h				\
 	e-book-backend-summary.h			\
@@ -66,8 +57,7 @@
 	e-data-book-types.h				\
 	e-data-book-view.h				\
 	e-data-book.h                                   \
-	e-book-backend-cache.h 				\
-	e-book-backend-db-cache.h
+	e-book-backend-cache.h 								
 
 %-$(API_VERSION).pc: %.pc
 	 cp $< $@
@@ -75,12 +65,37 @@
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = libedata-book-$(API_VERSION).pc
 
-BUILT_SOURCES = $(CORBA_GENERATED)
-CLEANFILES = $(BUILT_SOURCES)
+service_in_files = org.gnome.evolution.dataserver.AddressBook.service.in
+servicedir = $(datadir)/dbus-1/services
+service_DATA = $(service_in_files:.service.in=.service)
+ EVO_SUBST_SERVICE_RULE@
+
+BUILT_SOURCES = $(DBUS_GENERATED_H)
+CLEANFILES = $(BUILT_SOURCES) $(service_DATA)
 DISTCLEANFILES = $(pkgconfig_DATA)
 
 EXTRA_DIST = 						\
-	$(pkgconfig_DATA:-$(API_VERSION).pc=.pc.in)
+	e-data-book-factory.xml				\
+	e-data-book-view.xml				\
+	e-data-book.xml					\
+	$(pkgconfig_DATA:-$(API_VERSION).pc=.pc.in)	\
+	$(service_in_files)
 
 dist-hook:
 	cd $(distdir); rm -f $(BUILT_SOURCES)
+
+%-glue.h: %.xml
+	dbus-binding-tool --mode=glib-server --output=$@ --prefix=$(subst -,_,$*) $^
+
+%-bindings.h: %.xml
+	dbus-binding-tool --mode=glib-client --output=$@ --prefix=$(subst -,_,$*) $^
+
+
+DBUS_BINDINGS = e-data-book-factory-bindings.h e-data-book-bindings.h e-data-book-view-bindings.h
+BUILT_SOURCES += $(DBUS_BINDINGS) $(ENUM_GENERATED)
+
+factorydir = $(libexecdir)
+factory_PROGRAMS = e-addressbook-factory
+
+e_addressbook_factory_SOURCES = e-data-book-factory.c e-data-book-factory.h
+e_addressbook_factory_LDADD = libedata-book-1.2.la

Modified: branches/eds-dbus/addressbook/libedata-book/e-book-backend-sync.h
==============================================================================
--- branches/eds-dbus/addressbook/libedata-book/e-book-backend-sync.h	(original)
+++ branches/eds-dbus/addressbook/libedata-book/e-book-backend-sync.h	Fri Sep 12 17:21:22 2008
@@ -6,7 +6,6 @@
 #define __E_BOOK_BACKEND_SYNC_H__
 
 #include <glib.h>
-#include <libedata-book/Evolution-DataServer-Addressbook.h>
 #include <libedata-book/e-data-book-types.h>
 #include <libedata-book/e-book-backend.h>
 
@@ -21,7 +20,7 @@
 
 typedef struct _EBookBackendSyncPrivate EBookBackendSyncPrivate;
 
-typedef GNOME_Evolution_Addressbook_CallStatus EBookBackendSyncStatus;
+typedef EDataBookStatus EBookBackendSyncStatus;
 
 struct _EBookBackendSync {
 	EBookBackend parent_object;

Modified: branches/eds-dbus/addressbook/libedata-book/e-book-backend.c
==============================================================================
--- branches/eds-dbus/addressbook/libedata-book/e-book-backend.c	(original)
+++ branches/eds-dbus/addressbook/libedata-book/e-book-backend.c	Fri Sep 12 17:21:22 2008
@@ -3,12 +3,12 @@
  * Author:
  *   Nat Friedman (nat ximian com)
  *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright 2000, Ximian, Inc.
  */
 
 #include <config.h>
-
 #include "e-data-book-view.h"
+#include "e-data-book.h"
 #include "e-book-backend.h"
 
 struct _EBookBackendPrivate {
@@ -18,7 +18,7 @@
 	GList *clients;
 
 	ESource *source;
-	gboolean loaded, writable, removed, online;
+	gboolean loaded, writable, removed;
 
 	GMutex *views_mutex;
 	EList *views;
@@ -58,12 +58,12 @@
  *
  * Return value: A #GNOME_Evolution_Addressbook_CallStatus indicating the outcome.
  **/
-GNOME_Evolution_Addressbook_CallStatus
+EDataBookStatus
 e_book_backend_load_source (EBookBackend           *backend,
 			    ESource                *source,
 			    gboolean                only_if_exists)
 {
-	GNOME_Evolution_Addressbook_CallStatus status;
+	EDataBookStatus status;
 
 	g_return_val_if_fail (E_IS_BOOK_BACKEND (backend), FALSE);
 	g_return_val_if_fail (source, FALSE);
@@ -73,7 +73,7 @@
 
 	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) {
+	if (status == Success || status == InvalidServerVersion) {
 		g_object_ref (source);
 		backend->priv->source = source;
 	}
@@ -84,9 +84,9 @@
 /**
  * e_book_backend_get_source:
  * @backend: An addressbook backend.
- *
+ * 
  * Queries the source that an addressbook backend is serving.
- *
+ * 
  * Return value: ESource for the backend.
  **/
 ESource *
@@ -119,20 +119,17 @@
 	g_mutex_lock (backend->priv->open_mutex);
 
 	if (backend->priv->loaded) {
-		e_data_book_respond_open (
-			book, opid, GNOME_Evolution_Addressbook_Success);
+		e_data_book_respond_open (book, opid, Success);
 
 		e_data_book_report_writable (book, backend->priv->writable);
-		e_data_book_report_connection_status (book, backend->priv->online);
 	} else {
-		GNOME_Evolution_Addressbook_CallStatus status =
+		EDataBookStatus status =
 			e_book_backend_load_source (backend, e_data_book_get_source (book), only_if_exists);
 
 		e_data_book_respond_open (book, opid, status);
 
-		if (status == GNOME_Evolution_Addressbook_Success || status == GNOME_Evolution_Addressbook_InvalidServerVersion)
-			e_data_book_report_writable (book, backend->priv->writable);
-			e_data_book_report_connection_status (book, backend->priv->online);
+				if (status == Success || status == InvalidServerVersion)
+					e_data_book_report_writable (book, backend->priv->writable);
 	}
 
 	g_mutex_unlock (backend->priv->open_mutex);
@@ -236,6 +233,31 @@
 }
 
 /**
+ * e_book_backend_modify_contacts:
+ * @backend: an #EBookBackend
+ * @book: an #EDataBook
+ * @opid: the ID to use for this operation
+ * @vcards: the VCards to update
+ *
+ * Executes a 'modify contacts' request specified by @opid on @book
+ * using @backend.
+ **/
+void
+e_book_backend_modify_contacts (EBookBackend *backend,
+				EDataBook    *book,
+				guint32       opid,
+				const char  **vcards)
+{
+	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
+	g_return_if_fail (E_IS_DATA_BOOK (book));
+	g_return_if_fail (vcards);
+
+	g_assert (E_BOOK_BACKEND_GET_CLASS (backend)->modify_contacts);
+
+	(* E_BOOK_BACKEND_GET_CLASS (backend)->modify_contacts) (backend, book, opid, vcards);
+}
+
+/**
  * e_book_backend_get_contact:
  * @backend: an #EBookBackend
  * @book: an #EDataBook
@@ -456,12 +478,12 @@
  *
  * Return value: A GNOME_Evolution_Addressbook_CallStatus indicating the outcome.
  **/
-GNOME_Evolution_Addressbook_CallStatus
+EDataBookStatus
 e_book_backend_cancel_operation (EBookBackend *backend,
 				 EDataBook    *book)
 {
-	g_return_val_if_fail (E_IS_BOOK_BACKEND (backend), GNOME_Evolution_Addressbook_OtherError);
-	g_return_val_if_fail (E_IS_DATA_BOOK (book), GNOME_Evolution_Addressbook_OtherError);
+	g_return_val_if_fail (E_IS_BOOK_BACKEND (backend), OtherError);
+	g_return_val_if_fail (E_IS_DATA_BOOK (book), OtherError);
 
 	g_assert (E_BOOK_BACKEND_GET_CLASS (backend)->cancel_operation);
 
@@ -477,14 +499,6 @@
 }
 
 static void
-listener_died_cb (gpointer cnx, gpointer user_data)
-{
-	EDataBook *book = E_DATA_BOOK (user_data);
-
-	e_book_backend_remove_client (e_data_book_get_backend (book), book);
-}
-
-static void
 last_client_gone (EBookBackend *backend)
 {
 	g_signal_emit (backend, e_book_backend_signals[LAST_CLIENT_GONE], 0);
@@ -561,13 +575,7 @@
 {
 	g_return_val_if_fail (E_IS_BOOK_BACKEND (backend), FALSE);
 	g_return_val_if_fail (E_IS_DATA_BOOK (book), FALSE);
-
-	bonobo_object_set_immortal (BONOBO_OBJECT (book), TRUE);
-
 	g_object_weak_ref (G_OBJECT (book), book_destroy_cb, backend);
-
-	ORBit_small_listen_for_broken (e_data_book_get_listener (book), G_CALLBACK (listener_died_cb), book);
-
 	g_mutex_lock (backend->priv->clients_mutex);
 	backend->priv->clients = g_list_prepend (backend->priv->clients, book);
 	g_mutex_unlock (backend->priv->clients_mutex);
@@ -603,7 +611,7 @@
 	 */
 	if (!backend->priv->clients)
 		last_client_gone (backend);
-
+	
 	g_mutex_unlock (backend->priv->clients_mutex);
 
 	g_object_unref (backend);
@@ -620,29 +628,7 @@
 gboolean
 e_book_backend_has_out_of_proc_clients (EBookBackend *backend)
 {
-	GList *l;
-
-	g_mutex_lock (backend->priv->clients_mutex);
-
-	if (!backend->priv->clients) {
-		g_mutex_unlock (backend->priv->clients_mutex);
-
-		return FALSE;
-	}
-
-	for (l = backend->priv->clients; l; l = l->next) {
-		if (ORBit_small_get_connection_status (e_data_book_get_listener (l->data)) != ORBIT_CONNECTION_IN_PROC) {
-			g_mutex_unlock (backend->priv->clients_mutex);
-
-			return TRUE;
-		}
-	}
-
-	g_mutex_unlock (backend->priv->clients_mutex);
-
-	/* If we get here, all remaining clients are in proc */
-
-	return FALSE;
+	return TRUE;
 }
 
 /**
@@ -657,7 +643,7 @@
 e_book_backend_get_static_capabilities (EBookBackend *backend)
 {
 	g_return_val_if_fail (E_IS_BOOK_BACKEND (backend), NULL);
-
+	
 	g_assert (E_BOOK_BACKEND_GET_CLASS (backend)->get_static_capabilities);
 
 	return E_BOOK_BACKEND_GET_CLASS (backend)->get_static_capabilities (backend);
@@ -708,7 +694,7 @@
 e_book_backend_is_writable (EBookBackend *backend)
 {
 	g_return_val_if_fail (E_IS_BOOK_BACKEND (backend), FALSE);
-
+	
 	return backend->priv->writable;
 }
 
@@ -724,7 +710,7 @@
 e_book_backend_set_is_writable (EBookBackend *backend, gboolean is_writable)
 {
 	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
-
+	
 	backend->priv->writable = is_writable;
 }
 
@@ -740,7 +726,7 @@
 e_book_backend_is_removed (EBookBackend *backend)
 {
 	g_return_val_if_fail (E_IS_BOOK_BACKEND (backend), FALSE);
-
+	
 	return backend->priv->removed;
 }
 
@@ -756,7 +742,7 @@
 e_book_backend_set_is_removed (EBookBackend *backend, gboolean is_removed)
 {
 	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
-
+	
 	backend->priv->removed = is_removed;
 }
 
@@ -768,31 +754,23 @@
  * Sets @backend's online/offline mode to @mode. Mode can be 1 for offline
  * or 2 indicating that it is connected and online.
  **/
-void
+void 
 e_book_backend_set_mode (EBookBackend *backend,
-			 GNOME_Evolution_Addressbook_BookMode  mode)
+			 EDataBookMode  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);	
 
 }
 
-/**
- * e_book_backend_sync:
- * @backend: an #EBookbackend
- *
- * Write all pending data to disk.  This is only required under special
- * circumstances (for example before a live backup) and should not be used in
- * normal use.
- */
-void
+void 
 e_book_backend_sync (EBookBackend *backend)
 {
 	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
-
+	
 	if (E_BOOK_BACKEND_GET_CLASS (backend)->sync)
 		(* E_BOOK_BACKEND_GET_CLASS (backend)->sync) (backend);
 }
@@ -806,13 +784,13 @@
  *
  * Return value: A new #GNOME_Evolution_Addressbook_BookChangeItem.
  **/
-GNOME_Evolution_Addressbook_BookChangeItem*
+EDataBookChange *
 e_book_backend_change_add_new     (const char *vcard)
 {
-	GNOME_Evolution_Addressbook_BookChangeItem* new_change = GNOME_Evolution_Addressbook_BookChangeItem__alloc();
+  EDataBookChange *new_change = g_new (EDataBookChange, 1);
 
-	new_change->changeType= GNOME_Evolution_Addressbook_ContactAdded;
-	new_change->vcard = CORBA_string_dup (vcard);
+	new_change->change_type = E_BOOK_BACKEND_CHANGE_ADDED;
+	new_change->vcard = g_strdup (vcard);
 
 	return new_change;
 }
@@ -826,13 +804,13 @@
  *
  * Return value: A new #GNOME_Evolution_Addressbook_BookChangeItem.
  **/
-GNOME_Evolution_Addressbook_BookChangeItem*
+EDataBookChange *
 e_book_backend_change_modify_new  (const char *vcard)
 {
-	GNOME_Evolution_Addressbook_BookChangeItem* new_change = GNOME_Evolution_Addressbook_BookChangeItem__alloc();
+  EDataBookChange *new_change = g_new (EDataBookChange, 1);
 
-	new_change->changeType= GNOME_Evolution_Addressbook_ContactModified;
-	new_change->vcard = CORBA_string_dup (vcard);
+	new_change->change_type = E_BOOK_BACKEND_CHANGE_MODIFIED;
+	new_change->vcard = g_strdup (vcard);
 
 	return new_change;
 }
@@ -846,13 +824,13 @@
  *
  * Return value: A new #GNOME_Evolution_Addressbook_BookChangeItem.
  **/
-GNOME_Evolution_Addressbook_BookChangeItem*
+EDataBookChange *
 e_book_backend_change_delete_new  (const char *vcard)
 {
-	GNOME_Evolution_Addressbook_BookChangeItem* new_change = GNOME_Evolution_Addressbook_BookChangeItem__alloc();
+  EDataBookChange *new_change = g_new (EDataBookChange, 1);
 
-	new_change->changeType= GNOME_Evolution_Addressbook_ContactDeleted;
-	new_change->vcard = CORBA_string_dup (vcard);
+	new_change->change_type = E_BOOK_BACKEND_CHANGE_DELETED;
+	new_change->vcard = g_strdup (vcard);
 
 	return new_change;
 }
@@ -874,9 +852,9 @@
 	while (e_iterator_is_valid (iter)) {
 		view = (EDataBookView*)e_iterator_get (iter);
 
-		bonobo_object_ref (view);
+		g_object_ref (view);
 		callback (view, user_data);
-		bonobo_object_unref (view);
+		g_object_unref (view);
 
 		e_iterator_next (iter);
 	}
@@ -939,7 +917,7 @@
 static void
 view_notify_complete (EDataBookView *view, gpointer unused)
 {
-	e_data_book_view_notify_complete (view, GNOME_Evolution_Addressbook_Success);
+	e_data_book_view_notify_complete (view, Success);
 }
 
 /**
@@ -964,16 +942,16 @@
  *
  * Notifies all backends clients about the current writable state.
  **/
-void
+void 
 e_book_backend_notify_writable (EBookBackend *backend, gboolean is_writable)
 {
 	EBookBackendPrivate *priv;
 	GList *clients;
-
+	
 	priv = backend->priv;
 	priv->writable = is_writable;
 	g_mutex_lock (priv->clients_mutex);
-
+	
 	for (clients = priv->clients; clients != NULL; clients = g_list_next (clients))
 		e_data_book_report_writable (E_DATA_BOOK (clients->data), is_writable);
 
@@ -989,16 +967,15 @@
  * Notifies clients of @backend's connection status indicated by @is_online.
  * Meant to be used by backend implementations.
  **/
-void
+void 
 e_book_backend_notify_connection_status (EBookBackend *backend, gboolean is_online)
 {
 	EBookBackendPrivate *priv;
 	GList *clients;
-
+	
 	priv = backend->priv;
-	priv->online = is_online;
 	g_mutex_lock (priv->clients_mutex);
-
+	
 	for (clients = priv->clients; clients != NULL; clients = g_list_next (clients))
 		e_data_book_report_connection_status (E_DATA_BOOK (clients->data), is_online);
 
@@ -1017,10 +994,10 @@
 {
 	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);
@@ -1033,6 +1010,7 @@
 
 	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 ();
@@ -1056,7 +1034,10 @@
 			backend->priv->views = NULL;
 		}
 
-		g_object_unref (backend->priv->source);
+		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);

Modified: branches/eds-dbus/addressbook/libedata-book/e-book-backend.h
==============================================================================
--- branches/eds-dbus/addressbook/libedata-book/e-book-backend.h	(original)
+++ branches/eds-dbus/addressbook/libedata-book/e-book-backend.h	Fri Sep 12 17:21:22 2008
@@ -16,7 +16,7 @@
  * Author:
  *   Nat Friedman (nat ximian com)
  *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright 2000, Ximian, Inc.
  */
 
 #ifndef __E_BOOK_BACKEND_H__
@@ -25,9 +25,10 @@
 #include <glib.h>
 #include <glib-object.h>
 #include <libebook/e-contact.h>
-#include <libedata-book/Evolution-DataServer-Addressbook.h>
-#include <libedata-book/e-data-book-types.h>
-#include <libedata-book/e-data-book.h>
+#include "e-data-book-types.h"
+#include "e-data-book.h"
+#include <libedataserver/e-list.h>
+#include <libedataserver/e-source.h>
 
 G_BEGIN_DECLS
 
@@ -49,7 +50,7 @@
 	GObjectClass parent_class;
 
 	/* Virtual methods */
-	GNOME_Evolution_Addressbook_CallStatus (*load_source) (EBookBackend *backend, ESource *source, gboolean only_if_exists);
+	EDataBookStatus (*load_source) (EBookBackend *backend, ESource *source, gboolean only_if_exists);
 	void (*remove) (EBookBackend *backend, EDataBook *book, guint32 opid);
         char *(*get_static_capabilities) (EBookBackend *backend);
 
@@ -65,16 +66,16 @@
 	void (*get_required_fields) (EBookBackend *backend, EDataBook *bokk, guint32 opid);
 	void (*get_supported_fields) (EBookBackend *backend, EDataBook *book, guint32 opid);
 	void (*get_supported_auth_methods) (EBookBackend *backend, EDataBook *book, guint32 opid);
-	GNOME_Evolution_Addressbook_CallStatus (*cancel_operation) (EBookBackend *backend, EDataBook *book);
-	void (*set_mode) (EBookBackend *backend, GNOME_Evolution_Addressbook_BookMode  mode);
+	EDataBookStatus (*cancel_operation) (EBookBackend *backend, EDataBook *book);
+	void (*set_mode) (EBookBackend *backend, EDataBookMode  mode);
 
 	/* Notification signals */
 	void (* last_client_gone) (EBookBackend *backend);
 
 	void (*sync) (EBookBackend *backend);
+	void (*modify_contacts)  (EBookBackend *backend, EDataBook *book, guint32 opid, const char **vcards);
 
 	/* Padding for future expansion */
-	void (*_pas_reserved1) (void);
 	void (*_pas_reserved2) (void);
 	void (*_pas_reserved3) (void);
 	void (*_pas_reserved4) (void);
@@ -82,8 +83,7 @@
 
 gboolean    e_book_backend_construct                (EBookBackend             *backend);
 
-GNOME_Evolution_Addressbook_CallStatus
-            e_book_backend_load_source              (EBookBackend             *backend,
+EDataBookStatus e_book_backend_load_source              (EBookBackend             *backend,
 						     ESource                  *source,
 						     gboolean                  only_if_exists);
 ESource    *e_book_backend_get_source               (EBookBackend             *backend);
@@ -120,6 +120,10 @@
 						     EDataBook                *book,
 						     guint32                   opid,
 						     const char               *vcard);
+void        e_book_backend_modify_contacts          (EBookBackend             *backend,
+						     EDataBook                *book,
+						     guint32                   opid,
+						     const char              **vcards);
 void        e_book_backend_get_contact              (EBookBackend             *backend,
 						     EDataBook                *book,
 						     guint32                   opid,
@@ -149,10 +153,10 @@
 void        e_book_backend_get_supported_auth_methods (EBookBackend           *backend,
 						       EDataBook              *book,
 						       guint32                 opid);
-GNOME_Evolution_Addressbook_CallStatus e_book_backend_cancel_operation (EBookBackend             *backend,
+EDataBookStatus e_book_backend_cancel_operation (EBookBackend             *backend,
 									EDataBook                *book);
 void        e_book_backend_set_mode (EBookBackend           *backend,
-				     GNOME_Evolution_Addressbook_BookMode                mode);
+				     EDataBookMode                mode);
 
 void        e_book_backend_start_book_view            (EBookBackend           *backend,
 						       EDataBookView          *view);
@@ -174,7 +178,7 @@
 void        e_book_backend_notify_complete            (EBookBackend           *backend);
 void        e_book_backend_notify_writable            (EBookBackend *backend, gboolean is_writable);
 void        e_book_backend_notify_connection_status   (EBookBackend *backend, gboolean is_online);
-void        e_book_backend_notify_auth_required       (EBookBackend *backend);
+void        e_book_backend_notify_auth_required       (EBookBackend *backend);    
 void        e_book_backend_sync                       (EBookBackend *backend);
 
 GType       e_book_backend_get_type                 (void);
@@ -189,9 +193,9 @@
 						     gboolean                  is_removed);
 
 /* useful for implementing _get_changes in backends */
-GNOME_Evolution_Addressbook_BookChangeItem* e_book_backend_change_add_new     (const char *vcard);
-GNOME_Evolution_Addressbook_BookChangeItem* e_book_backend_change_modify_new  (const char *vcard);
-GNOME_Evolution_Addressbook_BookChangeItem* e_book_backend_change_delete_new  (const char *id);
+EDataBookChange *e_book_backend_change_add_new     (const char *vcard);
+EDataBookChange *e_book_backend_change_modify_new  (const char *vcard);
+EDataBookChange *e_book_backend_change_delete_new  (const char *vcard);
 
 G_END_DECLS
 

Modified: branches/eds-dbus/addressbook/libedata-book/e-data-book-factory.c
==============================================================================
--- branches/eds-dbus/addressbook/libedata-book/e-data-book-factory.c	(original)
+++ branches/eds-dbus/addressbook/libedata-book/e-data-book-factory.c	Fri Sep 12 17:21:22 2008
@@ -1,576 +1,399 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
+ * Copyright (C) 2006 OpenedHand Ltd
  *
- * Author:
- *   Nat Friedman (nat ximian com)
+ * 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.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Author: Ross Burton <ross openedhand com>
  */
 
-#ifdef HAVE_CONFIG_H
 #include <config.h>
-#endif
-
+#include <stdlib.h>
 #include <string.h>
-
-#include <bonobo-activation/bonobo-activation.h>
-#include <bonobo/bonobo-main.h>
-#include <bonobo/bonobo-arg.h>
-#include "libebackend/e-data-server-module.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 <libebackend/e-data-server-module.h>
+#include "e-book-backend-factory.h"
 #include "e-data-book-factory.h"
+#include "e-data-book.h"
+#include "e-book-backend.h"
+#include "e-book-backend-factory.h"
+
+static void impl_BookFactory_getBook(EDataBookFactory *factory, const char *IN_uri, DBusGMethodInvocation *context);
+#include "e-data-book-factory-glue.h"
+
+static gchar *nm_dbus_escape_object_path (const gchar *utf8_string);
+
+static GMainLoop *loop;
+static EDataBookFactory *factory;
+static DBusGProxy *bus_proxy, *backup_proxy;
+
+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
 
-#include <backends/groupwise/e-book-backend-groupwise.h>
-
-#define DEFAULT_E_DATA_BOOK_FACTORY_OAF_ID "OAFIID:GNOME_Evolution_DataServer_BookFactory:" BASE_VERSION
-
-static BonoboObjectClass          *e_data_book_factory_parent_class;
+/* Generate the GObject boilerplate */
+G_DEFINE_TYPE(EDataBookFactory, e_data_book_factory, G_TYPE_OBJECT);
 
-typedef struct {
-	char                                     *uri;
-	GNOME_Evolution_Addressbook_BookListener  listener;
-} EDataBookFactoryQueuedRequest;
+#define E_DATA_BOOK_FACTORY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), E_TYPE_DATA_BOOK_FACTORY, EDataBookFactoryPrivate))
 
 struct _EDataBookFactoryPrivate {
-	GMutex *map_mutex;
-
-	GHashTable *backends;
-	GHashTable *active_server_map;
-
-	/* OAFIID of the factory */
-	char *iid;
-
-	/* Whether the factory has been registered with OAF yet */
-	guint       registered : 1;
-
-	int mode;
-};
+  /* TODO: as the factory is not threaded these locks could be removed */
+  GMutex *backend_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;
 
-/* Signal IDs */
-enum {
-	LAST_BOOK_GONE,
-	LAST_SIGNAL
+  guint exit_timeout;
 };
 
-static guint factory_signals[LAST_SIGNAL];
-
-static char *
-e_data_book_factory_canonicalize_uri (const char *uri)
-{
-	/* FIXME: What do I do here? */
-
-	return g_strdup (uri);
-}
-
-static char *
-e_data_book_factory_extract_proto_from_uri (const char *uri)
-{
-	char *proto;
-	char *p;
-
-	p = strchr (uri, ':');
-
-	if (p == NULL)
-		return NULL;
-
-	proto = g_malloc0 (p - uri + 1);
-
-	strncpy (proto, uri, p - uri);
-
-	return proto;
-}
-
-/**
- * e_data_book_factory_register_backend:
- * @factory: an #EDataBookFactory
- * @backend_factory: an #EBookBackendFactory
- *
- * Registers @backend_factory with @factory.
- **/
-void
-e_data_book_factory_register_backend (EDataBookFactory      *book_factory,
-				      EBookBackendFactory   *backend_factory)
-{
-	const char *proto;
-
-	g_return_if_fail (E_IS_DATA_BOOK_FACTORY (book_factory));
-	g_return_if_fail (E_IS_BOOK_BACKEND_FACTORY (backend_factory));
-
-	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);
+/* Create the EDataBookFactory error quark */
+GQuark
+e_data_book_factory_error_quark (void)
+{
+  static GQuark quark = 0;
+  if (!quark)
+    quark = g_quark_from_static_string ("e_data_book_factory_error");
+  return quark;
 }
 
 static void
-out_of_proc_check (gpointer key, gpointer value, gpointer data)
+e_data_book_factory_register_backend (EDataBookFactory *book_factory, EBookBackendFactory *backend_factory)
 {
-	gboolean *out_of_proc = data;
-
-	if ((*out_of_proc))
-	    return;
-
-	*out_of_proc = e_book_backend_has_out_of_proc_clients (value);
+  const char *proto;
+  
+  g_return_if_fail (E_IS_DATA_BOOK_FACTORY (book_factory));
+  g_return_if_fail (E_IS_BOOK_BACKEND_FACTORY (backend_factory));
+  
+  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);
 }
 
-/**
- * e_data_book_factory_get_n_backends:
- * @factory: An addressbook factory.
- *
- * Queries the number of running addressbook backends in an addressbook factory.
- *
- * Return value: Number of running backends.
- **/
-int
-e_data_book_factory_get_n_backends (EDataBookFactory *factory)
+static void
+e_data_book_factory_register_backends (EDataBookFactory *book_factory)
 {
-	int n_backends;
-	gboolean out_of_proc = FALSE;
-
-	g_return_val_if_fail (factory != NULL, -1);
-	g_return_val_if_fail (E_IS_DATA_BOOK_FACTORY (factory), -1);
-
-	g_mutex_lock (factory->priv->map_mutex);
-	g_hash_table_foreach (factory->priv->active_server_map, out_of_proc_check, &out_of_proc);
-
-	if (!out_of_proc)
-		n_backends = 0;
-	else
-		n_backends = g_hash_table_size (factory->priv->active_server_map);
-	g_mutex_unlock (factory->priv->map_mutex);
-
-	return n_backends;
+  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 ();
 }
 
-/**
- * e_data_book_factory_register_backends:
- * @book_factory: an #EDataBookFactory
- *
- * Register the backends supported by the Evolution Data Server,
- * with @book_factory.
- **/
-void
-e_data_book_factory_register_backends (EDataBookFactory *book_factory)
+/* Class init */
+static void
+e_data_book_factory_class_init (EDataBookFactoryClass *e_data_book_factory_class)
 {
-	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);
+  g_type_class_add_private (e_data_book_factory_class, sizeof (EDataBookFactoryPrivate));
+  dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (e_data_book_factory_class), &dbus_glib_e_data_book_factory_object_info);
 }
 
+/* Instance init */
 static void
-dump_active_server_map_entry (gpointer key, gpointer value, gpointer data)
+e_data_book_factory_init (EDataBookFactory *factory)
 {
-	char *uri;
-	EBookBackend *backend;
+  factory->priv = E_DATA_BOOK_FACTORY_GET_PRIVATE (factory);
+  g_assert (factory->priv);
 
-	uri = key;
-	backend = E_BOOK_BACKEND (value);
+  factory->priv->backend_lock = g_mutex_new ();
+  factory->priv->backends = g_hash_table_new (g_str_hash, g_str_equal);
 
-	g_message ("  %s: %p", uri, backend);
-}
+  factory->priv->books_lock = g_mutex_new ();
+  factory->priv->books = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
 
-/**
- * e_data_book_factory_dump_active_backends:
- * @factory: an #EDataBookFactory
- *
- * Dump the list of active backends registered with @factory
- * to stdout. This is a debugging function.
- **/
-void
-e_data_book_factory_dump_active_backends (EDataBookFactory *factory)
-{
-	g_message ("Active PAS backends");
-
-	g_mutex_lock (factory->priv->map_mutex);
-	g_hash_table_foreach (factory->priv->active_server_map,
-			      dump_active_server_map_entry,
-			      NULL);
-	g_mutex_unlock (factory->priv->map_mutex);
+  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);
 }
 
-/* Callback used when a backend loses its last connected client */
-static void
-backend_last_client_gone_cb (EBookBackend *backend, gpointer data)
+/* TODO: write dispose to kill hash */
+static char *
+e_data_book_factory_extract_proto_from_uri (const char *uri)
 {
-	EDataBookFactory *factory;
-	ESource *source;
-	gchar *uri;
-
-	factory = E_DATA_BOOK_FACTORY (data);
-
-	/* Remove the backend from the active server map */
-
-	source = e_book_backend_get_source (backend);
-	if (source)
-		uri = e_source_get_uri (source);
-	else
-		uri = NULL;
-
-	if (uri) {
-		g_mutex_lock (factory->priv->map_mutex);
-		g_hash_table_remove (factory->priv->active_server_map, uri);
-		g_mutex_unlock (factory->priv->map_mutex);
-	}
-
-	if (g_hash_table_size (factory->priv->active_server_map) == 0) {
-		/* Notify upstream if there are no more backends */
-		g_signal_emit (G_OBJECT (factory), factory_signals[LAST_BOOK_GONE], 0);
-	}
-
-	g_free (uri);
+  char *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 char     *uri)
 {
-	EBookBackendFactory *backend_factory;
-	char                *proto;
-	char                *canonical_uri;
-
-	g_assert (factory != NULL);
-	g_assert (E_IS_DATA_BOOK_FACTORY (factory));
-	g_assert (uri != NULL);
-
-	canonical_uri = e_data_book_factory_canonicalize_uri (uri);
-	if (canonical_uri == NULL)
-		return NULL;
-
-	proto = e_data_book_factory_extract_proto_from_uri (canonical_uri);
-	if (proto == NULL) {
-		g_free (canonical_uri);
-		return NULL;
-	}
+  EBookBackendFactory *backend_factory;
+  char                *proto;
 
-	backend_factory = g_hash_table_lookup (factory->priv->backends, proto);
-
-	g_free (proto);
-	g_free (canonical_uri);
-
-	return backend_factory;
+  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 char* make_path_name(const char* uri)
+{
+  char *s, *path;
+  s = nm_dbus_escape_object_path (uri);
+  path = g_strdup_printf ("/org/gnome/evolution/dataserver/addressbook/%s", s);
+  g_free (s);
+  return path;
+}
+
+static void my_remove (char *key, GObject *dead)
+{
+  g_mutex_lock (factory->priv->books_lock);
+  g_hash_table_remove (factory->priv->books, key);
+  g_mutex_unlock (factory->priv->books_lock);
+
+  g_free (key);
+
+  /* If there are no open books, start a timer to quit */
+  if (factory->priv->exit_timeout == 0 && g_hash_table_size (factory->priv->books) == 0) {
+    factory->priv->exit_timeout = g_timeout_add (10000, (GSourceFunc)g_main_loop_quit, loop);
+  }
 }
 
-static EBookBackend *
-e_data_book_factory_launch_backend (EDataBookFactory      *book_factory,
-				    EBookBackendFactory   *backend_factory,
-				    GNOME_Evolution_Addressbook_BookListener listener,
-				    const char          *uri)
+static void
+book_closed_cb (EDataBook *book, const char *client)
 {
-	EBookBackend          *backend;
+  GList *list;
 
-	backend = e_book_backend_factory_new_backend (backend_factory);
-	if (!backend)
-		return NULL;
-
-	g_hash_table_insert (book_factory->priv->active_server_map,
-			     g_strdup (uri),
-			     backend);
-
-	g_signal_connect (backend, "last_client_gone",
-			  G_CALLBACK (backend_last_client_gone_cb),
-			  book_factory);
-
-	return backend;
+  list = g_hash_table_lookup (factory->priv->connections, client);
+  list = g_list_remove (list, book);
+  g_hash_table_insert (factory->priv->connections, g_strdup (client), list);
 }
 
-static GNOME_Evolution_Addressbook_Book
-impl_GNOME_Evolution_Addressbook_BookFactory_getBook (PortableServer_Servant        servant,
-						      const CORBA_char             *source_xml,
-						      const GNOME_Evolution_Addressbook_BookListener listener,
-						      CORBA_Environment            *ev)
+static void
+impl_BookFactory_getBook(EDataBookFactory *factory, const char *IN_uri, DBusGMethodInvocation *context)
 {
-	EDataBookFactory      *factory = E_DATA_BOOK_FACTORY (bonobo_object (servant));
-	GNOME_Evolution_Addressbook_Book corba_book;
-	EBookBackend *backend;
-	EDataBook *book = NULL;
-	ESource *source;
-	gchar *uri;
-
-	printf ("impl_GNOME_Evolution_Addressbook_BookFactory_getBook\n");
-
-	source = e_source_new_from_standalone_xml (source_xml);
-	if (!source) {
-		CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
-				     ex_GNOME_Evolution_Addressbook_BookFactory_ProtocolNotSupported,
-				     NULL);
-		return CORBA_OBJECT_NIL;
-	}
-
-	uri = e_source_get_uri (source);
-	if (!uri) {
-		g_object_unref (source);
-		CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
-				     ex_GNOME_Evolution_Addressbook_BookFactory_ProtocolNotSupported,
-				     NULL);
-		return CORBA_OBJECT_NIL;
-	}
-	printf (" + %s\n", uri);
-
-	/* Look up the backend and create one if needed */
-	g_mutex_lock (factory->priv->map_mutex);
-
-	backend = g_hash_table_lookup (factory->priv->active_server_map, uri);
-
-	if (!backend) {
-		EBookBackendFactory*  backend_factory;
-
-		backend_factory = e_data_book_factory_lookup_backend_factory (factory, uri);
-
-		if (backend_factory == NULL) {
-			CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
-					     ex_GNOME_Evolution_Addressbook_BookFactory_ProtocolNotSupported,
-					     NULL);
-
-			g_mutex_unlock (factory->priv->map_mutex);
+  EDataBook *book;
+  EDataBookFactoryPrivate *priv = factory->priv;
+  ESource *source;
+  char *path, *sender;
+  GList *list;
+  
+  if (IN_uri == NULL || IN_uri[0] == '\0') {
+    dbus_g_method_return_error (context, g_error_new (E_DATA_BOOK_ERROR, NoSuchBook, _("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->books_lock);
+
+  source = e_source_new_with_absolute_uri ("", IN_uri);
+  path = make_path_name (IN_uri);
+  book = g_hash_table_lookup (priv->books, path);
+  if (book == NULL) {
+    EBookBackend *backend = NULL;
+    backend = e_book_backend_factory_new_backend (e_data_book_factory_lookup_backend_factory (factory, IN_uri));
+    book = e_data_book_new (backend, source, book_closed_cb);
+    e_book_backend_set_mode (backend, 2); /* TODO: very odd */
+    g_hash_table_insert (priv->books, g_strdup(path), 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));
+    g_object_unref (backend); /* The book takes a reference to the backend */
+  } else {
+    g_object_ref (book);
+  }
+  g_object_unref (source);
+
+  /* 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_free (uri);
-			return CORBA_OBJECT_NIL;
-		}
-
-		backend = e_data_book_factory_launch_backend (factory, backend_factory, listener, uri);
-	}
-
-	g_free (uri);
-
-	if (backend) {
-		g_mutex_unlock (factory->priv->map_mutex);
-
-		book = e_data_book_new (backend, source, listener);
-
-		e_book_backend_add_client (backend, book);
-		e_book_backend_set_mode (backend, factory->priv->mode);
-		corba_book = bonobo_object_corba_objref (BONOBO_OBJECT (book));
-	}
-	else {
-		/* probably need a more descriptive exception here */
-		CORBA_exception_set (ev, CORBA_USER_EXCEPTION,
-				     ex_GNOME_Evolution_Addressbook_BookFactory_ProtocolNotSupported,
-				     NULL);
-		g_mutex_unlock (factory->priv->map_mutex);
+  g_mutex_unlock (priv->books_lock);
 
-		corba_book = CORBA_OBJECT_NIL;
-	}
+  dbus_g_method_return (context, path);
+}
 
-	g_object_unref (source);
-	if (book)
-		printf (" => %p\n", book);
-	return corba_book;
+static void
+name_owner_changed (DBusGProxy *proxy,
+                    const char *name,
+                    const char *prev_owner,
+                    const char *new_owner,
+                    EDataBookFactory *factory)
+{
+  if (strcmp (new_owner, "") == 0 && strcmp (name, prev_owner) == 0) {
+    char *key;
+    GList *list = NULL;
+    g_mutex_lock (factory->priv->connections_lock);
+    if (g_hash_table_lookup_extended (factory->priv->connections, prev_owner, (gpointer)&key, (gpointer)&list)) {
+      g_list_foreach (list, (GFunc)g_object_unref, NULL);
+      g_list_free (list);
+      g_hash_table_remove (factory->priv->connections, prev_owner);
+    }
+    g_mutex_unlock (factory->priv->connections_lock);
+  }
 }
 
+/* Convenience function to print an error and exit */
 static void
-e_data_book_factory_construct (EDataBookFactory *factory)
+die (const char *prefix, GError *error) 
 {
-	/* nothing to do here.. */
+  g_error("%s: %s", prefix, error->message);
+  g_error_free (error);
+  exit(1);
 }
 
-/**
- * e_data_book_factory_new:
- *
- * Create a new #EDataBookFactory.
- *
- * Return value: A new #EDataBookFactory.
- **/
-EDataBookFactory *
-e_data_book_factory_new (void)
+static void
+sync_book_foreach (gpointer key, gpointer value, gpointer user_data)
 {
-	static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
-	static PortableServer_POA poa = NULL;
-	EDataBookFactory *factory;
-
-	g_static_mutex_lock (&mutex);
-	if (poa == NULL)
-		poa = bonobo_poa_get_threaded (ORBIT_THREAD_HINT_PER_REQUEST, NULL);
-	g_static_mutex_unlock (&mutex);
-
-	factory = g_object_new (E_TYPE_DATA_BOOK_FACTORY, "poa", poa, NULL);
-
-	e_data_book_factory_construct (factory);
-
-	return factory;
+  EDataBook *book = E_DATA_BOOK (value);
+  g_assert (book);
+  e_book_backend_sync (book->backend);
 }
 
-/**
- * e_data_book_factory_activate:
- * @factory: an #EDataBookFactory
- * @iid: the OAF ID of the factory to activate
- *
- * Activates the factory specified by @iid, using Bonobo.
- *
- * Return value: %TRUE for success, %FALSE otherwise.
- **/
-gboolean
-e_data_book_factory_activate (EDataBookFactory *factory, const char *iid)
-{
-	EDataBookFactoryPrivate *priv;
-	Bonobo_RegistrationResult result;
-	char *tmp_iid;
-
-	g_return_val_if_fail (factory != NULL, FALSE);
-	g_return_val_if_fail (E_IS_DATA_BOOK_FACTORY (factory), FALSE);
-
-	priv = factory->priv;
-
-	g_return_val_if_fail (!priv->registered, FALSE);
-
-	/* if iid is NULL, use the default factory OAFIID */
-	if (iid)
-		tmp_iid = g_strdup (iid);
-	else
-		tmp_iid = g_strdup (DEFAULT_E_DATA_BOOK_FACTORY_OAF_ID);
-
-	result = bonobo_activation_active_server_register (tmp_iid, bonobo_object_corba_objref (BONOBO_OBJECT (factory)));
-
-	switch (result) {
-	case Bonobo_ACTIVATION_REG_SUCCESS:
-		priv->registered = TRUE;
-		priv->iid = tmp_iid;
-		return TRUE;
-	case Bonobo_ACTIVATION_REG_NOT_LISTED:
-		g_message ("Error registering the PAS factory: not listed");
-		break;
-	case Bonobo_ACTIVATION_REG_ALREADY_ACTIVE:
-		g_message ("Error registering the PAS factory: already active");
-		break;
-	case Bonobo_ACTIVATION_REG_ERROR:
-	default:
-		g_message ("Error registering the PAS factory: generic error");
-		break;
-	}
-
-	g_free (tmp_iid);
-	return FALSE;
-}
 static void
-set_backend_online_status (gpointer key, gpointer value, gpointer data)
+backup_start (DBusGProxy *proxy, EDataBookFactory *factory)
 {
-	EBookBackend *backend;
-
-	backend = E_BOOK_BACKEND (value);
-	e_book_backend_set_mode (backend, GPOINTER_TO_INT (data));
+  g_mutex_lock (factory->priv->books_lock);
+  g_hash_table_foreach (factory->priv->books, sync_book_foreach, NULL);
+  g_mutex_unlock (factory->priv->books_lock);
 }
 
-/**
- * e_data_book_factory_set_backend_mode:
- * @factory: an #EDataBookFactory
- * @mode: a connection status
- *
- * Sets all the backends associated with @factory to be either online
- * or offline. @mode should be passed as 1 for offline, or 2 for
- * online.
- **/
-void
-e_data_book_factory_set_backend_mode (EDataBookFactory *factory, int mode)
-{
-	EDataBookFactoryPrivate *priv = factory->priv;
+#define E_DATA_BOOK_FACTORY_SERVICE_NAME "org.gnome.evolution.dataserver.AddressBook"
 
+int
+main (int argc, char **argv)
+{
+  GError *error = NULL;
+  guint32 request_name_ret;
 
-	g_mutex_lock (priv->map_mutex);
-	priv->mode = mode;
-	g_hash_table_foreach (priv->active_server_map, set_backend_online_status, GINT_TO_POINTER (priv->mode));
-	g_mutex_unlock (priv->map_mutex);
+  g_type_init ();
+  if (!g_thread_supported ()) g_thread_init (NULL);
+  dbus_g_thread_init ();
 
-}
-static void
-e_data_book_factory_init (EDataBookFactory *factory)
-{
-	GHashTable *active_server_map;
-	GHashTable *backends;
+  loop = g_main_loop_new (NULL, FALSE);
 
-	active_server_map = g_hash_table_new_full (
-		g_str_hash, g_str_equal,
-		(GDestroyNotify) g_free,
-		(GDestroyNotify) g_object_unref);
-
-	backends = g_hash_table_new_full (
-		g_str_hash, g_str_equal,
-		(GDestroyNotify) g_free,
-		(GDestroyNotify) NULL);
-
-	factory->priv = g_new0 (EDataBookFactoryPrivate, 1);
-
-	factory->priv->map_mutex         = g_mutex_new();
-	factory->priv->active_server_map = active_server_map;
-	factory->priv->backends          = backends;
-	factory->priv->registered        = 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);
 
-static void
-e_data_book_factory_dispose (GObject *object)
-{
-	EDataBookFactory *factory = E_DATA_BOOK_FACTORY (object);
-	EDataBookFactoryPrivate *priv = factory->priv;
+  bus_proxy = dbus_g_proxy_new_for_name (connection,
+                                            DBUS_SERVICE_DBUS,
+                                            DBUS_PATH_DBUS,
+                                            DBUS_INTERFACE_DBUS);
 
-	g_hash_table_remove_all (priv->active_server_map);
-	g_hash_table_remove_all (priv->backends);
+  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 (priv->registered) {
-		bonobo_activation_active_server_unregister (
-			priv->iid, bonobo_object_corba_objref (
-			BONOBO_OBJECT (factory)));
-		priv->registered = FALSE;
-	}
+  if (request_name_ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
+    g_error ("Got result code %u from requesting name", request_name_ret);
+    exit (1);
+  }
 
-	if (G_OBJECT_CLASS (e_data_book_factory_parent_class)->dispose)
-		G_OBJECT_CLASS (e_data_book_factory_parent_class)->dispose (object);
-}
+  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));
 
-static void
-e_data_book_factory_finalize (GObject *object)
-{
-	EDataBookFactory *factory = E_DATA_BOOK_FACTORY (object);
-	EDataBookFactoryPrivate *priv = factory->priv;
+  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);
 
-	g_mutex_free (priv->map_mutex);
-	g_hash_table_destroy (priv->active_server_map);
-	g_hash_table_destroy (priv->backends);
-	g_free (priv->iid);
-	g_free (priv);
+  /* Nokia 770 specific code: listen for backup starting signals */
+  backup_proxy = dbus_g_proxy_new_for_name (connection,
+                                            "com.nokia.backup",
+                                            "/com/nokia/backup",
+                                            "com.nokia.backup");
+  dbus_g_proxy_add_signal (backup_proxy, "backup_start", G_TYPE_INVALID);
+  dbus_g_proxy_connect_signal (backup_proxy, "backup_start", G_CALLBACK (backup_start), factory, NULL);
 
-	if (G_OBJECT_CLASS (e_data_book_factory_parent_class)->finalize)
-		G_OBJECT_CLASS (e_data_book_factory_parent_class)->finalize (object);
+  g_main_loop_run (loop);
+
+  dbus_g_connection_unref (connection);
+
+  return 0;
 }
 
-static void
-e_data_book_factory_class_init (EDataBookFactoryClass *klass)
+/* Stolen from http://cvs.gnome.org/viewcvs/NetworkManager/utils/nm-utils.c */
+static gchar *nm_dbus_escape_object_path (const gchar *utf8_string)
 {
-	GObjectClass *object_class = G_OBJECT_CLASS (klass);
-	POA_GNOME_Evolution_Addressbook_BookFactory__epv *epv;
+	const gchar *p;
+	GString *string;
 
-	e_data_book_factory_parent_class = g_type_class_peek_parent (klass);
+	g_return_val_if_fail (utf8_string != NULL, NULL);	
+	g_return_val_if_fail (g_utf8_validate (utf8_string, -1, NULL), NULL);
 
-	object_class->dispose = e_data_book_factory_dispose;
-	object_class->finalize = e_data_book_factory_finalize;
+	string = g_string_sized_new ((strlen (utf8_string) + 1) * 2);
 
-	factory_signals[LAST_BOOK_GONE] =
-		g_signal_new ("last_book_gone",
-			      G_OBJECT_CLASS_TYPE (object_class),
-			      G_SIGNAL_RUN_FIRST,
-			      G_STRUCT_OFFSET (EDataBookFactoryClass, last_book_gone),
-			      NULL, NULL,
-			      g_cclosure_marshal_VOID__VOID,
-			      G_TYPE_NONE, 0);
+	for (p = utf8_string; *p != '\0'; p = g_utf8_next_char (p))
+	{
+		gunichar character;
 
+		character = g_utf8_get_char (p);
 
-	epv = &klass->epv;
+		if (((character >= ((gunichar) 'a')) && 
+		     (character <= ((gunichar) 'z'))) ||
+		    ((character >= ((gunichar) 'A')) && 
+		     (character <= ((gunichar) 'Z'))) ||
+		    ((character >= ((gunichar) '0')) && 
+		     (character <= ((gunichar) '9'))))
+		{
+			g_string_append_c (string, (gchar) character);
+			continue;
+		}
 
-	epv->getBook = impl_GNOME_Evolution_Addressbook_BookFactory_getBook;
-}
+		g_string_append_printf (string, "_%x_", character);
+	}
 
-BONOBO_TYPE_FUNC_FULL (
-		       EDataBookFactory,
-		       GNOME_Evolution_Addressbook_BookFactory,
-		       BONOBO_TYPE_OBJECT,
-		       e_data_book_factory);
+	return g_string_free (string, FALSE);
+}

Modified: branches/eds-dbus/addressbook/libedata-book/e-data-book-factory.h
==============================================================================
--- branches/eds-dbus/addressbook/libedata-book/e-data-book-factory.h	(original)
+++ branches/eds-dbus/addressbook/libedata-book/e-data-book-factory.h	Fri Sep 12 17:21:22 2008
@@ -1,56 +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) 2006 OpenedHand Ltd
+ *
+ * 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.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Author: Ross Burton <ross openedhand com>
  */
 
-#include <bonobo/bonobo-object.h>
-#include <libedata-book/Evolution-DataServer-Addressbook.h>
-#include <libedata-book/e-book-backend.h>
-#include <libedata-book/e-book-backend-factory.h>
-
 #ifndef __E_DATA_BOOK_FACTORY_H__
 #define __E_DATA_BOOK_FACTORY_H__
 
-G_BEGIN_DECLS
-
-#define E_TYPE_DATA_BOOK_FACTORY        (e_data_book_factory_get_type ())
-#define E_DATA_BOOK_FACTORY(o)          (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_DATA_BOOK_FACTORY, EDataBookFactory))
-#define E_DATA_BOOK_FACTORY_CLASS(k)    (G_TYPE_CHECK_CLASS_CAST((k), E_TYPE_DATA_BOOK_FACTORY, EDataBookFactoryClass))
-#define E_IS_DATA_BOOK_FACTORY(o)       (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_DATA_BOOK_FACTORY))
-#define E_IS_DATA_BOOK_FACTORY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_DATA_BOOK_FACTORY))
-#define E_DATA_BOOK_FACTORY_GET_CLASS(k) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_DATA_BOOK_FACTORY, EDataBookFactoryClass))
+#include <glib-object.h>
 
+typedef struct EDataBookFactory EDataBookFactory;
+typedef struct EDataBookFactoryClass EDataBookFactoryClass;
 typedef struct _EDataBookFactoryPrivate EDataBookFactoryPrivate;
 
-typedef struct {
-	BonoboObject            parent_object;
-	EDataBookFactoryPrivate *priv;
-} EDataBookFactory;
-
-typedef struct {
-	BonoboObjectClass parent_class;
-
-	POA_GNOME_Evolution_Addressbook_BookFactory__epv epv;
-
-	/* Notification signals */
-	void (* last_book_gone) (EDataBookFactory *factory);
-} EDataBookFactoryClass;
-
-EDataBookFactory *e_data_book_factory_new                  (void);
-
-void              e_data_book_factory_register_backend     (EDataBookFactory    *factory,
-							    EBookBackendFactory *backend_factory);
-
-int               e_data_book_factory_get_n_backends       (EDataBookFactory    *factory);
-
-void		  e_data_book_factory_register_backends    (EDataBookFactory    *factory);
-
-void              e_data_book_factory_dump_active_backends (EDataBookFactory    *factory);
-
-gboolean          e_data_book_factory_activate             (EDataBookFactory    *factory, const char *iid);
-void              e_data_book_factory_set_backend_mode             (EDataBookFactory    *factory, int mode);
+struct EDataBookFactory
+{
+  GObject parent;
+  EDataBookFactoryPrivate *priv;
+};
+
+struct EDataBookFactoryClass
+{
+  GObjectClass parent;
+};
+
+#define E_TYPE_DATA_BOOK_FACTORY              (e_data_book_factory_get_type ())
+#define E_DATA_BOOK_FACTORY(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), E_TYPE_DATA_BOOK_FACTORY, EDataBookFactory))
+#define E_DATA_BOOK_FACTORY_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_DATA_BOOK_FACTORY, EDataBookFactoryClass))
+#define E_IS_DATA_BOOK_FACTORY(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), E_TYPE_DATA_BOOK_FACTORY))
+#define E_IS_DATA_BOOK_FACTORY_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_DATA_BOOK_FACTORY))
+#define E_DATA_BOOK_FACTORY_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_DATA_BOOK_FACTORY, EDataBookFactoryClass))
+
+typedef enum
+{
+  E_DATA_BOOK_FACTORY_ERROR_GENERIC
+} EDataBookFactoryError;
 
-GType             e_data_book_factory_get_type             (void);
+GQuark e_data_book_factory_error_quark (void);
+#define E_DATA_BOOK_FACTORY_ERROR e_data_book_factory_error_quark ()
 
-G_END_DECLS
+GType e_data_book_factory_get_type (void);
 
-#endif /* ! __E_DATA_BOOK_FACTORY_H__ */
+#endif /* __E_DATA_BOOK_FACTORY_H__ */

Modified: branches/eds-dbus/addressbook/libedata-book/e-data-book-types.h
==============================================================================
--- branches/eds-dbus/addressbook/libedata-book/e-data-book-types.h	(original)
+++ branches/eds-dbus/addressbook/libedata-book/e-data-book-types.h	Fri Sep 12 17:21:22 2008
@@ -31,6 +31,83 @@
 typedef struct _EDataBook        EDataBook;
 typedef struct _EDataBookClass   EDataBookClass;
 
+typedef enum {
+	Success,
+	RepositoryOffline,
+	PermissionDenied,
+	ContactNotFound,
+	ContactIdAlreadyExists,
+	AuthenticationFailed,
+	AuthenticationRequired,
+	UnsupportedField,
+	UnsupportedAuthenticationMethod,
+	TLSNotAvailable,
+	NoSuchBook,
+	BookRemoved,
+	OfflineUnavailable,
+	
+	/* These can be returned for successful searches, but
+	   indicate the result set was truncated */
+	SearchSizeLimitExceeded,
+	SearchTimeLimitExceeded,
+	
+	InvalidQuery,
+	QueryRefused,
+	
+	CouldNotCancel,
+	
+	OtherError,
+	InvalidServerVersion,
+	NoSpace,
+} EDataBookStatus;
+
+/* Some hacks so the backends compile without change */
+#define GNOME_Evolution_Addressbook_CallStatus EDataBookStatus
+#define GNOME_Evolution_Addressbook_BookMode EDataBookMode
+
+#define GNOME_Evolution_Addressbook_Success                         Success
+#define GNOME_Evolution_Addressbook_RepositoryOffline               RepositoryOffline
+#define GNOME_Evolution_Addressbook_PermissionDenied                PermissionDenied
+#define GNOME_Evolution_Addressbook_ContactNotFound                 ContactNotFound
+#define GNOME_Evolution_Addressbook_ContactIdAlreadyExists          ContactIdAlreadyExists
+#define GNOME_Evolution_Addressbook_AuthenticationFailed            AuthenticationFailed
+#define GNOME_Evolution_Addressbook_AuthenticationRequired          AuthenticationRequired
+#define GNOME_Evolution_Addressbook_UnsupportedField                UnsupportedField
+#define GNOME_Evolution_Addressbook_UnsupportedAuthenticationMethod UnsupportedAuthenticationMethod
+#define GNOME_Evolution_Addressbook_TLSNotAvailable                 TLSNotAvailable
+#define GNOME_Evolution_Addressbook_NoSuchBook                      NoSuchBook
+#define GNOME_Evolution_Addressbook_BookRemoved                     BookRemoved
+#define GNOME_Evolution_Addressbook_OfflineUnavailable              OfflineUnavailable
+#define GNOME_Evolution_Addressbook_SearchSizeLimitExceeded         SearchSizeLimitExceeded
+#define GNOME_Evolution_Addressbook_SearchTimeLimitExceeded         SearchTimeLimitExceeded
+#define GNOME_Evolution_Addressbook_InvalidQuery                    InvalidQuery
+#define GNOME_Evolution_Addressbook_QueryRefused                    QueryRefused
+#define GNOME_Evolution_Addressbook_CouldNotCancel                  CouldNotCancel
+#define GNOME_Evolution_Addressbook_OtherError                      OtherError
+#define GNOME_Evolution_Addressbook_InvalidServerVersion            InvalidServerVersion
+#define GNOME_Evolution_Addressbook_NoSpace                         NoSpace
+
+typedef enum {
+	Local,
+	Remote,
+	Any,
+} EDataBookMode;
+
+#define GNOME_Evolution_Addressbook_MODE_LOCAL Local
+#define GNOME_Evolution_Addressbook_MODE_REMOTE Remote
+#define GNOME_Evolution_Addressbook_MODE_ANY Any
+
+typedef enum {
+  E_BOOK_BACKEND_CHANGE_ADDED,
+  E_BOOK_BACKEND_CHANGE_DELETED,
+  E_BOOK_BACKEND_CHANGE_MODIFIED
+} EDataBookChangeType;
+
+typedef struct {
+  EDataBookChangeType change_type;
+  char *vcard;
+} EDataBookChange;
+
 G_END_DECLS
 
 #endif /* __E_DATA_BOOK_TYPES_H__ */

Modified: branches/eds-dbus/addressbook/libedata-book/e-data-book-view.c
==============================================================================
--- branches/eds-dbus/addressbook/libedata-book/e-data-book-view.c	(original)
+++ branches/eds-dbus/addressbook/libedata-book/e-data-book-view.c	Fri Sep 12 17:21:22 2008
@@ -1,767 +1,583 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /*
- * pas-book-view.c
+ * Copyright (C) 2006 OpenedHand Ltd
  *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * 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.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Author: Ross Burton <ross openedhand com>
  */
 
-#ifdef HAVE_CONFIG_H
 #include <config.h>
-#endif
-
 #include <string.h>
-#include <glib.h>
-#include <bonobo/bonobo-main.h>
-#include "e-book-backend.h"
-#include "e-book-backend-sexp.h"
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+#include <libebook/e-contact.h>
 #include "e-data-book-view.h"
 
-#define d(x)
+extern DBusGConnection *connection;
 
-static BonoboObjectClass *e_data_book_view_parent_class;
+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);
 
-struct _EDataBookViewPrivate {
-	GNOME_Evolution_Addressbook_BookViewListener  listener;
+#include "e-data-book-view-glue.h"
 
-#define DEFAULT_INITIAL_THRESHOLD 20
-#define DEFAULT_THRESHOLD_MAX 3000
+static void reset_array (GArray *array);
 
-	GMutex *mutex;
+G_DEFINE_TYPE (EDataBookView, e_data_book_view, G_TYPE_OBJECT);
+#define E_DATA_BOOK_VIEW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), E_TYPE_DATA_BOOK_VIEW, EDataBookViewPrivate))
 
-	GMutex *pending_mutex;
+#define THRESHOLD 32
 
-	CORBA_sequence_GNOME_Evolution_Addressbook_VCard adds;
-	int next_threshold;
-	int threshold_max;
-	int threshold_min;
+struct _EDataBookViewPrivate {
+  EDataBook *book;
+  EBookBackend *backend;
 
-	CORBA_sequence_GNOME_Evolution_Addressbook_VCard changes;
-	CORBA_sequence_GNOME_Evolution_Addressbook_ContactId removes;
+  char* card_query;
+  EBookBackendSExp *card_sexp;
+  int max_results;
+
+  gboolean running;
+  GMutex *pending_mutex;
+
+  GArray *adds;
+  GArray *changes;
+  GArray *removes;
 
-	EBookBackend *backend;
-	char *card_query;
-	EBookBackendSExp *card_sexp;
-	GHashTable *ids;
+  GHashTable *ids;
+  guint idle_id;
+};
 
-	int max_results;
+enum {
+  CONTACTS_ADDED,
+  CONTACTS_CHANGED,
+  CONTACTS_REMOVED,
+  STATUS_MESSAGE,
+  COMPLETE,
+  LAST_SIGNAL
 };
 
-static void
-view_listener_died_cb (gpointer cnx, gpointer user_data)
-{
-	EDataBookView *book_view = E_DATA_BOOK_VIEW (user_data);
+static guint signals[LAST_SIGNAL] = { 0 };
 
-	if (book_view) {
-		e_book_backend_stop_book_view (e_data_book_view_get_backend (book_view), book_view);
-		bonobo_object_unref (book_view);
-	}
-}
+static void e_data_book_view_dispose (GObject *object);
+static void e_data_book_view_finalize (GObject *object);
 
 static void
-send_pending_adds (EDataBookView *book_view, gboolean reset)
-{
-	CORBA_Environment ev;
-	CORBA_sequence_GNOME_Evolution_Addressbook_VCard *adds;
-
-	adds = &book_view->priv->adds;
-	if (adds->_length == 0)
-		return;
-
-	CORBA_exception_init (&ev);
-
-	GNOME_Evolution_Addressbook_BookViewListener_notifyContactsAdded (
-		book_view->priv->listener, adds, &ev);
+e_data_book_view_class_init (EDataBookViewClass *klass)
+{ 
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
-	if (ev._major != CORBA_NO_EXCEPTION) {
-		g_warning ("send_pending_adds: Exception signaling BookViewListener!\n");
-	}
+  object_class->dispose = e_data_book_view_dispose;
+  object_class->finalize = e_data_book_view_finalize;
 
-	CORBA_exception_free (&ev);
+  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);
 
-	CORBA_free (adds->_buffer);
-	adds->_buffer = NULL;
-	adds->_maximum = 0;
-	adds->_length = 0;
+  g_type_class_add_private (klass, sizeof (EDataBookViewPrivate));
 
-	if (reset)
-		book_view->priv->next_threshold = book_view->priv->threshold_min;
+  dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (klass), &dbus_glib_e_data_book_view_object_info);
 }
 
 static void
-send_pending_changes (EDataBookView *book_view)
+e_data_book_view_init (EDataBookView *book_view)
 {
-	CORBA_Environment ev;
-	CORBA_sequence_GNOME_Evolution_Addressbook_VCard *changes;
-
-	changes = &book_view->priv->changes;
-	if (changes->_length == 0)
-		return;
-
-	CORBA_exception_init (&ev);
+  EDataBookViewPrivate *priv = E_DATA_BOOK_VIEW_GET_PRIVATE (book_view);
+  book_view->priv = priv;
 
-	GNOME_Evolution_Addressbook_BookViewListener_notifyContactsChanged (
-		book_view->priv->listener, changes, &ev);
+  priv->running = FALSE;
+  priv->pending_mutex = g_mutex_new ();
 
-	if (ev._major != CORBA_NO_EXCEPTION) {
-		g_warning ("send_pending_changes: Exception signaling BookViewListener!\n");
-	}
+  priv->adds = g_array_sized_new (TRUE, TRUE, sizeof (char*), THRESHOLD);
+  priv->changes = g_array_sized_new (TRUE, TRUE, sizeof (char*), THRESHOLD);
+  priv->removes = g_array_sized_new (TRUE, TRUE, sizeof (char*), THRESHOLD);
 
-	CORBA_exception_free (&ev);
-
-	CORBA_free (changes->_buffer);
-	changes->_buffer = NULL;
-	changes->_maximum = 0;
-	changes->_length = 0;
+  priv->ids = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                     g_free, NULL);
 }
 
 static void
-send_pending_removes (EDataBookView *book_view)
+book_destroyed_cb (gpointer data, GObject *dead)
 {
-	CORBA_Environment ev;
-	CORBA_sequence_GNOME_Evolution_Addressbook_VCard *removes;
-
-	removes = &book_view->priv->removes;
-	if (removes->_length == 0)
-		return;
-
-	CORBA_exception_init (&ev);
-
-	GNOME_Evolution_Addressbook_BookViewListener_notifyContactsRemoved (
-		book_view->priv->listener, removes, &ev);
-
-	if (ev._major != CORBA_NO_EXCEPTION) {
-		g_warning ("send_pending_removes: Exception signaling BookViewListener!\n");
-	}
+  EDataBookView *view = E_DATA_BOOK_VIEW (data);
+  EDataBookViewPrivate *priv = view->priv;
 
-	CORBA_exception_free (&ev);
+  /* The book has just died, so unset the pointer so we don't try and remove a
+     dead weak reference. */
+  view->priv->book = NULL;
 
-	CORBA_free (removes->_buffer);
-	removes->_buffer = NULL;
-	removes->_maximum = 0;
-	removes->_length = 0;
+  /* If the view is running stop it here. */
+  if (priv->running) {
+    e_book_backend_stop_book_view (priv->backend, view);
+    priv->running = FALSE;
+  }
 }
 
-#define MAKE_REALLOC(type)						\
-static void								\
-CORBA_sequence_ ## type ## _realloc (CORBA_sequence_ ## type *seq,	\
-				     CORBA_unsigned_long      new_max)	\
-{									\
-	type *new_buf;							\
-	int i;								\
-	new_buf = CORBA_sequence_ ## type ## _allocbuf (new_max);	\
-	for (i = 0; i < seq->_maximum; i ++)				\
-		new_buf[i] = CORBA_string_dup (seq->_buffer[i]);	\
-	CORBA_free (seq->_buffer);					\
-	seq->_buffer = new_buf;						\
-	seq->_maximum = new_max;					\
-}
-
-MAKE_REALLOC (GNOME_Evolution_Addressbook_VCard)
-MAKE_REALLOC (GNOME_Evolution_Addressbook_ContactId)
-
-static void
-notify_change (EDataBookView *book_view, const char *vcard)
+/**
+ * e_data_book_view_new:
+ * @book: The #EDataBook to search
+ * @path: The object path that this book view should have
+ * @card_query: The query as a string
+ * @card_sexp: The query as an #EBookBackendSExp
+ * @max_results: The maximum number of results to return
+ *
+ * Create a new #EDataBookView for the given #EBook, filtering on #card_sexp,
+ * and place it on DBus at the object path #path.
+ */
+EDataBookView *
+e_data_book_view_new (EDataBook *book, const char *path, const char *card_query, EBookBackendSExp *card_sexp, int max_results)
 {
-	CORBA_sequence_GNOME_Evolution_Addressbook_VCard *changes;
+  EDataBookView *view;
+  EDataBookViewPrivate *priv;
 
-	send_pending_adds (book_view, TRUE);
-	send_pending_removes (book_view);
+  view = g_object_new (E_TYPE_DATA_BOOK_VIEW, NULL);
+  priv = view->priv;
 
-	changes = &book_view->priv->changes;
+  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;
 
-	if (changes->_length == changes->_maximum) {
-		CORBA_sequence_GNOME_Evolution_Addressbook_VCard_realloc (
-			changes, 2 * (changes->_maximum + 1));
-	}
+  dbus_g_connection_register_g_object (connection, path, G_OBJECT (view));
 
-	changes->_buffer[changes->_length++] = CORBA_string_dup (vcard);
+  return view;
 }
 
 static void
-notify_remove (EDataBookView *book_view, const char *id)
+e_data_book_view_dispose (GObject *object)
 {
-	CORBA_sequence_GNOME_Evolution_Addressbook_ContactId *removes;
+  EDataBookView *book_view = E_DATA_BOOK_VIEW (object);
+  EDataBookViewPrivate *priv = book_view->priv;
 
-	send_pending_adds (book_view, TRUE);
-	send_pending_changes (book_view);
+  if (priv->book) {
+    /* Remove the weak reference */
+    g_object_weak_unref (G_OBJECT (priv->book), book_destroyed_cb, book_view);
+    priv->book = NULL;
+  }
 
-	removes = &book_view->priv->removes;
+  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 (removes->_length == removes->_maximum) {
-		CORBA_sequence_GNOME_Evolution_Addressbook_ContactId_realloc (
-			removes, 2 * (removes->_maximum + 1));
-	}
+  if (priv->idle_id) {
+    g_source_remove (priv->idle_id);
+    priv->idle_id = 0;
+  }
 
-	removes->_buffer[removes->_length++] = CORBA_string_dup (id);
-	g_hash_table_remove (book_view->priv->ids, id);
+  G_OBJECT_CLASS (e_data_book_view_parent_class)->dispose (object);
 }
 
 static void
-notify_add (EDataBookView *book_view, const char *id, const char *vcard)
+e_data_book_view_finalize (GObject *object)
 {
-	CORBA_sequence_GNOME_Evolution_Addressbook_VCard *adds;
-	EDataBookViewPrivate *priv = book_view->priv;
-
-	send_pending_changes (book_view);
-	send_pending_removes (book_view);
+  EDataBookView *book_view = E_DATA_BOOK_VIEW (object);
+  EDataBookViewPrivate *priv = book_view->priv;
 
-	adds = &priv->adds;
+  reset_array (priv->adds);
+  reset_array (priv->changes);
+  reset_array (priv->removes);
+  g_array_free (priv->adds, TRUE);
+  g_array_free (priv->changes, TRUE);
+  g_array_free (priv->removes, TRUE);
 
-	if (adds->_length == adds->_maximum) {
-		send_pending_adds (book_view, FALSE);
+  g_free (priv->card_query);
 
-		adds->_buffer = CORBA_sequence_GNOME_Evolution_Addressbook_VCard_allocbuf (priv->next_threshold);
-		adds->_maximum = priv->next_threshold;
+  g_mutex_free (priv->pending_mutex);
 
-		if (priv->next_threshold < priv->threshold_max) {
-			priv->next_threshold = MIN (2 * priv->next_threshold,
-						    priv->threshold_max);
-		}
-	}
+  g_hash_table_destroy (priv->ids);
 
-	adds->_buffer[adds->_length++] = CORBA_string_dup (vcard);
-	g_hash_table_insert (book_view->priv->ids, g_strdup (id),
-			     GUINT_TO_POINTER (1));
+  G_OBJECT_CLASS (e_data_book_view_parent_class)->finalize (object);
 }
 
-/**
- * e_data_book_view_notify_update:
- * @book_view: an #EDataBookView
- * @contact: an #EContact
- *
- * Notify listeners that @contact has changed. This can
- * trigger an add, change or removal event depending on
- * whether the change causes the contact to start matching,
- * no longer match, or stay matching the query specified
- * by @book_view.
- **/
-void
-e_data_book_view_notify_update (EDataBookView *book_view,
-			     EContact    *contact)
+static gboolean
+bookview_idle_start (gpointer data)
 {
-	gboolean currently_in_view, want_in_view;
-	const char *id=NULL;
-	char *vcard;
-
-	g_mutex_lock (book_view->priv->pending_mutex);
-
-	id = e_contact_get_const (contact, E_CONTACT_UID);
-	if (!id) {
-		g_object_unref (contact);
-		g_mutex_unlock (book_view->priv->pending_mutex);
-		return;
-	}
-
-	currently_in_view =
-		g_hash_table_lookup (book_view->priv->ids, id) != NULL;
-	want_in_view = e_book_backend_sexp_match_contact (
-		book_view->priv->card_sexp, contact);
-
-	if (want_in_view) {
-		vcard = e_vcard_to_string (E_VCARD (contact),
-					   EVC_FORMAT_VCARD_30);
-
-		if (currently_in_view)
-			notify_change (book_view, vcard);
-		else
-			notify_add (book_view, id, vcard);
-
-		g_free (vcard);
-	} else {
-		if (currently_in_view)
-			notify_remove (book_view, id);
-		/* else nothing; we're removing a card that wasn't there */
-	}
+  EDataBookView *book_view = data;
 
-	g_mutex_unlock (book_view->priv->pending_mutex);
+  book_view->priv->running = TRUE;
+  book_view->priv->idle_id = 0;
+
+  e_book_backend_start_book_view (book_view->priv->backend, book_view);
+  return FALSE;
 }
 
-/**
- * e_data_book_view_notify_update_vcard:
- * @book_view: an #EDataBookView
- * @vcard: a plain vCard
- *
- * Notify listeners that @vcard has changed. This can
- * trigger an add, change or removal event depending on
- * whether the change causes the contact to start matching,
- * no longer match, or stay matching the query specified
- * by @book_view.  This method should be preferred over
- * #e_data_book_view_notify_update when the native
- * representation of a contact is a vCard.
- **/
-void
-e_data_book_view_notify_update_vcard (EDataBookView *book_view, char *vcard)
+static gboolean
+impl_BookView_start (EDataBookView *book_view, GError **error)
 {
-	gboolean currently_in_view, want_in_view;
-	const char *id = NULL;
-	EContact *contact;
-
-	g_mutex_lock (book_view->priv->pending_mutex);
-
-	contact = e_contact_new_from_vcard (vcard);
-	id = e_contact_get_const (contact, E_CONTACT_UID);
-	if (!id) {
-		free (vcard);
-		g_object_unref (contact);
-		g_mutex_unlock (book_view->priv->pending_mutex);
-		return;
-	}
-
-	currently_in_view =
-		g_hash_table_lookup (book_view->priv->ids, id) != NULL;
-	want_in_view =
-		e_book_backend_sexp_match_contact (book_view->priv->card_sexp, contact);
-
-	if (want_in_view) {
-		if (currently_in_view)
-			notify_change (book_view, vcard);
-		else
-			notify_add (book_view, id, vcard);
-	} else {
-		if (currently_in_view)
-			notify_remove (book_view, id);
-	}
-
-	g_free (vcard);
-	g_object_unref (contact);
-	g_mutex_unlock (book_view->priv->pending_mutex);
+  book_view->priv->idle_id = g_idle_add (bookview_idle_start, book_view);
+  return TRUE;
 }
 
-/**
- * e_data_book_view_notify_update_prefiltered_vcard:
- * @book_view: an #EDataBookView
- * @id: the UID of this contact
- * @vcard: a plain vCard
- *
- * Notify listeners that @vcard has changed. This can
- * trigger an add, change or removal event depending on
- * whether the change causes the contact to start matching,
- * no longer match, or stay matching the query specified
- * by @book_view.  This method should be preferred over
- * #e_data_book_view_notify_update when the native
- * representation of a contact is a vCard.
- *
- * The important difference between this method and
- * #e_data_book_view_notify_update and #e_data_book_view_notify_update_vcard is
- * that it doesn't match the contact against the book view query to see if it
- * should be included, it assumes that this has been done and the contact is
- * known to exist in the view.
- **/
-void
-e_data_book_view_notify_update_prefiltered_vcard (EDataBookView *book_view, const char *id, char *vcard)
+static gboolean
+bookview_idle_stop (gpointer data)
 {
-	gboolean currently_in_view;
+  EDataBookView *book_view = data;
 
-	g_mutex_lock (book_view->priv->pending_mutex);
+  e_book_backend_stop_book_view (book_view->priv->backend, book_view);
 
-	currently_in_view =
-		g_hash_table_lookup (book_view->priv->ids, id) != NULL;
+  book_view->priv->running = FALSE;
+  book_view->priv->idle_id = 0;
 
-	if (currently_in_view)
-		notify_change (book_view, vcard);
-	else
-		notify_add (book_view, id, vcard);
-
-	g_free (vcard);
-	g_mutex_unlock (book_view->priv->pending_mutex);
+  return FALSE;
 }
 
-/**
- * e_data_book_view_notify_remove:
- * @book_view: an #EDataBookView
- * @id: a unique contact ID
- *
- * Notify listeners that a contact specified by @id
- * was removed from @book_view.
- **/
-void
-e_data_book_view_notify_remove (EDataBookView *book_view,
-			     const char  *id)
+static gboolean
+impl_BookView_stop (EDataBookView *book_view, GError **error)
 {
-	g_mutex_lock (book_view->priv->pending_mutex);
-
-	if (g_hash_table_lookup (book_view->priv->ids, id))
-		notify_remove (book_view, id);
-
-	g_mutex_unlock (book_view->priv->pending_mutex);
+  if (book_view->priv->idle_id)
+    g_source_remove (book_view->priv->idle_id);
+  
+  book_view->priv->idle_id = g_idle_add (bookview_idle_stop, book_view);
+  return TRUE;
 }
 
-/**
- * e_data_book_view_notify_complete:
- * @book_view: an #EDataBookView
- * @status: the status of the query
- *
- * Notifies listeners that all pending updates on @book_view
- * have been sent. The listener's information should now be
- * in sync with the backend's.
- **/
-void
-e_data_book_view_notify_complete (EDataBookView *book_view,
-			       GNOME_Evolution_Addressbook_CallStatus status)
+static gboolean
+impl_BookView_dispose (EDataBookView *book_view, GError **eror)
 {
-	CORBA_Environment ev;
-
-	g_mutex_lock (book_view->priv->pending_mutex);
-
-	send_pending_adds (book_view, TRUE);
-	send_pending_changes (book_view);
-	send_pending_removes (book_view);
-
-	g_mutex_unlock (book_view->priv->pending_mutex);
-
-	CORBA_exception_init (&ev);
-
-	GNOME_Evolution_Addressbook_BookViewListener_notifySequenceComplete (
-		book_view->priv->listener, status, &ev);
-
-	if (ev._major != CORBA_NO_EXCEPTION) {
-		g_warning ("e_data_book_view_notify_complete: Exception signaling BookViewListener!\n");
-	}
-
-	CORBA_exception_free (&ev);
+  g_object_unref (book_view);
+  
+  return TRUE;
 }
 
-/**
- * e_data_book_view_notify_status_message:
- * @book_view: an #EDataBookView
- * @message: a text message
- *
- * Provides listeners with a human-readable text describing the
- * current backend operation. This can be used for progress
- * reporting.
- **/
 void
-e_data_book_view_notify_status_message (EDataBookView *book_view,
-				     const char  *message)
+e_data_book_view_set_thresholds (EDataBookView *book_view,
+                                 int minimum_grouping_threshold,
+                                 int maximum_grouping_threshold)
 {
-	CORBA_Environment ev;
-
-	CORBA_exception_init (&ev);
-
-	GNOME_Evolution_Addressbook_BookViewListener_notifyProgress (
-		book_view->priv->listener, message, 0, &ev);
-
-	if (ev._major != CORBA_NO_EXCEPTION) {
-		g_warning ("e_data_book_view_notify_status_message: Exception signaling BookViewListener!\n");
-	}
-
-	CORBA_exception_free (&ev);
+  g_return_if_fail (E_IS_DATA_BOOK_VIEW (book_view));
+  
+  g_debug ("e_data_book_view_set_thresholds does nothing in eds-dbus");
 }
 
-static void
-e_data_book_view_construct (EDataBookView                *book_view,
-			    EBookBackend                 *backend,
-			    GNOME_Evolution_Addressbook_BookViewListener  listener,
-			    const char                   *card_query,
-			    EBookBackendSExp             *card_sexp,
-			    int                           max_results)
+const char*
+e_data_book_view_get_card_query (EDataBookView *book_view)
 {
-	EDataBookViewPrivate *priv;
-	CORBA_Environment ev;
-
-	g_return_if_fail (book_view != NULL);
-	g_return_if_fail (listener != CORBA_OBJECT_NIL);
-
-	priv = book_view->priv;
-
-	CORBA_exception_init (&ev);
-
-	priv->listener = bonobo_object_dup_ref (listener, &ev);
-	if (ev._major != CORBA_NO_EXCEPTION) {
-		g_warning("Unable to duplicate listener object in pas-book-view.c\n");
-		CORBA_exception_free (&ev);
-		return;
-	}
-
-	CORBA_exception_free (&ev);
-
-	priv->backend = backend;
-	priv->card_query = g_strdup (card_query);
-	priv->card_sexp = card_sexp;
-	priv->max_results = max_results;
+  g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (book_view), NULL);
+  return book_view->priv->card_query;
+}
 
-	ORBit_small_listen_for_broken (e_data_book_view_get_listener (book_view), G_CALLBACK (view_listener_died_cb), book_view);
+EBookBackendSExp*
+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;
 }
 
-static void
-impl_GNOME_Evolution_Addressbook_BookView_start (PortableServer_Servant servant,
-						 CORBA_Environment *ev)
+int
+e_data_book_view_get_max_results (EDataBookView *book_view)
 {
-	EDataBookView *view = E_DATA_BOOK_VIEW (bonobo_object (servant));
+  g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (book_view), 0);
+  return book_view->priv->max_results;
+}
 
-	e_book_backend_start_book_view (e_data_book_view_get_backend (view), view);
+EBookBackend*
+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;
 }
 
 static void
-impl_GNOME_Evolution_Addressbook_BookView_stop (PortableServer_Servant servant,
-						CORBA_Environment *ev)
+send_pending_adds (EDataBookView *view)
 {
-	EDataBookView *view = E_DATA_BOOK_VIEW (bonobo_object (servant));
+  EDataBookViewPrivate *priv = view->priv;
+
+  if (priv->adds->len == 0)
+    return;
 
-	e_book_backend_stop_book_view (e_data_book_view_get_backend (view), view);
+  g_signal_emit (view, signals[CONTACTS_ADDED], 0, priv->adds->data);
+  reset_array (priv->adds);
 }
 
 static void
-impl_GNOME_Evolution_Addressbook_BookView_dispose (PortableServer_Servant servant,
-						   CORBA_Environment *ev)
+send_pending_changes (EDataBookView *view)
 {
-	EDataBookView *view = E_DATA_BOOK_VIEW (bonobo_object (servant));
+  EDataBookViewPrivate *priv = view->priv;
 
-	d(printf("in impl_GNOME_Evolution_Addressbook_BookView_dispose\n"));
-	ORBit_small_unlisten_for_broken (e_data_book_view_get_listener (view), G_CALLBACK (view_listener_died_cb));
+  if (priv->changes->len == 0)
+    return;
 
-	bonobo_object_unref (view);
+  g_signal_emit (view, signals[CONTACTS_CHANGED], 0, priv->changes->data);
+  reset_array (priv->changes);
 }
 
-/**
- * e_data_book_view_get_card_query:
- * @book_view: an #EDataBookView
- *
- * Gets the text representation of the s-expression used
- * for matching contacts to @book_view.
- *
- * Return value: The textual s-expression used.
- **/
-const char*
-e_data_book_view_get_card_query (EDataBookView *book_view)
+static void
+send_pending_removes (EDataBookView *view)
 {
-	g_return_val_if_fail (book_view, NULL);
+  EDataBookViewPrivate *priv = view->priv;
 
-	return book_view->priv->card_query;
+  if (priv->removes->len == 0)
+    return;
+
+  g_signal_emit (view, signals[CONTACTS_REMOVED], 0, priv->removes->data);
+  reset_array (priv->removes);
 }
 
-/**
- * e_data_book_view_get_card_sexp:
- * @book_view: an #EDataBookView
- *
- * Gets the s-expression used for matching contacts to
- * @book_view.
- *
- * Return value: The #EBookBackendSExp used.
- **/
-EBookBackendSExp*
-e_data_book_view_get_card_sexp (EDataBookView *book_view)
+static void
+notify_change (EDataBookView *view, char *vcard)
 {
-	g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (book_view), NULL);
-
-	return book_view->priv->card_sexp;
+  EDataBookViewPrivate *priv = view->priv;
+  send_pending_adds (view);
+  send_pending_removes (view);
+  
+  g_array_append_val (priv->changes, vcard);
 }
 
-/**
- * e_data_book_view_get_max_results:
- * @book_view: an #EDataBookView
- *
- * Gets the maximum number of results returned by
- * @book_view's query.
- *
- * Return value: The maximum number of results returned.
- **/
-int
-e_data_book_view_get_max_results (EDataBookView *book_view)
+static void
+notify_remove (EDataBookView *view, char *id)
 {
-	g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (book_view), 0);
+  EDataBookViewPrivate *priv = view->priv;
+
+  send_pending_adds (view);
+  send_pending_changes (view);
 
-	return book_view->priv->max_results;
+  g_array_append_val (priv->removes, id);
+  g_hash_table_remove (priv->ids, id);
 }
 
-/**
- * e_data_book_view_get_backend:
- * @book_view: an #EDataBookView
- *
- * Gets the backend that @book_view is querying.
- *
- * Return value: The associated #EBookBackend.
- **/
-EBookBackend*
-e_data_book_view_get_backend (EDataBookView *book_view)
+static void
+notify_add (EDataBookView *view, const char *id, char *vcard)
 {
-	g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (book_view), NULL);
+  EDataBookViewPrivate *priv = view->priv;
+  send_pending_changes (view);
+  send_pending_removes (view);
 
-	return book_view->priv->backend;
+  if (priv->adds->len == THRESHOLD) {
+    send_pending_adds (view);
+  }
+  g_array_append_val (priv->adds, vcard);
+  g_hash_table_insert (priv->ids, g_strdup (id),
+                       GUINT_TO_POINTER (1));
 }
 
-/**
- * e_data_book_view_get_mutex:
- * @book_view: an #EDataBookView
- *
- * Gets the internal mutex of @book_view.
- *
- * Return value: The #GMutex for @book_view.
- **/
-GMutex*
-e_data_book_view_get_mutex (EDataBookView *book_view)
+void
+e_data_book_view_notify_update (EDataBookView *book_view, EContact *contact)
 {
-	g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (book_view), NULL);
+  EDataBookViewPrivate *priv = book_view->priv;
+  gboolean currently_in_view, want_in_view;
+  const char *id;
+  char *vcard;
+
+  if (!priv->running)
+    return;
+
+  g_mutex_lock (priv->pending_mutex);
+
+  id = e_contact_get_const (contact, E_CONTACT_UID);
+
+  currently_in_view =
+    g_hash_table_lookup (priv->ids, id) != NULL;
+  want_in_view =
+    e_book_backend_sexp_match_contact (priv->card_sexp, contact);
+
+  if (want_in_view) {
+    vcard = e_vcard_to_string (E_VCARD (contact),
+                               EVC_FORMAT_VCARD_30);
+
+    if (currently_in_view)
+      notify_change (book_view, vcard);
+    else
+      notify_add (book_view, id, vcard);
+  } else {
+    if (currently_in_view)
+      notify_remove (book_view, g_strdup (id));
+    /* else nothing; we're removing a card that wasn't there */
+  }
 
-	return book_view->priv->mutex;
+  g_mutex_unlock (priv->pending_mutex);
 }
 
-/**
- * e_data_book_view_get_listener:
- * @book_view: an #EDataBookView
- *
- * Gets the CORBA listener that @book_view is dispatching
- * events to.
- *
- * Return value: The CORBA book view listener.
- **/
-GNOME_Evolution_Addressbook_BookViewListener
-e_data_book_view_get_listener (EDataBookView  *book_view)
+void
+e_data_book_view_notify_update_vcard (EDataBookView *book_view, char *vcard)
 {
-	g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (book_view), CORBA_OBJECT_NIL);
+  EDataBookViewPrivate *priv = book_view->priv;
+  gboolean currently_in_view, want_in_view;
+  const char *id;
+  EContact *contact;
+
+  if (!priv->running)
+    return;
+
+  g_mutex_lock (priv->pending_mutex);
+
+  contact = e_contact_new_from_vcard (vcard);
+  id = e_contact_get_const (contact, E_CONTACT_UID);
+  currently_in_view =
+    g_hash_table_lookup (priv->ids, id) != NULL;
+  want_in_view =
+    e_book_backend_sexp_match_contact (priv->card_sexp, contact);
+
+  if (want_in_view) {
+    if (currently_in_view)
+      notify_change (book_view, vcard);
+    else
+      notify_add (book_view, id, vcard);
+  } else {
+    if (currently_in_view)
+      notify_remove (book_view, g_strdup (id));
+    else
+      /* else nothing; we're removing a card that wasn't there */
+      g_free (vcard);
+  }
+  /* Do this last so that id is still valid when notify_ is called */
+  g_object_unref (contact);
 
-	return book_view->priv->listener;
+  g_mutex_unlock (priv->pending_mutex);
 }
 
-/**
- * e_data_book_view_set_thresholds:
- * @book_view: an #EDataBookView
- * @minimum_grouping_threshold: the minimum threshold
- * @maximum_grouping_threshold: the maximum threshold
- *
- * Sets the thresholds for grouping add events together
- * for efficiency reasons. The minimum threshold specifies
- * how many adds must be grouped (as long as there are
- * pending adds), and the maximum threshold specifies
- * the maximum number of adds that can be grouped.
- **/
 void
-e_data_book_view_set_thresholds (EDataBookView *book_view,
-				 int minimum_grouping_threshold,
-				 int maximum_grouping_threshold)
+e_data_book_view_notify_update_prefiltered_vcard (EDataBookView *book_view, const char *id, char *vcard)
 {
-	book_view->priv->threshold_min = minimum_grouping_threshold;
-	book_view->priv->threshold_max = maximum_grouping_threshold;
-}
+  EDataBookViewPrivate *priv = book_view->priv;
+  gboolean currently_in_view;
 
-/**
- * e_data_book_view_new:
- * @backend: an #EBookBackend to view
- * @listener: a CORBA listener to reveive notifications
- * @card_query: an s-expression representing the query
- * @card_sexp:
- * @max_results: the maximum number of results for the query
- *
- * Return value: A new #EDataBookView.
- **/
-EDataBookView *
-e_data_book_view_new (EBookBackend *backend,
-		      GNOME_Evolution_Addressbook_BookViewListener  listener,
-		      const char *card_query,
-		      EBookBackendSExp *card_sexp,
-		      int max_results)
-{
-	static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
-	static PortableServer_POA poa = NULL;
-	EDataBookView *book_view;
-
-	g_static_mutex_lock (&mutex);
-	if (poa == NULL)
-		poa = bonobo_poa_get_threaded (ORBIT_THREAD_HINT_PER_OBJECT, NULL);
-	g_static_mutex_unlock (&mutex);
+  if (!priv->running)
+    return;
 
-	book_view = g_object_new (E_TYPE_DATA_BOOK_VIEW, "poa", poa, NULL);
+  g_mutex_lock (priv->pending_mutex);
 
-	e_data_book_view_construct (book_view, backend, listener, card_query, card_sexp, max_results);
+  currently_in_view =
+    g_hash_table_lookup (priv->ids, id) != NULL;
 
-	return book_view;
-}
+  if (currently_in_view)
+    notify_change (book_view, vcard);
+  else
+    notify_add (book_view, id, vcard);
 
-/**
- * e_data_book_view_ref
- * @book_view: an #EBookView
- *
- * Increase the reference count of the book view. This is a function to aid
- * the transition from Bonobo to DBUS.
- */
-void
-e_data_book_view_ref (EDataBookView *book_view)
-{
-	bonobo_object_ref (book_view);
+  g_mutex_unlock (priv->pending_mutex);
 }
 
-/**
- * e_data_book_view_unref
- * @book_view: an #EBookView
- *
- * Decrease the reference count of the book view. This is a function to aid
- * the transition from Bonobo to DBUS.
- */
 void
-e_data_book_view_unref (EDataBookView *book_view)
+e_data_book_view_notify_remove (EDataBookView *book_view, const char *id)
 {
-	bonobo_object_unref (book_view);
-}
+  EDataBookViewPrivate *priv = E_DATA_BOOK_VIEW_GET_PRIVATE (book_view);
 
-static void
-e_data_book_view_dispose (GObject *object)
-{
-	EDataBookView *book_view = E_DATA_BOOK_VIEW (object);
+  if (!priv->running)
+    return;
 
-	d(printf ("disposing of EDataBookView\n"));
-	if (book_view->priv) {
-		bonobo_object_release_unref (book_view->priv->listener, NULL);
+  g_mutex_lock (priv->pending_mutex);
 
-		if (book_view->priv->adds._buffer)
-			CORBA_free (book_view->priv->adds._buffer);
-		if (book_view->priv->changes._buffer)
-			CORBA_free (book_view->priv->changes._buffer);
-		if (book_view->priv->removes._buffer)
-			CORBA_free (book_view->priv->removes._buffer);
+  if (g_hash_table_lookup (priv->ids, id))
+    notify_remove (book_view, g_strdup (id));
+  
+  g_mutex_unlock (priv->pending_mutex);
+}
 
-		g_free (book_view->priv->card_query);
-		g_object_unref (book_view->priv->card_sexp);
+void
+e_data_book_view_notify_complete (EDataBookView *book_view, EDataBookStatus status)
+{
+  EDataBookViewPrivate *priv = book_view->priv;
 
-		g_mutex_free (book_view->priv->pending_mutex);
+  if (!priv->running)
+    return;
 
-		g_mutex_free (book_view->priv->mutex);
+  g_mutex_lock (priv->pending_mutex);
 
-		g_hash_table_destroy (book_view->priv->ids);
+  send_pending_adds (book_view);
+  send_pending_changes (book_view);
+  send_pending_removes (book_view);
 
-		g_free (book_view->priv);
-		book_view->priv = NULL;
-	}
+  g_mutex_unlock (priv->pending_mutex);
+  
+  /* We're done now, so tell the backend to stop?  TODO: this is a bit different to
+     how the CORBA backend works... */
 
-	if (G_OBJECT_CLASS (e_data_book_view_parent_class)->dispose)
-		G_OBJECT_CLASS (e_data_book_view_parent_class)->dispose (object);
+  g_signal_emit (book_view, signals[COMPLETE], 0, status);
 }
 
-static void
-e_data_book_view_class_init (EDataBookViewClass *klass)
+void
+e_data_book_view_notify_status_message (EDataBookView *book_view, const char *message)
 {
-	GObjectClass *object_class = G_OBJECT_CLASS (klass);
-	POA_GNOME_Evolution_Addressbook_BookView__epv *epv;
-
-	e_data_book_view_parent_class = g_type_class_peek_parent (klass);
-
-	object_class->dispose = e_data_book_view_dispose;
+  EDataBookViewPrivate *priv = E_DATA_BOOK_VIEW_GET_PRIVATE (book_view);
 
-	epv = &klass->epv;
-
-	epv->start                = impl_GNOME_Evolution_Addressbook_BookView_start;
-	epv->stop                 = impl_GNOME_Evolution_Addressbook_BookView_stop;
-	epv->dispose              = impl_GNOME_Evolution_Addressbook_BookView_dispose;
+  if (!priv->running)
+    return;
 
+  g_signal_emit (book_view, signals[STATUS_MESSAGE], 0, message);
 }
 
 static void
-e_data_book_view_init (EDataBookView *book_view)
+reset_array (GArray *array)
 {
-	book_view->priv = g_new0 (EDataBookViewPrivate, 1);
+  gint i = 0;
+  gchar *tmp = NULL;
 
-	book_view->priv->pending_mutex = g_mutex_new();
-	book_view->priv->mutex = g_mutex_new();
+  /* Free stored strings */
+  for (i = 0; i < array->len; i++)
+  {
+    tmp = g_array_index (array, gchar *, i);
+    g_free (tmp);
+  }
 
-	book_view->priv->threshold_min = DEFAULT_INITIAL_THRESHOLD;
-	book_view->priv->threshold_max = DEFAULT_THRESHOLD_MAX;
-	book_view->priv->next_threshold = book_view->priv->threshold_min;
+  /* Force the array size to 0 */
+  g_array_set_size (array, 0);
+}
 
-	book_view->priv->ids = g_hash_table_new_full (g_str_hash, g_str_equal,
-						      g_free, NULL);
+void
+e_data_book_view_ref (EDataBookView *book_view)
+{
+  g_object_ref (book_view);
 }
 
-BONOBO_TYPE_FUNC_FULL (
-		       EDataBookView,
-		       GNOME_Evolution_Addressbook_BookView,
-		       BONOBO_TYPE_OBJECT,
-		       e_data_book_view);
+void
+e_data_book_view_unref (EDataBookView *book_view)
+{
+  g_object_unref (book_view);
+}

Modified: branches/eds-dbus/addressbook/libedata-book/e-data-book-view.h
==============================================================================
--- branches/eds-dbus/addressbook/libedata-book/e-data-book-view.h	(original)
+++ branches/eds-dbus/addressbook/libedata-book/e-data-book-view.h	Fri Sep 12 17:21:22 2008
@@ -1,23 +1,32 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
- * A wrapper object which exports the GNOME_Evolution_Addressbook_Book CORBA interface
- * and which maintains a request queue.
+ * Copyright (C) 2006 OpenedHand Ltd
  *
- * Author:
- *   Nat Friedman (nat ximian com)
+ * 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.
  *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * 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.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Author: Ross Burton <ross openedhand com>
  */
 
 #ifndef __E_DATA_BOOK_VIEW_H__
 #define __E_DATA_BOOK_VIEW_H__
 
-#include <bonobo/bonobo-object.h>
 #include <glib.h>
 #include <glib-object.h>
 #include <libebook/e-contact.h>
-#include <libedata-book/Evolution-DataServer-Addressbook.h>
-#include <libedata-book/e-data-book-types.h>
+#include "e-data-book-types.h"
+#include "e-book-backend.h"
+#include "e-book-backend-sexp.h"
 
 G_BEGIN_DECLS
 
@@ -31,22 +40,15 @@
 typedef struct _EDataBookViewPrivate EDataBookViewPrivate;
 
 struct _EDataBookView {
-	BonoboObject     parent_object;
-	EDataBookViewPrivate *priv;
+  GObject parent;
+  EDataBookViewPrivate *priv;
 };
 
 struct _EDataBookViewClass {
-	BonoboObjectClass parent_class;
-
-	POA_GNOME_Evolution_Addressbook_BookView__epv epv;
+  GObjectClass parent;
 };
 
-
-EDataBookView *e_data_book_view_new                  (EBookBackend                 *backend,
-						      GNOME_Evolution_Addressbook_BookViewListener  listener,
-						      const char                   *card_query,
-						      EBookBackendSExp             *card_sexp,
-						      int                           max_results);
+EDataBookView * e_data_book_view_new (EDataBook *book, const char *path, const char *card_query, EBookBackendSExp *card_sexp, int max_results);
 
 void              e_data_book_view_set_thresholds    (EDataBookView *book_view,
 						      int minimum_grouping_threshold,
@@ -56,10 +58,7 @@
 EBookBackendSExp* e_data_book_view_get_card_sexp     (EDataBookView                *book_view);
 int               e_data_book_view_get_max_results   (EDataBookView                *book_view);
 EBookBackend*     e_data_book_view_get_backend       (EDataBookView                *book_view);
-GNOME_Evolution_Addressbook_BookViewListener e_data_book_view_get_listener (EDataBookView  *book_view);
-GMutex*           e_data_book_view_get_mutex         (EDataBookView                *book_view);
-
-void         e_data_book_view_notify_update          (EDataBookView                *book_view,
+void              e_data_book_view_notify_update     (EDataBookView                *book_view,
 						      EContact                     *contact);
 
 void         e_data_book_view_notify_update_vcard    (EDataBookView                *book_view,
@@ -70,13 +69,14 @@
 
 void         e_data_book_view_notify_remove          (EDataBookView                *book_view,
 						      const char                   *id);
-void         e_data_book_view_notify_complete        (EDataBookView                *book_view,
-						      GNOME_Evolution_Addressbook_CallStatus);
+void         e_data_book_view_notify_complete        (EDataBookView                *book_view, EDataBookStatus status);
 void         e_data_book_view_notify_status_message  (EDataBookView                *book_view,
 						      const char                   *message);
+
 void         e_data_book_view_ref                    (EDataBookView                *book_view);
 void         e_data_book_view_unref                  (EDataBookView                *book_view);
 
+
 GType        e_data_book_view_get_type               (void);
 
 G_END_DECLS

Modified: branches/eds-dbus/addressbook/libedata-book/e-data-book.c
==============================================================================
--- branches/eds-dbus/addressbook/libedata-book/e-data-book.c	(original)
+++ branches/eds-dbus/addressbook/libedata-book/e-data-book.c	Fri Sep 12 17:21:22 2008
@@ -1,1016 +1,734 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
- * pas-book.c
+ * Copyright (C) 2006 OpenedHand Ltd
  *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * 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.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Author: Ross Burton <ross openedhand com>
  */
 
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <bonobo/bonobo-main.h>
-#include <bonobo/bonobo-arg.h>
-#include "libedataserver/e-list.h"
-#include <libebook/e-contact.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+#include <glib/gi18n.h>
+#include <glib-object.h>
+#include "e-data-book-enumtypes.h"
+#include "e-data-book-factory.h"
+#include "e-data-book.h"
 #include "e-data-book-view.h"
-#include "e-book-backend.h"
 #include "e-book-backend-sexp.h"
-#include "e-data-book.h"
+#include "opid.h"
 
-static BonoboObjectClass *e_data_book_parent_class;
-POA_GNOME_Evolution_Addressbook_Book__vepv e_data_book_vepv;
+extern DBusGConnection *connection;
 
-struct _EDataBookPrivate {
-	EBookBackend                               *backend;
-	GNOME_Evolution_Addressbook_BookListener  listener;
-	ESource                                    *source;
+/* 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);
+static void impl_AddressBook_Book_getContact(EDataBook *book, const char *IN_uid, DBusGMethodInvocation *context);
+static void impl_AddressBook_Book_getContactList(EDataBook *book, const char *query, DBusGMethodInvocation *context);
+static void impl_AddressBook_Book_authenticateUser(EDataBook *book, const char *IN_user, const char *IN_passwd, const char *IN_auth_method, DBusGMethodInvocation *context);
+static void impl_AddressBook_Book_addContact(EDataBook *book, const char *IN_vcard, DBusGMethodInvocation *context);
+static void impl_AddressBook_Book_modifyContact(EDataBook *book, const char *IN_vcard, DBusGMethodInvocation *context);
+static void impl_AddressBook_Book_modifyContacts(EDataBook *book, const char **IN_vcards, DBusGMethodInvocation *context);
+static void impl_AddressBook_Book_removeContacts(EDataBook *book, const char **IN_uids, DBusGMethodInvocation *context);
+static gboolean impl_AddressBook_Book_getStaticCapabilities(EDataBook *book, char **OUT_capabilities, GError **error);
+static void impl_AddressBook_Book_getSupportedFields(EDataBook *book, DBusGMethodInvocation *context);
+static void impl_AddressBook_Book_getRequiredFields(EDataBook *book, DBusGMethodInvocation *context);
+static void impl_AddressBook_Book_getSupportedAuthMethods(EDataBook *book, DBusGMethodInvocation *context);
+static void impl_AddressBook_Book_getBookView (EDataBook *book, const char *search, const guint max_results, DBusGMethodInvocation *context);
+static void impl_AddressBook_Book_getChanges(EDataBook *book, const char *IN_change_id, DBusGMethodInvocation *context);
+static gboolean impl_AddressBook_Book_cancelOperation(EDataBook *book, GError **error);
+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);
+
+enum {
+  WRITABLE,
+  CONNECTION,
+  AUTH_REQUIRED,
+  LAST_SIGNAL
 };
 
-static void
-impl_GNOME_Evolution_Addressbook_Book_open (PortableServer_Servant servant,
-					    const CORBA_long opid,
-					    const CORBA_boolean only_if_exists,
-					    CORBA_Environment *ev)
-{
-	EDataBook *book = E_DATA_BOOK (bonobo_object (servant));
+static guint signals[LAST_SIGNAL] = { 0 };
 
-	printf ("impl_GNOME_Evolution_Addressbook_Book_open (%p)\n", book);
+static GThreadPool *op_pool;
 
-	e_book_backend_open (e_data_book_get_backend (book), book, opid, only_if_exists);
+typedef enum {
+  OP_OPEN,
+  OP_AUTHENTICATE,
+  OP_ADD_CONTACT,
+  OP_GET_CONTACT,
+  OP_GET_CONTACTS,
+  OP_MODIFY_CONTACT,
+  OP_MODIFY_CONTACTS,
+  OP_REMOVE_CONTACTS,
+  OP_GET_CHANGES,
+} OperationID;
+
+typedef struct {
+  OperationID op;
+  guint32 id; /* operation id */
+  EDataBook *book; /* book */
+  union {
+    /* OP_OPEN */
+    gboolean only_if_exists;
+    /* OP_AUTHENTICATE */
+    struct {
+      char *username;
+      char *password;
+      char *method;
+    } auth;
+    /* OP_ADD_CONTACT */
+    /* OP_MODIFY_CONTACT */
+    char *vcard;
+    /* OP_GET_CONTACT */
+    char *uid;
+    /* OP_GET_CONTACTS */
+    char *query;
+    /* OP_MODIFY_CONTACT */
+    char **vcards;
+    /* OP_REMOVE_CONTACTS */
+    GList *ids;
+    /* OP_GET_CHANGES */
+    char *change_id;
+  };
+} OperationData;
+
+
+static void
+operation_thread (gpointer data, gpointer user_data)
+{
+  OperationData *op = data;
+  EBookBackend *backend;
+
+  backend = e_data_book_get_backend (op->book);
+  
+  switch (op->op) {
+  case OP_OPEN:
+    e_book_backend_open (backend, op->book, op->id, op->only_if_exists);
+    break;
+  case OP_AUTHENTICATE:
+    e_book_backend_authenticate_user (backend, op->book, op->id,
+                                      op->auth.username,
+                                      op->auth.password,
+                                      op->auth.method);
+    g_free (op->auth.username);
+    g_free (op->auth.password);
+    g_free (op->auth.method);
+    break;
+  case OP_ADD_CONTACT:
+    e_book_backend_create_contact (backend, op->book, op->id, op->vcard);
+    g_free (op->vcard);
+    break;
+  case OP_GET_CONTACT:
+    e_book_backend_get_contact (backend, op->book, op->id, op->uid);
+    g_free (op->uid);
+    break;
+  case OP_GET_CONTACTS:
+    e_book_backend_get_contact_list (backend, op->book, op->id, op->query);
+    g_free (op->query);
+    break;
+  case OP_MODIFY_CONTACT:
+    e_book_backend_modify_contact (backend, op->book, op->id, op->vcard);
+    g_free (op->vcard);
+    break;
+  case OP_MODIFY_CONTACTS:
+    /* C is weird at times, need to cast to const char** */
+    e_book_backend_modify_contacts (backend, op->book, op->id, (const char**)op->vcards);
+    g_strfreev (op->vcards);
+    break;
+  case OP_REMOVE_CONTACTS:
+    e_book_backend_remove_contacts (backend, op->book, op->id, op->ids);
+    g_list_foreach (op->ids, (GFunc)g_free, NULL);
+    g_list_free (op->ids);
+    break;
+  case OP_GET_CHANGES:
+    e_book_backend_get_changes (backend, op->book, op->id, op->change_id);
+    g_free (op->change_id);
+    break;
+  }
+  
+  g_object_unref (op->book);
+  g_slice_free (OperationData, op);
+}
+
+static OperationData *
+op_new (OperationID op, EDataBook *book, DBusGMethodInvocation *context)
+{
+  OperationData *data;
+
+  data = g_slice_new0 (OperationData);
+  data->op = op;
+  data->book = g_object_ref (book);
+  data->id = opid_store (context);
+
+  return data;
+}
+
+
+/* Create the EDataBook error quark */
+GQuark
+e_data_book_error_quark (void)
+{
+  static GQuark quark = 0;
+  if (G_UNLIKELY (quark == 0))
+    quark = g_quark_from_static_string ("e-data-book-error");
+  return quark;
 }
 
-static void
-impl_GNOME_Evolution_Addressbook_Book_remove (PortableServer_Servant servant,
-					      const CORBA_long opid,
-					      CORBA_Environment *ev)
-{
-	EDataBook *book = E_DATA_BOOK (bonobo_object (servant));
-
-	printf ("impl_GNOME_Evolution_Addressbook_Book_remove\n");
 
-	e_book_backend_remove (e_data_book_get_backend (book), book, opid);
-}
+/* Generate the GObject boilerplate */
+G_DEFINE_TYPE(EDataBook, e_data_book, G_TYPE_OBJECT)
 
 static void
-impl_GNOME_Evolution_Addressbook_Book_getContact (PortableServer_Servant servant,
-						  const CORBA_long opid,
-						  const CORBA_char *id,
-						  CORBA_Environment *ev)
+e_data_book_dispose (GObject *object)
 {
-	EDataBook *book = E_DATA_BOOK (bonobo_object (servant));
-
-	printf ("impl_GNOME_Evolution_Addressbook_Book_getContact\n");
-
-	e_book_backend_get_contact (e_data_book_get_backend (book), book, opid, id);
+  EDataBook *book = E_DATA_BOOK (object);
+  
+  if (book->backend) {
+    g_object_unref (book->backend);
+    book->backend = NULL;
+  }
+
+  if (book->source) {
+    g_object_unref (book->source);
+    book->source = NULL;
+  }
+  
+  G_OBJECT_CLASS (e_data_book_parent_class)->dispose (object);	
 }
 
 static void
-impl_GNOME_Evolution_Addressbook_Book_getContactList (PortableServer_Servant servant,
-						      const CORBA_long opid,
-						      const CORBA_char *query,
-						      CORBA_Environment *ev)
-{
-	EDataBook *book = E_DATA_BOOK (bonobo_object (servant));
-
-	printf ("impl_GNOME_Evolution_Addressbook_Book_getContactList\n");
-
-	e_book_backend_get_contact_list (e_data_book_get_backend (book), book, opid, query);
+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);
+
+  dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (e_data_book_class), &dbus_glib_e_data_book_object_info);
+  
+  dbus_g_error_domain_register (E_DATA_BOOK_ERROR, NULL, E_TYPE_DATA_BOOK_STATUS);
+
+  op_pool = g_thread_pool_new (operation_thread, NULL, 10, FALSE, NULL);
+  /* Kill threads which don't do anything for 10 seconds */
+  g_thread_pool_set_max_idle_time (10 * 1000);
 }
 
+/* Instance init */
 static void
-impl_GNOME_Evolution_Addressbook_Book_authenticateUser (PortableServer_Servant servant,
-							const CORBA_long opid,
-							const char* user,
-							const char* passwd,
-							const char* auth_method,
-							CORBA_Environment *ev)
+e_data_book_init (EDataBook *ebook)
 {
-	EDataBook *book = E_DATA_BOOK (bonobo_object (servant));
-
-	e_book_backend_authenticate_user (e_data_book_get_backend (book), book,
-					  opid, user, passwd, auth_method);
 }
 
-static void
-impl_GNOME_Evolution_Addressbook_Book_addContact (PortableServer_Servant servant,
-						  const CORBA_long opid,
-						  const CORBA_char *vcard,
-						  CORBA_Environment *ev)
+EDataBook *
+e_data_book_new (EBookBackend *backend, ESource *source, EDataBookClosedCallback closed_cb)
 {
-	EDataBook *book = E_DATA_BOOK (bonobo_object (servant));
-
-	e_book_backend_create_contact (e_data_book_get_backend (book), book, opid, vcard);
+  EDataBook *book;
+  book = g_object_new (E_TYPE_DATA_BOOK, NULL);
+  book->backend = g_object_ref (backend);
+  book->source = g_object_ref (source);
+  book->closed_cb = closed_cb;
+  return book;
 }
 
-static void
-impl_GNOME_Evolution_Addressbook_Book_removeContacts (PortableServer_Servant servant,
-						      const CORBA_long opid,
-						      const GNOME_Evolution_Addressbook_ContactIdList *ids,
-						      CORBA_Environment *ev)
+ESource*
+e_data_book_get_source (EDataBook *book)
 {
-	EDataBook *book = E_DATA_BOOK (bonobo_object (servant));
-	int i;
-	GList *id_list = NULL;
-
-	for (i = 0; i < ids->_length; i ++)
-		id_list = g_list_append (id_list, ids->_buffer[i]);
-
-	e_book_backend_remove_contacts (e_data_book_get_backend (book), book, opid, id_list);
+  g_return_val_if_fail (book != NULL, NULL);
 
-	g_list_free (id_list);
+  return book->source;
 }
 
-static void
-impl_GNOME_Evolution_Addressbook_Book_modifyContact (PortableServer_Servant servant,
-						     const CORBA_long opid,
-						     const CORBA_char *vcard,
-						     CORBA_Environment *ev)
+EBookBackend*
+e_data_book_get_backend (EDataBook *book)
 {
-	EDataBook *book = E_DATA_BOOK (bonobo_object (servant));
+  g_return_val_if_fail (book != NULL, NULL);
 
-	e_book_backend_modify_contact (e_data_book_get_backend (book), book, opid, vcard);
+  return book->backend;
 }
 
 static void
-impl_GNOME_Evolution_Addressbook_Book_getBookView (PortableServer_Servant servant,
-						   const CORBA_long opid,
-						   const GNOME_Evolution_Addressbook_BookViewListener listener,
-						   const CORBA_char *search,
-						   const GNOME_Evolution_Addressbook_stringlist* requested_fields,
-						   const CORBA_long max_results,
-						   CORBA_Environment *ev)
+impl_AddressBook_Book_open(EDataBook *book, gboolean only_if_exists, DBusGMethodInvocation *context)
 {
-	EDataBook *book = E_DATA_BOOK (bonobo_object (servant));
-	EBookBackend *backend = e_data_book_get_backend (book);
-	EBookBackendSExp *card_sexp;
-	EDataBookView *view;
-
-	g_warning ("impl_GNOME_Evolution_Addressbook_Book_getBookView (%s)\n", search);
-
-	/* we handle this entirely here, since it doesn't require any
-	   backend involvement now that we have e_data_book_view_start to
-	   actually kick off the search. */
-
-	card_sexp = e_book_backend_sexp_new (search);
-	if (!card_sexp) {
-		e_data_book_respond_get_book_view (book, opid, GNOME_Evolution_Addressbook_InvalidQuery, NULL);
-		return;
-	}
-
-	/* XXX still need to add requested_fields here */
-	view = e_data_book_view_new (backend, listener, search, card_sexp, max_results);
-
-	if (!view) {
-		g_object_unref (card_sexp);
-		e_data_book_respond_get_book_view (book, opid, GNOME_Evolution_Addressbook_OtherError, NULL);
-		return;
-	}
+  OperationData *op;
+  
+  op = op_new (OP_OPEN, book, context);
+  op->only_if_exists = only_if_exists;
+  g_thread_pool_push (op_pool, op, NULL);
+}
 
-	e_book_backend_add_book_view (backend, view);
+void
+e_data_book_respond_open (EDataBook *book, guint opid, EDataBookStatus status)
+{
+  DBusGMethodInvocation *context = opid_fetch (opid);
 
-	e_data_book_respond_get_book_view (book, opid, GNOME_Evolution_Addressbook_Success, view);
+  if (status != Success) {
+    dbus_g_method_return_error (context, g_error_new (E_DATA_BOOK_ERROR, status, _("Cannot open book")));
+  } else {
+    dbus_g_method_return (context);
+  }
 }
 
-
 static void
-impl_GNOME_Evolution_Addressbook_Book_getChanges (PortableServer_Servant servant,
-						  const CORBA_long opid,
-						  const CORBA_char *change_id,
-						  CORBA_Environment *ev)
+impl_AddressBook_Book_remove(EDataBook *book, DBusGMethodInvocation *context)
 {
-	EDataBook *book = E_DATA_BOOK (bonobo_object (servant));
-
-	e_book_backend_get_changes (e_data_book_get_backend (book), book, opid, change_id);
+  e_book_backend_remove (book->backend, book, opid_store (context));
 }
 
-static char *
-impl_GNOME_Evolution_Addressbook_Book_getStaticCapabilities (PortableServer_Servant servant,
-							     CORBA_Environment *ev)
+void
+e_data_book_respond_remove (EDataBook *book, guint opid, EDataBookStatus status)
 {
-	EDataBook *book = E_DATA_BOOK (bonobo_object (servant));
-	char *temp;
-	char *ret_val;
+  DBusGMethodInvocation *context = opid_fetch (opid);
 
-	temp = e_book_backend_get_static_capabilities (book->priv->backend);
-	ret_val = CORBA_string_dup(temp);
-	g_free(temp);
-	return ret_val;
+  if (status != Success) {
+    dbus_g_method_return_error (context, g_error_new (E_DATA_BOOK_ERROR, status, _("Cannot remove book")));
+  } else {
+    dbus_g_method_return (context);
+  }
 }
 
-
 static void
-impl_GNOME_Evolution_Addressbook_Book_getRequiredFields (PortableServer_Servant servant,
-							  const CORBA_long opid,
-							  CORBA_Environment *ev)
-
+impl_AddressBook_Book_getContact (EDataBook *book, const char *IN_uid, DBusGMethodInvocation *context)
 {
+  OperationData *op;
 
-	EDataBook *book = E_DATA_BOOK (bonobo_object (servant));
-
-	e_book_backend_get_required_fields (e_data_book_get_backend (book), book, opid);
-
+  if (IN_uid == NULL) {
+    dbus_g_method_return_error (context, g_error_new (E_DATA_BOOK_ERROR, ContactNotFound, _("Cannot get contact")));
+    return;
+  }
+  
+  op = op_new (OP_GET_CONTACT, book, context);
+  op->uid = g_strdup (IN_uid);
+  g_thread_pool_push (op_pool, op, NULL);
 }
 
-static void
-impl_GNOME_Evolution_Addressbook_Book_getSupportedFields (PortableServer_Servant servant,
-							  const CORBA_long opid,
-							  CORBA_Environment *ev)
+void
+e_data_book_respond_get_contact (EDataBook *book, guint32 opid, EDataBookStatus status, char *vcard)
 {
-	EDataBook *book = E_DATA_BOOK (bonobo_object (servant));
+  DBusGMethodInvocation *context = opid_fetch (opid);
 
-	e_book_backend_get_supported_fields (e_data_book_get_backend (book), book, opid);
+  if (status != Success) {
+    dbus_g_method_return_error (context, g_error_new (E_DATA_BOOK_ERROR, status, _("Cannot get contact")));
+  } else {
+    dbus_g_method_return (context, vcard);
+  }
 }
 
 static void
-impl_GNOME_Evolution_Addressbook_Book_getSupportedAuthMethods (PortableServer_Servant servant,
-							       const CORBA_long opid,
-							       CORBA_Environment *ev)
+impl_AddressBook_Book_getContactList (EDataBook *book, const char *query, DBusGMethodInvocation *context)
 {
-	EDataBook *book = E_DATA_BOOK (bonobo_object (servant));
+  OperationData *op;
 
-	e_book_backend_get_supported_auth_methods (e_data_book_get_backend (book), book, opid);
-}
-
-static GNOME_Evolution_Addressbook_CallStatus
-impl_GNOME_Evolution_Addressbook_Book_cancelOperation (PortableServer_Servant servant,
-						       CORBA_Environment *ev)
-{
-	EDataBook *book = E_DATA_BOOK (bonobo_object (servant));
+  if (query == NULL || query[0] == '\0') {
+    dbus_g_method_return_error (context, g_error_new (E_DATA_BOOK_ERROR, InvalidQuery, _("Empty query")));
+    return;
+  }
 
-	return e_book_backend_cancel_operation (e_data_book_get_backend (book), book);
+  op = op_new (OP_GET_CONTACTS, book, context);
+  op->query = g_strdup (query);
+  g_thread_pool_push (op_pool, op, NULL);
 }
 
-
-/**
- * e_data_book_get_backend:
- * @book: an #EDataBook
- *
- * Gets the #EBookBackend being used to store data for @book.
- *
- * Return value: The #EBookBackend being used.
- **/
-EBookBackend *
-e_data_book_get_backend (EDataBook *book)
+void
+e_data_book_respond_get_contact_list (EDataBook *book, guint32 opid, EDataBookStatus status, GList *cards)
 {
-	g_return_val_if_fail (book && E_IS_DATA_BOOK (book), NULL);
-
-	return book->priv->backend;
+  return_status_and_list (opid, status, cards, TRUE);
 }
 
-/**
- * e_data_book_get_listener:
- * @book: an #EDataBook
- *
- * Gets the CORBA listener associated with @book.
- *
- * Return value: A #GNOME_Evolution_Addressbook_BookListener.
- **/
-GNOME_Evolution_Addressbook_BookListener
-e_data_book_get_listener (EDataBook *book)
+static void
+impl_AddressBook_Book_authenticateUser(EDataBook *book, const char *IN_user, const char *IN_passwd, const char *IN_auth_method, DBusGMethodInvocation *context)
 {
-	g_return_val_if_fail (book && E_IS_DATA_BOOK (book), CORBA_OBJECT_NIL);
-
-	return book->priv->listener;
-}
+  OperationData *op;
 
-/**
- * e_data_book_get_source:
- * @book: an #EDataBook
- *
- * Gets the #ESource associated with @book.
- *
- * Return value: An #ESource.
- **/
-ESource *
-e_data_book_get_source (EDataBook *book)
-{
-	return book->priv->source;
+  op = op_new (OP_AUTHENTICATE, book, context);
+  op->auth.username = g_strdup (IN_user);
+  op->auth.password = g_strdup (IN_passwd);
+  op->auth.method = g_strdup (IN_auth_method);
+  g_thread_pool_push (op_pool, op, NULL);
 }
 
-/**
- * e_data_book_respond_open:
- * @book: an #EDataBook
- * @opid: the operation ID that generated the response
- * @status: the outcome of the operation
- *
- * Respond to an 'open' request specified by @opid on @book,
- * indicating @status as the outcome.
- **/
 void
-e_data_book_respond_open (EDataBook                              *book,
-			  guint32                                 opid,
-			  GNOME_Evolution_Addressbook_CallStatus  status)
+e_data_book_respond_authenticate_user (EDataBook *book, guint32 opid, EDataBookStatus status)
 {
-	CORBA_Environment ev;
-
-	CORBA_exception_init (&ev);
-	GNOME_Evolution_Addressbook_BookListener_notifyBookOpened (book->priv->listener, opid, status, &ev);
+  DBusGMethodInvocation *context = opid_fetch (opid);
 
-	if (ev._major != CORBA_NO_EXCEPTION) {
-		g_warning ("e_data_book_respond_open: Exception "
-			   "responding to BookListener!\n");
-	}
-
-	CORBA_exception_free (&ev);
+  if (status != Success) {
+    dbus_g_method_return_error (context, g_error_new (E_DATA_BOOK_ERROR, status, _("Cannot authenticate user")));
+  } else {
+    dbus_g_method_return (context);
+  }
 }
 
-/**
- * e_data_book_respond_remove:
- * @book: an #EDataBook
- * @opid: the operation ID that generated the response
- * @status: the outcome of the operation
- *
- * Respond to a 'remove' request to remove all of @book's data,
- * specified by @opid, indicating @status as the outcome.
- **/
-void
-e_data_book_respond_remove (EDataBook                           *book,
-			    guint32                              opid,
-			    GNOME_Evolution_Addressbook_CallStatus  status)
+static void
+impl_AddressBook_Book_addContact (EDataBook *book, const char *IN_vcard, DBusGMethodInvocation *context)
 {
-	CORBA_Environment ev;
-
-	CORBA_exception_init (&ev);
-	GNOME_Evolution_Addressbook_BookListener_notifyBookRemoved (book->priv->listener, opid, status, &ev);
+  OperationData *op;
 
-	if (ev._major != CORBA_NO_EXCEPTION) {
-		g_warning ("e_data_book_respond_remove: Exception "
-			   "responding to BookListener!\n");
-	}
+  if (IN_vcard == NULL || IN_vcard[0] == '\0') {
+    dbus_g_method_return_error (context, g_error_new (E_DATA_BOOK_ERROR, InvalidQuery, _("Cannot add contact")));
+    return;
+  }
 
-	CORBA_exception_free (&ev);
+  op = op_new (OP_ADD_CONTACT, book, context);
+  op->vcard = g_strdup (IN_vcard);
+  g_thread_pool_push (op_pool, op, NULL);
 }
 
-/**
- * e_data_book_respond_create:
- * @book: an #EDataBook
- * @opid: the operation ID that generated the response
- * @status: the outcome of the operation
- * @contact: the contact created, or %NULL
- *
- * Respond to a 'create' request specified by @opid on @book,
- * indicating @status as the outcome.
- **/
-void
-e_data_book_respond_create (EDataBook                              *book,
-			    guint32                                 opid,
-			    GNOME_Evolution_Addressbook_CallStatus  status,
-			    EContact                               *contact)
-{
-	CORBA_Environment ev;
-
-	if (status == GNOME_Evolution_Addressbook_Success) {
-		e_book_backend_notify_update (book->priv->backend, contact);
-		e_book_backend_notify_complete (book->priv->backend);
-	}
-
-	CORBA_exception_init (&ev);
-
-	GNOME_Evolution_Addressbook_BookListener_notifyContactCreated (
-		book->priv->listener, opid, status,
-		status == GNOME_Evolution_Addressbook_Success ? e_contact_get_const (contact, E_CONTACT_UID) : "",
-		&ev);
-
-	if (ev._major != CORBA_NO_EXCEPTION) {
-		g_warning ("e_data_book_respond_create: Exception "
-			   "responding to BookListener!\n");
-	}
-
-	CORBA_exception_free (&ev);
-}
-
-/**
- * e_data_book_respond_remove_contacts:
- * @book: an #EDataBook
- * @opid: the operation ID that generated the response
- * @status: the outcome of the operation
- * @ids: a list of contact IDs removed
- *
- * Respond to a 'remove contacts' request specified by @opid on @book,
- * indicating @status as the outcome.
- **/
-void
-e_data_book_respond_remove_contacts (EDataBook                              *book,
-				     guint32                                 opid,
-				     GNOME_Evolution_Addressbook_CallStatus  status,
-				     GList                                  *ids)
-{
-	CORBA_Environment ev;
-	GList *i;
-
-	CORBA_exception_init (&ev);
-
-	if (ids) {
-		for (i = ids; i; i = i->next)
-			e_book_backend_notify_remove (book->priv->backend, i->data);
-		e_book_backend_notify_complete (book->priv->backend);
-	}
-
-	GNOME_Evolution_Addressbook_BookListener_notifyContactsRemoved (
-		book->priv->listener, opid, status, &ev);
-
-	if (ev._major != CORBA_NO_EXCEPTION) {
-		g_warning ("e_data_book_respond_remove: Exception "
-			   "responding to BookListener!\n");
-	}
-
-	CORBA_exception_free (&ev);
-}
-
-/**
- * e_data_book_respond_modify:
- * @book: an #EDataBook
- * @opid: the operation ID that generated the response
- * @status: the outcome of the operation
- * @contact: the modified #EContact
- *
- * Respond to a 'modify' request specified by @opid on @book,
- * indicating @status as the outcome.
- **/
 void
-e_data_book_respond_modify (EDataBook                              *book,
-			    guint32                                 opid,
-			    GNOME_Evolution_Addressbook_CallStatus  status,
-			    EContact                               *contact)
+e_data_book_respond_create (EDataBook *book, guint32 opid, EDataBookStatus status, EContact *contact)
 {
-	CORBA_Environment ev;
-
-	if (status == GNOME_Evolution_Addressbook_Success) {
-		e_book_backend_notify_update (book->priv->backend, contact);
-		e_book_backend_notify_complete (book->priv->backend);
-	}
-
-	CORBA_exception_init (&ev);
-
-	GNOME_Evolution_Addressbook_BookListener_notifyContactModified (
-		book->priv->listener, opid, status, &ev);
+  DBusGMethodInvocation *context = opid_fetch (opid);
 
-	if (ev._major != CORBA_NO_EXCEPTION) {
-		g_warning ("e_data_book_respond_modify: Exception "
-			   "responding to BookListener!\n");
-	}
+  if (status != Success) {
+    dbus_g_method_return_error (context, g_error_new (E_DATA_BOOK_ERROR, status, _("Cannot add contact")));
+  } else {
+    e_book_backend_notify_update (e_data_book_get_backend (book), contact);
+    e_book_backend_notify_complete (e_data_book_get_backend (book));
 
-	CORBA_exception_free (&ev);
+    dbus_g_method_return (context, e_contact_get_const (contact, E_CONTACT_UID));
+  }
 }
 
-/**
- * e_data_book_respond_authenticate_user:
- * @book: an #EDataBook
- * @opid: the operation ID that generated the response
- * @status: the outcome of the operation
- *
- * Respond to an 'authenticate' request specified by @opid on @book,
- * indicating @status as the outcome.
- **/
-void
-e_data_book_respond_authenticate_user (EDataBook                              *book,
-				       guint32                                 opid,
-				       GNOME_Evolution_Addressbook_CallStatus  status)
+static void
+impl_AddressBook_Book_modifyContact (EDataBook *book, const char *IN_vcard, DBusGMethodInvocation *context)
 {
-	CORBA_Environment ev;
-
-	CORBA_exception_init (&ev);
-
-	GNOME_Evolution_Addressbook_BookListener_notifyAuthenticationResult (
-		book->priv->listener, opid, status, &ev);
+  OperationData *op;
 
-	if (ev._major != CORBA_NO_EXCEPTION) {
-		g_warning ("e_data_book_respond_authenticate_user: Exception "
-			   "responding to BookListener!\n");
-	}
+  if (IN_vcard == NULL) {
+    dbus_g_method_return_error (context, g_error_new (E_DATA_BOOK_ERROR, InvalidQuery, _("Cannot modify contact")));
+    return;
+  }
 
-	CORBA_exception_free (&ev);
+  op = op_new (OP_MODIFY_CONTACT, book, context);
+  op->vcard = g_strdup (IN_vcard);
+  g_thread_pool_push (op_pool, op, NULL);
 }
 
-/**
- * e_data_book_respond_get_required_fields:
- * @book: an #EDataBook
- * @opid: the operation ID that generated the response
- * @status: the outcome of the operation
- * @fields: a list of required field names
- *
- * Respond to a 'get required fields' request specified by @opid on @book,
- * indicating @status as the outcome.
- **/
 void
-e_data_book_respond_get_required_fields (EDataBook                              *book,
-					  guint32                                 opid,
-					  GNOME_Evolution_Addressbook_CallStatus  status,
-					  GList                                  *fields)
+e_data_book_respond_modify (EDataBook *book, guint32 opid, EDataBookStatus status, EContact *contact)
 {
+  DBusGMethodInvocation *context = opid_fetch (opid);
 
-	CORBA_Environment ev;
-	GNOME_Evolution_Addressbook_stringlist stringlist;
-	int num_fields;
-	int i;
-	GList *iter;
-
-	CORBA_exception_init (&ev);
-
-	num_fields = g_list_length (fields);
+  if (status != Success) {
+    dbus_g_method_return_error (context, g_error_new (E_DATA_BOOK_ERROR, status, _("Cannot modify contact")));
+  } else {
+    e_book_backend_notify_update (e_data_book_get_backend (book), contact);
+    e_book_backend_notify_complete (e_data_book_get_backend (book));
 
-	stringlist._buffer = CORBA_sequence_CORBA_string_allocbuf (num_fields);
-	stringlist._maximum = num_fields;
-	stringlist._length = num_fields;
-
-	for (i = 0, iter = fields; iter; iter = iter->next, i ++) {
-		stringlist._buffer[i] = CORBA_string_dup ((char*)iter->data);
-	}
-
-	printf ("calling GNOME_Evolution_Addressbook_BookListener_notifyRequiredFields\n");
+    dbus_g_method_return (context);
+  }
+}
 
-	GNOME_Evolution_Addressbook_BookListener_notifyRequiredFields (
-			book->priv->listener, opid, status,
-			&stringlist,
-			&ev);
+static void
+impl_AddressBook_Book_modifyContacts(EDataBook *book, const char **IN_vcards, DBusGMethodInvocation *context)
+{
+  OperationData *op;
 
-	CORBA_exception_free (&ev);
+  if (IN_vcards == NULL || IN_vcards[0] == NULL) {
+    dbus_g_method_return_error (context, g_error_new (E_DATA_BOOK_ERROR, InvalidQuery, _("Cannot modify contacts")));
+    return;
+  }
 
-	CORBA_free(stringlist._buffer);
+  op = op_new (OP_MODIFY_CONTACTS, book, context);
+  op->vcards = g_strdupv ((char**)IN_vcards);
+  g_thread_pool_push (op_pool, op, NULL);
 }
 
-/**
- * e_data_book_respond_get_supported_fields:
- * @book: an #EDataBook
- * @opid: the operation ID that generated the response
- * @status: the outcome of the operation
- * @fields: a list of supported field names
- *
- * Respond to a 'get supported fields' request specified by @opid on @book,
- * indicating @status as the outcome.
- **/
 void
-e_data_book_respond_get_supported_fields (EDataBook                              *book,
-					  guint32                                 opid,
-					  GNOME_Evolution_Addressbook_CallStatus  status,
-					  GList                                  *fields)
+e_data_book_respond_modify_contacts (EDataBook *book, guint32 opid, EDataBookStatus status, GList *contacts)
 {
-	CORBA_Environment ev;
-	GNOME_Evolution_Addressbook_stringlist stringlist;
-	int num_fields;
-	int i;
-	GList *iter;
-
-	CORBA_exception_init (&ev);
-
-	num_fields = g_list_length (fields);
+  DBusGMethodInvocation *context = opid_fetch (opid);
 
-	stringlist._buffer = CORBA_sequence_CORBA_string_allocbuf (num_fields);
-	stringlist._maximum = num_fields;
-	stringlist._length = num_fields;
+  if (status != Success) {
+    dbus_g_method_return_error (context, g_error_new (E_DATA_BOOK_ERROR, status, _("Cannot modify contacts")));
+  } else {
+    for (; contacts; contacts = contacts->next) {
+      e_book_backend_notify_update (e_data_book_get_backend (book), contacts->data);
+    }
+    e_book_backend_notify_complete (e_data_book_get_backend (book));
 
-	for (i = 0, iter = fields; iter; iter = iter->next, i ++) {
-		stringlist._buffer[i] = CORBA_string_dup ((char*)iter->data);
-	}
-
-	printf ("calling GNOME_Evolution_Addressbook_BookListener_notifySupportedFields\n");
+    dbus_g_method_return (context);
+  }
+}
 
-	GNOME_Evolution_Addressbook_BookListener_notifySupportedFields (
-			book->priv->listener, opid, status,
-			&stringlist,
-			&ev);
+static void
+impl_AddressBook_Book_removeContacts(EDataBook *book, const char **IN_uids, DBusGMethodInvocation *context)
+{
+  OperationData *op;
 
-	CORBA_exception_free (&ev);
+  /* Allow an empty array to be removed */
+  if (IN_uids == NULL) {
+    dbus_g_method_return (context);
+    return;
+  }
 
-	CORBA_free(stringlist._buffer);
+  op = op_new (OP_REMOVE_CONTACTS, book, context);
+  
+  for (; *IN_uids; IN_uids++) {
+    op->ids = g_list_prepend (op->ids, g_strdup (*IN_uids));
+  }
+  
+  g_thread_pool_push (op_pool, op, NULL);
 }
 
-/**
- * e_data_book_respond_get_supported_auth_methods:
- * @book: an #EDataBook
- * @opid: the operation ID that generated the response
- * @status: the outcome of the operation
- * @auth_methods: a list of names for supported auth methods
- *
- * Respond to a 'get supported auth methods' request specified by @opid on @book,
- * indicating @status as the outcome.
- **/
 void
-e_data_book_respond_get_supported_auth_methods (EDataBook                              *book,
-						guint32                                 opid,
-						GNOME_Evolution_Addressbook_CallStatus  status,
-						GList                                  *auth_methods)
+e_data_book_respond_remove_contacts (EDataBook *book, guint32 opid, EDataBookStatus status, GList *ids)
 {
-	CORBA_Environment ev;
-	GNOME_Evolution_Addressbook_stringlist stringlist;
-	int num_auth_methods;
-	GList *iter;
-	int i;
-
-	CORBA_exception_init (&ev);
+  DBusGMethodInvocation *context = opid_fetch (opid);
 
-	num_auth_methods = g_list_length (auth_methods);
+  if (status != Success) {
+    dbus_g_method_return_error (context, g_error_new (E_DATA_BOOK_ERROR, status, _("Cannot remove contacts")));
+  } else {
+    GList *i;
+    
+    for (i = ids; i; i = i->next)
+      e_book_backend_notify_remove (e_data_book_get_backend (book), i->data);
+    e_book_backend_notify_complete (e_data_book_get_backend (book));
 
-	stringlist._buffer = CORBA_sequence_CORBA_string_allocbuf (num_auth_methods);
-	stringlist._maximum = num_auth_methods;
-	stringlist._length = num_auth_methods;
-
-	for (i = 0, iter = auth_methods; iter; iter = iter->next, i ++) {
-		stringlist._buffer[i] = CORBA_string_dup ((char*)iter->data);
-	}
-
-	GNOME_Evolution_Addressbook_BookListener_notifySupportedAuthMethods (
-			book->priv->listener, opid, status,
-			&stringlist,
-			&ev);
-
-	CORBA_exception_free (&ev);
+    dbus_g_method_return (context);
+  }
+}
 
-	CORBA_free(stringlist._buffer);
+static gboolean
+impl_AddressBook_Book_getStaticCapabilities(EDataBook *book, char **OUT_capabilities, GError **error)
+{
+  *OUT_capabilities = e_book_backend_get_static_capabilities (e_data_book_get_backend (book));
+  return TRUE;
 }
 
 static void
-view_destroy(gpointer data, GObject *where_object_was)
+impl_AddressBook_Book_getSupportedFields(EDataBook *book, DBusGMethodInvocation *context)
 {
-	EDataBook           *book = (EDataBook *)data;
-	e_book_backend_remove_book_view (book->priv->backend, (EDataBookView*)where_object_was);
+  e_book_backend_get_supported_fields (e_data_book_get_backend (book), book, opid_store (context));
 }
 
-/**
- * e_data_book_respond_get_book_view:
- * @book: an #EDataBook
- * @opid: the operation ID that generated the response
- * @status: the outcome of the operation
- * @book_view: the #EDataBookView created
- *
- * Respond to a 'get book view' request specified by @opid on @book,
- * indicating @status as the outcome.
- **/
 void
-e_data_book_respond_get_book_view (EDataBook                              *book,
-				   guint32                                 opid,
-				   GNOME_Evolution_Addressbook_CallStatus  status,
-				   EDataBookView                          *book_view)
+e_data_book_respond_get_supported_fields (EDataBook *book, guint32 opid, EDataBookStatus status, GList *fields)
 {
-	CORBA_Environment ev;
-	CORBA_Object      object = CORBA_OBJECT_NIL;
-
-	printf ("e_data_book_respond_get_book_view\n");
-
-	CORBA_exception_init (&ev);
-
-	if (book_view) {
-		object = bonobo_object_corba_objref(BONOBO_OBJECT(book_view));
-
-		g_object_weak_ref (G_OBJECT (book_view), view_destroy, book);
-	}
-
-	GNOME_Evolution_Addressbook_BookListener_notifyViewRequested (
-		book->priv->listener, opid, status, object, &ev);
-
-	if (ev._major != CORBA_NO_EXCEPTION) {
-		g_warning ("e_data_book_respond_get_book_view: Exception "
-			   "responding to BookListener!\n");
-	}
-
-	CORBA_exception_free (&ev);
+  return_status_and_list (opid, status, fields, FALSE);
 }
 
-/**
- * e_data_book_respond_get_contact:
- * @book: an #EDataBook
- * @opid: the operation ID that generated the response
- * @status: the outcome of the operation
- * @vcard: the found VCard, or %NULL
- *
- * Respond to a 'get contact' request specified by @opid on @book,
- * indicating @status as the outcome.
- **/
-void
-e_data_book_respond_get_contact (EDataBook                              *book,
-				 guint32                                 opid,
-				 GNOME_Evolution_Addressbook_CallStatus  status,
-				 char                                   *vcard)
+static void
+impl_AddressBook_Book_getRequiredFields(EDataBook *book, DBusGMethodInvocation *context)
 {
-	CORBA_Environment ev;
-
-	CORBA_exception_init (&ev);
-
-	GNOME_Evolution_Addressbook_BookListener_notifyContactRequested (book->priv->listener,
-									 opid,
-									 status,
-									 vcard,
-									 &ev);
-
-	if (ev._major != CORBA_NO_EXCEPTION)
-		g_message ("could not notify listener of get-contact response");
-
-	CORBA_exception_free (&ev);
+  e_book_backend_get_required_fields (e_data_book_get_backend (book), book, opid_store (context));
 }
 
-/**
- * e_data_book_respond_get_contact_list:
- * @book: an #EDataBook
- * @opid: the operation ID that generated the response
- * @status: the outcome of the operation
- * @card_list: a list of VCard strings
- *
- * Respond to a 'get contact list' request specified by @opid on @book,
- * indicating @status as the outcome.
- **/
 void
-e_data_book_respond_get_contact_list (EDataBook                              *book,
-				      guint32                                 opid,
-				      GNOME_Evolution_Addressbook_CallStatus  status,
-				      GList                                  *card_list)
+e_data_book_respond_get_required_fields (EDataBook *book, guint32 opid, EDataBookStatus status, GList *fields)
 {
-	CORBA_Environment ev;
-	GNOME_Evolution_Addressbook_stringlist stringlist;
-	int num_cards;
-	int i;
-	GList *l;
-
-	CORBA_exception_init (&ev);
-
-	num_cards = g_list_length (card_list);
-
-	stringlist._buffer = CORBA_sequence_CORBA_string_allocbuf (num_cards);
-	stringlist._maximum = num_cards;
-	stringlist._length = num_cards;
-
-	for (i = 0, l = card_list; l; l = l->next, i ++)
-		stringlist._buffer[i] = CORBA_string_dup (l->data);
-
-	g_list_foreach (card_list, (GFunc)g_free, NULL);
-	g_list_free (card_list);
-
-
-	GNOME_Evolution_Addressbook_BookListener_notifyContactListRequested (book->priv->listener,
-									     opid,
-									     status,
-									     &stringlist,
-									     &ev);
-
-	if (ev._major != CORBA_NO_EXCEPTION)
-		g_message ("could not notify listener of get-contact-list response");
-
-	CORBA_exception_free (&ev);
-
-	CORBA_free(stringlist._buffer);
+  return_status_and_list (opid, status, fields, FALSE);
 }
 
-/**
- * e_data_book_respond_get_changes:
- * @book: an #EDataBook
- * @opid: the operation ID that generated the response
- * @status: the outcome of the operation
- * @changes: a list of GNOME_Evolution_Addressbook_BookChangeItem items
- *
- * Respond to a 'get changes' request specified by @opid on @book,
- * indicating @status as the outcome.
- **/
-void
-e_data_book_respond_get_changes (EDataBook                              *book,
-				 guint32                                 opid,
-				 GNOME_Evolution_Addressbook_CallStatus  status,
-				 GList                                  *changes)
+static void
+impl_AddressBook_Book_getSupportedAuthMethods(EDataBook *book, DBusGMethodInvocation *context)
 {
-	CORBA_Environment ev;
-	GNOME_Evolution_Addressbook_BookChangeList changelist;
-	int num_changes;
-	int i;
-	GList *l;
-
-	CORBA_exception_init (&ev);
-
-	num_changes = g_list_length (changes);
-
-	changelist._buffer = CORBA_sequence_GNOME_Evolution_Addressbook_BookChangeItem_allocbuf (num_changes);
-	changelist._maximum = num_changes;
-	changelist._length = num_changes;
-
-	for (i = 0, l = changes; l; l = l->next, i ++) {
-		GNOME_Evolution_Addressbook_BookChangeItem *change = (GNOME_Evolution_Addressbook_BookChangeItem*)l->data;
-		changelist._buffer[i] = *change;
-		changelist._buffer[i].vcard = CORBA_string_dup (change->vcard);
-	}
-
-	g_list_foreach (changes, (GFunc)CORBA_free, NULL);
-	g_list_free (changes);
-
-	GNOME_Evolution_Addressbook_BookListener_notifyChangesRequested (book->priv->listener,
-									 opid,
-									 status,
-									 &changelist,
-									 &ev);
-
-	if (ev._major != CORBA_NO_EXCEPTION)
-		g_message ("could not notify listener of get-changes response");
-
-	CORBA_exception_free (&ev);
-
-	CORBA_free(changelist._buffer);
+  e_book_backend_get_supported_auth_methods (e_data_book_get_backend (book), book, opid_store (context));
 }
 
-/**
- * e_data_book_report_writable:
- * @book: an #EDataBook
- * @writable: %TRUE if @book is writeable, %FALSE otherwise
- *
- * Notify listeners that @book's writeable status has changed
- * to @writable.
- **/
 void
-e_data_book_report_writable (EDataBook                           *book,
-			     gboolean                           writable)
+e_data_book_respond_get_supported_auth_methods (EDataBook *book, guint32 opid, EDataBookStatus status, GList *auth_methods)
 {
-	CORBA_Environment ev;
-
-	CORBA_exception_init (&ev);
-
-	GNOME_Evolution_Addressbook_BookListener_notifyWritable (
-		book->priv->listener, (CORBA_boolean) writable, &ev);
-
-	if (ev._major != CORBA_NO_EXCEPTION) {
-		g_warning ("e_data_book_report_writable: Exception "
-			   "responding to BookListener!\n");
-	}
-
-	CORBA_exception_free (&ev);
+  return_status_and_list (opid, status, auth_methods, FALSE);
 }
 
-/**
- * e_data_book_report_connection_status:
- * @book: an #EDataBook
- * @is_online: %TRUE if the book is connected, %FALSE otherwise
- *
- * Notify listeners that @book's online status has changed
- * to @is_online.
- **/
-void
-e_data_book_report_connection_status (EDataBook   *book,
-				      gboolean    is_online)
+static char*
+construct_bookview_path (void)
 {
-	CORBA_Environment ev;
-
-	CORBA_exception_init (&ev);
-
-	GNOME_Evolution_Addressbook_BookListener_notifyConnectionStatus (
-		book->priv->listener, (CORBA_boolean) is_online, &ev);
-
-	if (ev._major != CORBA_NO_EXCEPTION) {
-		g_warning ("e_data_book_report_connection_status: Exception "
-			   "responding to BookListener!\n");
-	}
-
-	CORBA_exception_free (&ev);
+  static volatile guint counter = 1;
 
+  return g_strdup_printf ("/org/gnome/evolution/dataserver/addressbook/BookView/%d/%d",
+                          getpid (),
+                          g_atomic_int_exchange_and_add ((int*)&counter, 1));
 }
 
-/**
- * e_data_book_report_connection_status:
- * @book: an #EDataBook
- *
- * Notify listeners that @book requires authentication.
- **/
-void
-e_data_book_report_auth_required (EDataBook *book)
+static void
+impl_AddressBook_Book_getBookView (EDataBook *book, const char *search, const guint max_results, DBusGMethodInvocation *context)
 {
+  EBookBackend *backend = e_data_book_get_backend (book);
+  EBookBackendSExp *card_sexp;
+  EDataBookView *book_view;
+  char *path;
 
-	CORBA_Environment ev;
-
-	CORBA_exception_init (&ev);
-
-	GNOME_Evolution_Addressbook_BookListener_notifyAuthRequired (
-			 book->priv->listener,  &ev);
+  card_sexp = e_book_backend_sexp_new (search);
+  if (!card_sexp) {
+    dbus_g_method_return_error (context, g_error_new (E_DATA_BOOK_ERROR, InvalidQuery, _("Invalid query")));
+    return;
+  }
 
-	if (ev._major != CORBA_NO_EXCEPTION) {
-		g_warning ("e_data_book_report_auth_required: Exception "
-			   "responding to BookListener!\n");
-	}
+  path = construct_bookview_path ();
+  book_view = e_data_book_view_new (book, path, search, card_sexp, max_results);
 
-	CORBA_exception_free (&ev);
+  e_book_backend_add_book_view (backend, book_view);
 
+  dbus_g_method_return (context, path);
+  g_free (path);
 }
 
 static void
-e_data_book_construct (EDataBook                *book,
-		       EBookBackend             *backend,
-		       ESource *source,
-		       GNOME_Evolution_Addressbook_BookListener listener)
+impl_AddressBook_Book_getChanges(EDataBook *book, const char *IN_change_id, DBusGMethodInvocation *context)
 {
-	EDataBookPrivate *priv;
-	CORBA_Environment ev;
-
-	g_return_if_fail (book != NULL);
-	g_return_if_fail (source != NULL);
+  OperationData *op;
+  
+  op = op_new (OP_GET_CHANGES, book, context);
+  op->change_id = g_strdup (IN_change_id);
+  g_thread_pool_push (op_pool, op, NULL);
+}
 
-	priv = book->priv;
+void
+e_data_book_respond_get_changes (EDataBook *book, guint32 opid, EDataBookStatus status, GList *changes)
+{
+  DBusGMethodInvocation *context = opid_fetch (opid);
+  
+  if (status != Success) {
+    dbus_g_method_return_error (context, g_error_new (E_DATA_BOOK_ERROR, status, _("Cannot get changes")));
+  } else {
+    /* The DBus interface to this is a(us), an array of structs of unsigned ints
+       and strings.  In dbus-glib this is a GPtrArray of GValueArray of unsigned
+       int and strings. */
+    GPtrArray *array;
 
-	CORBA_exception_init (&ev);
-	book->priv->listener = CORBA_Object_duplicate (listener, &ev);
+    array = g_ptr_array_new ();
 
-	if (ev._major != CORBA_NO_EXCEPTION) {
-		g_message ("e_data_book_construct(): could not duplicate the listener");
-		CORBA_exception_free (&ev);
-		return;
-	}
+    while (changes != NULL) {
+      EDataBookChange *change = (EDataBookChange *) changes->data;
+      GValueArray *vals;
 
-	CORBA_exception_free (&ev);
+      vals = g_value_array_new (2);
+      
+      g_value_array_append (vals, NULL);
+      g_value_init (g_value_array_get_nth (vals, 0), G_TYPE_UINT);
+      g_value_set_uint (g_value_array_get_nth (vals, 0), change->change_type);
 
-	g_object_ref (source);
+      g_value_array_append (vals, NULL);
+      g_value_init (g_value_array_get_nth (vals, 1), G_TYPE_STRING);
+      g_value_take_string (g_value_array_get_nth (vals, 1), change->vcard);
+      /* Now change->vcard is owned by the GValue */
 
-	priv->backend   = g_object_ref(backend);
-	priv->source    = source;
+      g_free (change);
+      changes = g_list_remove (changes, change);
+    }
+    
+    dbus_g_method_return (context, array);
+    g_ptr_array_foreach (array, (GFunc)g_value_array_free, NULL);
+    g_ptr_array_free (array, TRUE);
+  }
 }
 
-/**
- * e_data_book_new:
- * @backend: an #EBookBackend
- * @source: an #ESource
- * @listener: a #GNOME_Evolution_Addressbook_BookListener CORBA object
- *
- * Create a new #EDataBook using @backend for storage, @source as the
- * storage location and @listener for reporting status.
- *
- * Return value: A new #EDataBook.
- **/
-EDataBook *
-e_data_book_new (EBookBackend                               *backend,
-		 ESource *source,
-		 GNOME_Evolution_Addressbook_BookListener  listener)
+static gboolean
+impl_AddressBook_Book_cancelOperation(EDataBook *book, GError **error)
 {
-	static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
-	static PortableServer_POA poa = NULL;
-	EDataBook *book;
-
-	g_static_mutex_lock (&mutex);
-	if (poa == NULL)
-		poa = bonobo_poa_get_threaded (ORBIT_THREAD_HINT_PER_REQUEST, NULL);
-	g_static_mutex_unlock (&mutex);
-
-	book = g_object_new (E_TYPE_DATA_BOOK, "poa", poa, NULL);
+  if (!e_book_backend_cancel_operation (e_data_book_get_backend (book), book)) {
+    g_set_error (error, E_DATA_BOOK_ERROR, CouldNotCancel, "Failed to cancel operation");
+    return FALSE;
+  }
 
-	e_data_book_construct (book, backend, source, listener);
-
-	return book;
+  return TRUE;
 }
 
 static void
-e_data_book_dispose (GObject *object)
+impl_AddressBook_Book_close(EDataBook *book, DBusGMethodInvocation *context)
 {
-	EDataBook *book = E_DATA_BOOK (object);
+  char *sender;
 
-	if (book->priv) {
-		CORBA_Environment ev;
+  sender = dbus_g_method_get_sender (context);
 
-		CORBA_exception_init (&ev);
-		CORBA_Object_release (book->priv->listener, &ev);
+  book->closed_cb (book, sender);
 
-		if (ev._major != CORBA_NO_EXCEPTION)
-			g_message ("e_data_book_construct(): could not release the listener");
+  g_free (sender);
 
-		CORBA_exception_free (&ev);
+  g_object_unref (book);
 
-		g_object_unref (book->priv->source);
-		g_object_unref (book->priv->backend);
-		g_free (book->priv);
-		book->priv = NULL;
-	}
-
-	if (G_OBJECT_CLASS (e_data_book_parent_class)->dispose)
-		G_OBJECT_CLASS (e_data_book_parent_class)->dispose (object);
+  dbus_g_method_return (context);
 }
 
-static void
-e_data_book_class_init (EDataBookClass *klass)
+void
+e_data_book_report_writable (EDataBook *book, gboolean writable)
 {
-	GObjectClass *object_class = G_OBJECT_CLASS (klass);
-	POA_GNOME_Evolution_Addressbook_Book__epv *epv;
+  g_return_if_fail (book != NULL);
 
-	e_data_book_parent_class = g_type_class_peek_parent (klass);
+  g_signal_emit (book, signals[WRITABLE], 0, writable);
+}
 
-	object_class->dispose = e_data_book_dispose;
+void
+e_data_book_report_connection_status (EDataBook *book, gboolean connected)
+{
+  g_return_if_fail (book != NULL);
 
-	epv = &klass->epv;
+  g_signal_emit (book, signals[CONNECTION], 0, connected);
+}
 
-	epv->open                    = impl_GNOME_Evolution_Addressbook_Book_open;
-	epv->remove                  = impl_GNOME_Evolution_Addressbook_Book_remove;
-	epv->getContact              = impl_GNOME_Evolution_Addressbook_Book_getContact;
-	epv->getContactList          = impl_GNOME_Evolution_Addressbook_Book_getContactList;
-	epv->authenticateUser        = impl_GNOME_Evolution_Addressbook_Book_authenticateUser;
-	epv->addContact              = impl_GNOME_Evolution_Addressbook_Book_addContact;
-	epv->removeContacts          = impl_GNOME_Evolution_Addressbook_Book_removeContacts;
-	epv->modifyContact           = impl_GNOME_Evolution_Addressbook_Book_modifyContact;
-	epv->getStaticCapabilities   = impl_GNOME_Evolution_Addressbook_Book_getStaticCapabilities;
-	epv->getSupportedFields      = impl_GNOME_Evolution_Addressbook_Book_getSupportedFields;
-	epv->getRequiredFields       = impl_GNOME_Evolution_Addressbook_Book_getRequiredFields;
-	epv->getSupportedAuthMethods = impl_GNOME_Evolution_Addressbook_Book_getSupportedAuthMethods;
-	epv->getBookView             = impl_GNOME_Evolution_Addressbook_Book_getBookView;
-	epv->getChanges              = impl_GNOME_Evolution_Addressbook_Book_getChanges;
-	epv->cancelOperation         = impl_GNOME_Evolution_Addressbook_Book_cancelOperation;
+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
-e_data_book_init (EDataBook *book)
+return_status_and_list (guint32 opid, EDataBookStatus status, GList *list, gboolean free_data)
 {
-	book->priv                = g_new0 (EDataBookPrivate, 1);
+  DBusGMethodInvocation *context = opid_fetch (opid);
+
+  if (status == Success) {
+    char **array;
+    GList *l;
+    int i = 0;
+    
+    array = g_new0 (char*, 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 {
+    dbus_g_method_return_error (context, g_error_new (E_DATA_BOOK_ERROR, status, _("Cannot complete operation")));
+  }
 }
-
-BONOBO_TYPE_FUNC_FULL (
-		       EDataBook,
-		       GNOME_Evolution_Addressbook_Book,
-		       BONOBO_TYPE_OBJECT,
-		       e_data_book);

Modified: branches/eds-dbus/addressbook/libedata-book/e-data-book.h
==============================================================================
--- branches/eds-dbus/addressbook/libedata-book/e-data-book.h	(original)
+++ branches/eds-dbus/addressbook/libedata-book/e-data-book.h	Fri Sep 12 17:21:22 2008
@@ -1,120 +1,81 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
- * A wrapper object which exports the GNOME_Evolution_Addressbook_Book CORBA interface
- * and which maintains a request queue.
+ * Copyright (C) 2006 OpenedHand Ltd
  *
- * Author:
- *   Nat Friedman (nat ximian com)
+ * 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.
  *
- * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * 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.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Author: Ross Burton <ross openedhand com>
  */
 
 #ifndef __E_DATA_BOOK_H__
 #define __E_DATA_BOOK_H__
 
-#include <bonobo/bonobo-object.h>
-#include "libedataserver/e-list.h"
-#include "libedataserver/e-source.h"
-#include <libedata-book/Evolution-DataServer-Addressbook.h>
-#include <libedata-book/e-data-book-types.h>
-
-G_BEGIN_DECLS
-
-#define E_TYPE_DATA_BOOK        (e_data_book_get_type ())
-#define E_DATA_BOOK(o)          (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_DATA_BOOK, EDataBook))
-#define E_DATA_BOOK_CLASS(k)    (G_TYPE_CHECK_CLASS_CAST((k), E_DATA_BOOK_FACTORY_TYPE, EDataBookClass))
-#define E_IS_DATA_BOOK(o)       (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_DATA_BOOK))
-#define E_IS_DATA_BOOK_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_DATA_BOOK))
-#define E_DATA_BOOK_GET_CLASS(k) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_DATA_BOOK, EDataBookClass))
-
-typedef struct _EDataBookPrivate EDataBookPrivate;
-
-struct _EDataBook {
-	BonoboObject       parent_object;
-	EDataBookPrivate    *priv;
+#include <glib-object.h>
+#include <libedataserver/e-source.h>
+#include "e-book-backend.h"
+#include "e-data-book-types.h"
+
+typedef void (* EDataBookClosedCallback) (EDataBook *book, const char *client);
+
+struct _EDataBook
+{
+  GObject parent;
+  EBookBackend *backend;
+  ESource *source;
+  /* TODO: move to private data */
+  EDataBookClosedCallback closed_cb;
 };
 
-struct _EDataBookClass {
-	BonoboObjectClass parent_class;
-
-	POA_GNOME_Evolution_Addressbook_Book__epv epv;
-
-	/* Padding for future expansion */
-	void (*_pas_reserved0) (void);
-	void (*_pas_reserved1) (void);
-	void (*_pas_reserved2) (void);
-	void (*_pas_reserved3) (void);
-	void (*_pas_reserved4) (void);
+struct _EDataBookClass
+{
+  GObjectClass parent;
 };
 
+#define E_TYPE_DATA_BOOK              (e_data_book_get_type ())
+#define E_DATA_BOOK(object)           (G_TYPE_CHECK_INSTANCE_CAST ((object), E_TYPE_DATA_BOOK, EDataBook))
+#define E_DATA_BOOK_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_DATA_BOOK, EDataBookClass))
+#define E_IS_DATA_BOOK(object)        (G_TYPE_CHECK_INSTANCE_TYPE ((object), E_TYPE_DATA_BOOK))
+#define E_IS_DATA_BOOK_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_DATA_BOOK))
+#define E_DATA_BOOK_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_DATA_BOOK, EDataBookClass))
+
+GQuark e_data_book_error_quark (void);
+#define E_DATA_BOOK_ERROR e_data_book_error_quark ()
+
+GType e_data_book_get_type(void);
+
+EDataBook * e_data_book_new (EBookBackend *backend, ESource *source, EDataBookClosedCallback closed_cb);
+
+ESource* e_data_book_get_source (EDataBook *book);
+EBookBackend* e_data_book_get_backend (EDataBook *book);
+
+/* Callbacks from the backends */
+void e_data_book_respond_open (EDataBook *book, guint opid, EDataBookStatus status);
+void e_data_book_respond_get_contact (EDataBook *book, guint32 opid, EDataBookStatus status, char *vcard);
+void e_data_book_respond_get_contact_list (EDataBook *book, guint32 opid, EDataBookStatus status, GList *cards);
+void e_data_book_respond_remove_contacts (EDataBook *book, guint32 opid, EDataBookStatus  status, GList *ids);
+void e_data_book_respond_remove (EDataBook *book, guint32 opid, EDataBookStatus status);
+void e_data_book_respond_modify (EDataBook *book, guint32 opid, EDataBookStatus status, EContact *contact);
+void e_data_book_respond_modify_contacts (EDataBook *book, guint32 opid, EDataBookStatus status, GList *contacts);
+void e_data_book_respond_create (EDataBook *book, guint32 opid, EDataBookStatus status, EContact *contact);
+void e_data_book_respond_get_changes (EDataBook *book, guint32 opid, EDataBookStatus status, GList *changes);
+void e_data_book_respond_authenticate_user (EDataBook *book, guint32 opid, EDataBookStatus status);
+void e_data_book_respond_get_supported_fields (EDataBook *book, guint32 opid, EDataBookStatus status, GList *fields);
+void e_data_book_respond_get_required_fields (EDataBook *book, guint32 opid, EDataBookStatus status, GList *fields);
+void e_data_book_respond_get_supported_auth_methods (EDataBook *book, guint32 opid, EDataBookStatus status, GList *fields);
+
+void e_data_book_report_writable (EDataBook *book, gboolean writable);
+void e_data_book_report_connection_status (EDataBook *book, gboolean is_online);
+void e_data_book_report_auth_required (EDataBook *book);
 
-EDataBook                *e_data_book_new                    (EBookBackend                               *backend,
-							      ESource                                  *source,
-							 GNOME_Evolution_Addressbook_BookListener  listener);
-GNOME_Evolution_Addressbook_BookListener e_data_book_get_listener (EDataBook                         *book);
-EBookBackend             *e_data_book_get_backend            (EDataBook                                *book);
-ESource                *e_data_book_get_source             (EDataBook                                *book);
-
-void                    e_data_book_respond_open           (EDataBook                                *book,
-							    guint32                                   opid,
-							    GNOME_Evolution_Addressbook_CallStatus    status);
-void                    e_data_book_respond_remove         (EDataBook                                *book,
-							    guint32                                   opid,
-							    GNOME_Evolution_Addressbook_CallStatus  status);
-void                    e_data_book_respond_create         (EDataBook                                *book,
-							    guint32                                   opid,
-							    GNOME_Evolution_Addressbook_CallStatus  status,
-							    EContact                               *contact);
-void                    e_data_book_respond_remove_contacts (EDataBook                                *book,
-							     guint32                                   opid,
-							     GNOME_Evolution_Addressbook_CallStatus  status,
-							     GList                                  *ids);
-void                    e_data_book_respond_modify         (EDataBook                                *book,
-							    guint32                                   opid,
-							    GNOME_Evolution_Addressbook_CallStatus  status,
-							    EContact                               *contact);
-void                    e_data_book_respond_authenticate_user (EDataBook                                *book,
-							       guint32                                   opid,
-							       GNOME_Evolution_Addressbook_CallStatus  status);
-void                    e_data_book_respond_get_supported_fields (EDataBook                              *book,
-								  guint32                                 opid,
-								  GNOME_Evolution_Addressbook_CallStatus  status,
-								  GList                                  *fields);
-void                    e_data_book_respond_get_required_fields (EDataBook                              *book,
-								  guint32                                 opid,
-								  GNOME_Evolution_Addressbook_CallStatus  status,
-								  GList                                  *fields);
-void                    e_data_book_respond_get_supported_auth_methods (EDataBook                              *book,
-									guint32                                 opid,
-									GNOME_Evolution_Addressbook_CallStatus  status,
-									GList                                  *fields);
-
-void                    e_data_book_respond_get_book_view  (EDataBook                              *book,
-							    guint32                                 opid,
-							    GNOME_Evolution_Addressbook_CallStatus  status,
-							    EDataBookView                          *book_view);
-void                    e_data_book_respond_get_contact    (EDataBook                              *book,
-							    guint32                                 opid,
-							    GNOME_Evolution_Addressbook_CallStatus  status,
-							    char                              *vcard);
-void                    e_data_book_respond_get_contact_list (EDataBook                              *book,
-							      guint32                                 opid,
-							      GNOME_Evolution_Addressbook_CallStatus  status,
-							      GList *cards);
-void                    e_data_book_respond_get_changes    (EDataBook                              *book,
-							    guint32                                 opid,
-							    GNOME_Evolution_Addressbook_CallStatus  status,
-							    GList                                  *changes);
-
-void                    e_data_book_report_writable        (EDataBook                         *book,
-							    gboolean                           writable);
-void                    e_data_book_report_connection_status (EDataBook                        *book,
-							      gboolean                         is_online);
-
-void                    e_data_book_report_auth_required     (EDataBook                       *book);
-
-GType                   e_data_book_get_type               (void);
-
-G_END_DECLS
-
-#endif /* ! __E_DATA_BOOK_H__ */
+#endif /* __E_DATA_BOOK_H__ */

Modified: branches/eds-dbus/addressbook/libedata-book/libedata-book.pc.in
==============================================================================
--- branches/eds-dbus/addressbook/libedata-book/libedata-book.pc.in	(original)
+++ branches/eds-dbus/addressbook/libedata-book/libedata-book.pc.in	Fri Sep 12 17:21:22 2008
@@ -6,13 +6,13 @@
 datadir= datadir@
 
 idldir= idldir@
-IDL_INCLUDES=-I${idldir} @IDL_INCLUDES@
+IDL_INCLUDES=-I ${idldir} @IDL_INCLUDES@
 
 privincludedir= privincludedir@
 
 Name: libedatabook
 Description: Backend library for evolution address books
 Version: @VERSION@
-Requires: libbonobo-2.0 >= @LIBBONOBO_REQUIRED@ libgnome-2.0 libedataserver-1.2 libebackend-1.2 libebook-1.2
+Requires: libedataserver-1.2 libebook-1.2 dbus-glib-1
 Libs: -L${libdir} -ledata-book-1.2
 Cflags: -I${privincludedir}



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