[evolution-data-server] New EClient/EBookClient/ECalClient API deprecating EBook/ECal



commit 06cf0baa73a9d19d03cbf84e751fecef987e0b3a
Author: Milan Crha <mcrha redhat com>
Date:   Mon May 23 11:45:20 2011 +0200

    New EClient/EBookClient/ECalClient API deprecating EBook/ECal

 addressbook/backends/file/e-book-backend-file.c    |  398 +-
 .../backends/google/e-book-backend-google.c        |  471 +-
 addressbook/backends/ldap/e-book-backend-ldap.c    | 1155 ++--
 addressbook/backends/vcf/e-book-backend-vcf.c      |  158 +-
 .../backends/webdav/e-book-backend-webdav.c        |  237 +-
 addressbook/libebook/Makefile.am                   |    5 +
 .../e-book-client-view-private.h}                  |   14 +-
 addressbook/libebook/e-book-client-view.c          |  384 ++
 addressbook/libebook/e-book-client-view.h          |   71 +
 addressbook/libebook/e-book-client.c               | 2093 ++++++
 addressbook/libebook/e-book-client.h               |  131 +
 addressbook/libebook/e-book-view-private.h         |    1 +
 addressbook/libebook/e-book-view.c                 |   49 +-
 addressbook/libebook/e-book-view.h                 |   12 +-
 addressbook/libebook/e-book.c                      |  362 +-
 addressbook/libebook/e-book.h                      |    5 +
 addressbook/libedata-book/Makefile.am              |    1 -
 addressbook/libedata-book/e-book-backend-sync.c    |  511 +-
 addressbook/libedata-book/e-book-backend-sync.h    |   81 +-
 addressbook/libedata-book/e-book-backend.c         |  950 ++--
 addressbook/libedata-book/e-book-backend.h         |  221 +-
 addressbook/libedata-book/e-data-book-factory.c    |   53 +-
 addressbook/libedata-book/e-data-book-factory.h    |    2 +-
 addressbook/libedata-book/e-data-book-types.h      |   18 +-
 addressbook/libedata-book/e-data-book-view.c       |  169 +-
 addressbook/libedata-book/e-data-book-view.h       |   45 +-
 addressbook/libedata-book/e-data-book.c            |  894 ++-
 addressbook/libedata-book/e-data-book.h            |  118 +-
 addressbook/libedata-book/opid.c                   |   75 -
 addressbook/libegdbus/Makefile.am                  |   28 +-
 addressbook/libegdbus/e-gdbus-book-factory.c       |  551 ++
 addressbook/libegdbus/e-gdbus-book-factory.h       |  120 +
 addressbook/libegdbus/e-gdbus-book-view.c          |  690 ++
 addressbook/libegdbus/e-gdbus-book-view.h          |  155 +
 addressbook/libegdbus/e-gdbus-book.c               | 1126 +++
 addressbook/libegdbus/e-gdbus-book.h               |  265 +
 addressbook/libegdbus/e-gdbus-egdbusbook.c         | 4483 ------------
 addressbook/libegdbus/e-gdbus-egdbusbook.h         |  640 --
 addressbook/libegdbus/e-gdbus-egdbusbookfactory.c  | 1112 ---
 addressbook/libegdbus/e-gdbus-egdbusbookfactory.h  |  202 -
 addressbook/libegdbus/e-gdbus-egdbusbookview.c     | 2025 ------
 addressbook/libegdbus/e-gdbus-egdbusbookview.h     |  285 -
 addressbook/libegdbus/e-gdbus-marshallers.c        |  343 -
 addressbook/libegdbus/e-gdbus-marshallers.h        |   77 -
 addressbook/libegdbus/e-gdbus-typemappers.h        |   11 -
 calendar/backends/caldav/e-cal-backend-caldav.c    |  566 +-
 .../backends/contacts/e-cal-backend-contacts.c     |  249 +-
 calendar/backends/file/e-cal-backend-file.c        |  727 +--
 calendar/backends/http/e-cal-backend-http.c        |  437 +-
 calendar/backends/weather/e-cal-backend-weather.c  |  301 +-
 calendar/libecal/Makefile.am                       |    7 +-
 calendar/libecal/e-cal-client-view-private.h       |   35 +
 calendar/libecal/e-cal-client-view.c               |  527 ++
 calendar/libecal/e-cal-client-view.h               |   68 +
 calendar/libecal/e-cal-client.c                    | 4106 +++++++++++
 calendar/libecal/e-cal-client.h                    |  193 +
 calendar/libecal/e-cal-types.h                     |    3 +-
 calendar/libecal/e-cal-view.c                      |   40 +-
 calendar/libecal/e-cal-view.h                      |    6 +
 calendar/libecal/e-cal.c                           |  857 ++-
 calendar/libecal/e-cal.h                           |   12 +
 calendar/libedata-cal/e-cal-backend-sexp.c         |    8 +-
 calendar/libedata-cal/e-cal-backend-sync.c         |  742 +--
 calendar/libedata-cal/e-cal-backend-sync.h         |  213 +-
 calendar/libedata-cal/e-cal-backend.c              | 1610 +++---
 calendar/libedata-cal/e-cal-backend.h              |  235 +-
 calendar/libedata-cal/e-data-cal-common.h          |    3 -
 calendar/libedata-cal/e-data-cal-factory.c         |   65 +-
 calendar/libedata-cal/e-data-cal-factory.h         |   15 +-
 calendar/libedata-cal/e-data-cal-types.h           |   13 +-
 calendar/libedata-cal/e-data-cal-view.c            |  354 +-
 calendar/libedata-cal/e-data-cal-view.h            |   53 +-
 calendar/libedata-cal/e-data-cal.c                 | 1442 +++--
 calendar/libedata-cal/e-data-cal.h                 |  116 +-
 calendar/libegdbus/Makefile.am                     |   27 +-
 calendar/libegdbus/e-gdbus-cal-factory.c           |  604 ++
 calendar/libegdbus/e-gdbus-cal-factory.h           |  116 +
 calendar/libegdbus/e-gdbus-cal-view.c              |  690 ++
 calendar/libegdbus/e-gdbus-cal-view.h              |  147 +
 calendar/libegdbus/e-gdbus-cal.c                   | 1584 +++++
 calendar/libegdbus/e-gdbus-cal.h                   |  333 +
 calendar/libegdbus/e-gdbus-egdbuscal.c             | 7222 --------------------
 calendar/libegdbus/e-gdbus-egdbuscal.h             | 1011 ---
 calendar/libegdbus/e-gdbus-egdbuscalfactory.c      | 1130 ---
 calendar/libegdbus/e-gdbus-egdbuscalfactory.h      |  205 -
 calendar/libegdbus/e-gdbus-egdbuscalview.c         | 2043 ------
 calendar/libegdbus/e-gdbus-egdbuscalview.h         |  287 -
 calendar/libegdbus/e-gdbus-marshallers.c           |  474 --
 calendar/libegdbus/e-gdbus-marshallers.h           |  104 -
 calendar/libegdbus/e-gdbus-marshallers.list        |   14 -
 calendar/libegdbus/e-gdbus-typemappers.h           |   11 -
 configure.ac                                       |   14 +-
 libedataserver/Makefile.am                         |   17 +-
 libedataserver/e-client-private.h                  |  122 +
 libedataserver/e-client.c                          | 2489 +++++++
 libedataserver/e-client.h                          |  167 +
 libedataserver/e-credentials.c                     |  560 ++
 libedataserver/e-credentials.h                     |   87 +
 libedataserver/e-data-server-util.c                |   84 +
 libedataserver/e-data-server-util.h                |    5 +
 .../e-gdbus-marshallers.list                       |   17 +-
 libedataserver/e-gdbus-templates.c                 | 1710 +++++
 libedataserver/e-gdbus-templates.h                 |  750 ++
 libedataserver/e-operation-pool.c                  |  136 +
 libedataserver/e-operation-pool.h                  |   36 +
 libedataserverui/Makefile.am                       |   11 +-
 libedataserverui/e-client-utils.c                  |  773 +++
 libedataserverui/e-client-utils.h                  |   61 +
 po/POTFILES.in                                     |    8 +
 tests/libebook/Makefile.am                         |    2 +-
 tests/libebook/client/Makefile.am                  |   98 +
 tests/libebook/client/client-test-utils.c          |  433 ++
 tests/libebook/client/client-test-utils.h          |   27 +
 tests/libebook/client/test-client-add-contact.c    |   95 +
 tests/libebook/client/test-client-async.c          |  121 +
 tests/libebook/client/test-client-examine.c        |  399 ++
 tests/libebook/client/test-client-get-contact.c    |   70 +
 tests/libebook/client/test-client-get-view.c       |  180 +
 tests/libebook/client/test-client-modify-contact.c |  159 +
 tests/libebook/client/test-client-nonexistent-id.c |   44 +
 tests/libebook/client/test-client-refresh.c        |  114 +
 .../client/test-client-remove-contact-by-uid.c     |  127 +
 tests/libebook/client/test-client-remove-contact.c |  130 +
 .../libebook/client/test-client-remove-contacts.c  |  160 +
 tests/libebook/client/test-client-remove.c         |   69 +
 tests/libebook/client/test-client-search.c         |   67 +
 tests/libebook/client/test-client-self.c           |   46 +
 .../client/test-client-stress-factory--fifo.c      |   50 +
 .../client/test-client-stress-factory--serial.c    |   37 +
 .../test-client-stress-factory--single-book.c      |   62 +
 tests/libebook/client/test-client-stress-views.c   |  128 +
 tests/libebook/client/test-client.c                |   82 +
 tests/libebook/test-categories.c                   |    2 +-
 tests/libebook/test-date.c                         |    2 +-
 tests/libebook/test-photo.c                        |    2 +-
 tests/libebook/test-query.c                        |    2 +-
 tests/libebook/test-string.c                       |    2 +-
 tests/libebook/test-undefinedfield.c               |    2 +-
 tests/libebook/test-untyped-phones.c               |    2 +-
 tests/libecal/Makefile.am                          |    2 +
 tests/libecal/client/Makefile.am                   |   89 +
 tests/libecal/client/client-test-utils.c           |  350 +
 tests/libecal/client/client-test-utils.h           |   25 +
 tests/libecal/client/test-client-add-timezone.c    |  209 +
 tests/libecal/client/test-client-create-object.c   |  297 +
 tests/libecal/client/test-client-examine.c         |  487 ++
 .../client/test-client-get-attachment-uris.c       |  191 +
 tests/libecal/client/test-client-get-free-busy.c   |  164 +
 tests/libecal/client/test-client-get-object-list.c |  203 +
 tests/libecal/client/test-client-get-view.c        |  230 +
 tests/libecal/client/test-client-modify-object.c   |  194 +
 tests/libecal/client/test-client-open.c            |  124 +
 tests/libecal/client/test-client-receive-objects.c |  142 +
 tests/libecal/client/test-client-refresh.c         |  134 +
 tests/libecal/client/test-client-remove-object.c   |  156 +
 tests/libecal/client/test-client-send-objects.c    |  169 +
 .../client/test-client-stress-factory--fifo.c      |   51 +
 .../client/test-client-stress-factory--serial.c    |   38 +
 .../test-client-stress-factory--single-cal.c       |   63 +
 tests/libecal/client/test-client-stress-views.c    |  116 +
 tests/libecal/ecal-test-utils.c                    |    1 -
 tests/libecal/test-ecal-get-free-busy.c            |    3 +-
 tests/libedataserverui/Makefile.am                 |    5 +
 tests/libedataserverui/test-client-examine-auth.c  |  418 ++
 164 files changed, 34322 insertions(+), 29102 deletions(-)
---
diff --git a/addressbook/backends/file/e-book-backend-file.c b/addressbook/backends/file/e-book-backend-file.c
index 6f33d8d..1b09182 100644
--- a/addressbook/backends/file/e-book-backend-file.c
+++ b/addressbook/backends/file/e-book-backend-file.c
@@ -248,7 +248,7 @@ do_create (EBookBackendFile  *bf,
 static void
 e_book_backend_file_create_contact (EBookBackendSync *backend,
 				    EDataBook *book,
-				    guint32 opid,
+				    GCancellable *cancellable,
 				    const gchar *vcard,
 				    EContact **contact,
 				    GError **perror)
@@ -263,18 +263,18 @@ e_book_backend_file_create_contact (EBookBackendSync *backend,
 static void
 e_book_backend_file_remove_contacts (EBookBackendSync *backend,
 				     EDataBook *book,
-				     guint32 opid,
-				     GList *id_list,
-				     GList **ids,
+				     GCancellable *cancellable,
+				     const GSList *id_list,
+				     GSList **ids,
 				     GError **perror)
 {
 	EBookBackendFile *bf = E_BOOK_BACKEND_FILE (backend);
 	DB             *db = bf->priv->file_db;
 	DBT            id_dbt;
 	gint            db_error;
-	gchar          *id;
-	GList         *l;
-	GList         *removed_cards = NULL;
+	const gchar    *id;
+	const GSList   *l;
+	GSList         *removed_cards = NULL;
 
 	for (l = id_list; l; l = l->next) {
 		id = l->data;
@@ -288,7 +288,7 @@ e_book_backend_file_remove_contacts (EBookBackendSync *backend,
 			continue;
 		}
 
-		removed_cards = g_list_prepend (removed_cards, id);
+		removed_cards = g_slist_prepend (removed_cards, g_strdup (id));
 	}
 
 	/* if we actually removed some, try to sync */
@@ -301,7 +301,7 @@ e_book_backend_file_remove_contacts (EBookBackendSync *backend,
 	*ids = removed_cards;
 
 	for (l = removed_cards; l; l = l->next) {
-		gchar *id = l->data;
+		id = l->data;
 		e_book_backend_summary_remove_contact (bf->priv->summary, id);
 	}
 }
@@ -309,7 +309,7 @@ e_book_backend_file_remove_contacts (EBookBackendSync *backend,
 static void
 e_book_backend_file_modify_contact (EBookBackendSync *backend,
 				    EDataBook *book,
-				    guint32 opid,
+				    GCancellable *cancellable,
 				    const gchar *vcard,
 				    EContact **contact,
 				    GError **perror)
@@ -368,7 +368,7 @@ e_book_backend_file_modify_contact (EBookBackendSync *backend,
 static void
 e_book_backend_file_get_contact (EBookBackendSync *backend,
 				 EDataBook *book,
-				 guint32 opid,
+				 GCancellable *cancellable,
 				 const gchar *id,
 				 gchar **vcard,
 				 GError **perror)
@@ -400,9 +400,9 @@ e_book_backend_file_get_contact (EBookBackendSync *backend,
 static void
 e_book_backend_file_get_contact_list (EBookBackendSync *backend,
 				      EDataBook *book,
-				      guint32 opid,
+				      GCancellable *cancellable,
 				      const gchar *query,
-				      GList **contacts,
+				      GSList **contacts,
 				      GError **perror)
 {
 	EBookBackendFile *bf = E_BOOK_BACKEND_FILE (backend);
@@ -413,7 +413,7 @@ e_book_backend_file_get_contact_list (EBookBackendSync *backend,
 	EBookBackendSExp *card_sexp = NULL;
 	gboolean search_needed;
 	const gchar *search = query;
-	GList *contact_list = NULL;
+	GSList *contact_list = NULL;
 
 	d(printf ("e_book_backend_file_get_contact_list (%s)\n", search));
 	if (e_book_backend_summary_is_summary_query (bf->priv->summary, search)) {
@@ -435,7 +435,7 @@ e_book_backend_file_get_contact_list (EBookBackendSync *backend,
 
 			db_error = db->get (db, NULL, &id_dbt, &vcard_dbt, 0);
 			if (db_error == 0) {
-				contact_list = g_list_prepend (contact_list, vcard_dbt.data);
+				contact_list = g_slist_prepend (contact_list, vcard_dbt.data);
 			} else {
 				g_warning (G_STRLOC ": db->get failed with %s", db_strerror (db_error));
 				db_error_to_gerror (db_error, perror);
@@ -475,7 +475,7 @@ e_book_backend_file_get_contact_list (EBookBackendSync *backend,
 			    || strcmp (id_dbt.data, E_BOOK_BACKEND_FILE_VERSION_NAME)) {
 
 				if ((!search_needed) || (card_sexp != NULL && e_book_backend_sexp_match_vcard  (card_sexp, vcard_dbt.data))) {
-					contact_list = g_list_prepend (contact_list, vcard_dbt.data);
+					contact_list = g_slist_prepend (contact_list, vcard_dbt.data);
 				}
 			}
 
@@ -567,10 +567,10 @@ book_view_thread (gpointer data)
 	query = e_data_book_view_get_card_query (book_view);
 
 	if ( !strcmp (query, "(contains \"x-evolution-any-field\" \"\")")) {
-		e_data_book_view_notify_status_message (book_view, _("Loading..."));
+		e_data_book_view_notify_progress (book_view, -1, _("Loading..."));
 		allcontacts = TRUE;
 	} else {
-		e_data_book_view_notify_status_message (book_view, _("Searching..."));
+		e_data_book_view_notify_progress (book_view, -1, _("Searching..."));
 		allcontacts = FALSE;
 	}
 
@@ -695,262 +695,59 @@ e_book_backend_file_stop_book_view (EBookBackend  *backend,
 		g_thread_join (closure->thread);
 }
 
-typedef struct {
-	DB *db;
-
-	GList *add_cards;
-	GList *add_ids;
-	GList *mod_cards;
-	GList *mod_ids;
-	GList *del_ids;
-	GList *del_cards;
-} EBookBackendFileChangeContext;
-
-static void
-e_book_backend_file_changes_foreach_key (const gchar *key, gpointer user_data)
+static gchar *
+e_book_backend_file_extract_path_from_source (ESource *source)
 {
-	EBookBackendFileChangeContext *ctx = user_data;
-	DB      *db = ctx->db;
-	DBT     id_dbt, vcard_dbt;
-	gint     db_error = 0;
-
-	string_to_dbt (key, &id_dbt);
-	memset (&vcard_dbt, 0, sizeof (vcard_dbt));
-	vcard_dbt.flags = DB_DBT_MALLOC;
-
-	db_error = db->get (db, NULL, &id_dbt, &vcard_dbt, 0);
-
-	if (db_error != 0) {
-		EContact *contact;
-		gchar *id = id_dbt.data;
-		gchar *vcard_string;
-
-		contact = e_contact_new ();
-		e_contact_set (contact, E_CONTACT_UID, id);
-
-		vcard_string = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
-
-		ctx->del_ids = g_list_append (ctx->del_ids,
-					      g_strdup (id));
-		ctx->del_cards = g_list_append (ctx->del_cards,
-						vcard_string);
+	gchar *filename = NULL;
+	const gchar *absolute_uri;
 
-		g_object_unref (contact);
-
-		g_free (vcard_dbt.data);
-	}
-}
+	absolute_uri = e_source_peek_absolute_uri (source);
 
-static void
-e_book_backend_file_get_changes (EBookBackendSync *backend,
-				 EDataBook *book,
-				 guint32 opid,
-				 const gchar *change_id,
-				 GList **changes_out,
-				 GError **perror)
-{
-	EBookBackendFile *bf = E_BOOK_BACKEND_FILE (backend);
-	gint     db_error = 0;
-	DBT     id_dbt, vcard_dbt;
-	gchar    *filename;
-	EDbHash *ehash;
-	GList *i, *v;
-	DB      *db = bf->priv->file_db;
-	DBC *dbc;
-	GList *changes = NULL;
-	EBookBackendFileChangeContext ctx;
+	if (absolute_uri && g_str_has_prefix (absolute_uri, "local://")) {
+		gchar *uri;
 
-	memset (&id_dbt, 0, sizeof (id_dbt));
-	memset (&vcard_dbt, 0, sizeof (vcard_dbt));
+		uri = g_strconcat ("file://", absolute_uri + 8, NULL);
+		filename = g_filename_from_uri (uri, NULL, NULL);
+		g_free (uri);
 
-	memset (&ctx, 0, sizeof (ctx));
-
-	ctx.db = db;
-
-	/* Find the changed ids */
-	filename = g_strdup_printf ("%s/%s" CHANGES_DB_SUFFIX, bf->priv->dirname, change_id);
-	ehash = e_dbhash_new (filename);
-	g_free (filename);
-
-	db_error = db->cursor (db, NULL, &dbc, 0);
-
-	if (db_error != 0) {
-		g_warning (G_STRLOC ": db->cursor failed with %s", db_strerror (db_error));
-	} else {
-		db_error = dbc->c_get (dbc, &id_dbt, &vcard_dbt, DB_FIRST);
-
-		while (db_error == 0) {
-
-			/* don't include the version in the list of cards */
-			if (id_dbt.size != strlen (E_BOOK_BACKEND_FILE_VERSION_NAME) + 1
-			    || strcmp (id_dbt.data, E_BOOK_BACKEND_FILE_VERSION_NAME)) {
-				EContact *contact;
-				gchar *id = id_dbt.data;
-				gchar *vcard_string;
-
-				/* Remove fields the user can't change
-				 * and can change without the rest of the
-				 * card changing
-				 */
-				contact = create_contact (id_dbt.data, vcard_dbt.data);
-
-#ifdef notyet
-				g_object_set (card, "last_use", NULL, "use_score", 0.0, NULL);
-#endif
-				vcard_string = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
-				g_object_unref (contact);
-
-				/* check what type of change has occurred, if any */
-				switch (e_dbhash_compare (ehash, id, vcard_string)) {
-				case E_DBHASH_STATUS_SAME:
-					g_free (vcard_string);
-					break;
-				case E_DBHASH_STATUS_NOT_FOUND:
-					ctx.add_cards = g_list_append (ctx.add_cards, vcard_string);
-					ctx.add_ids = g_list_append (ctx.add_ids, g_strdup (id));
-					break;
-				case E_DBHASH_STATUS_DIFFERENT:
-					ctx.mod_cards = g_list_append (ctx.mod_cards, vcard_string);
-					ctx.mod_ids = g_list_append (ctx.mod_ids, g_strdup (id));
-					break;
-				}
-			}
-
-			db_error = dbc->c_get (dbc, &id_dbt, &vcard_dbt, DB_NEXT);
-		}
-		dbc->c_close (dbc);
-	}
-
-	e_dbhash_foreach_key (ehash, (EDbHashFunc) e_book_backend_file_changes_foreach_key, &ctx);
-
-	/* Send the changes */
-	if (db_error != DB_NOTFOUND) {
-		g_warning ("e_book_backend_file_changes: error building list\n");
-		*changes_out = NULL;
-		db_error_to_gerror (db_error, perror);
+		if (!g_file_test (filename, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
+			g_free (filename);
+			filename = NULL;
+ 		}
 	}
-	else {
-		/* Update the hash and build our changes list */
-		for (i = ctx.add_ids, v = ctx.add_cards; i != NULL; i = i->next, v = v->next) {
-			gchar *id = i->data;
-			gchar *vcard = v->data;
 
-			e_dbhash_add (ehash, id, vcard);
-			changes = g_list_prepend (changes,
-						  e_book_backend_change_add_new (vcard));
+	if (!filename) {
+		const gchar *user_data_dir;
+		const gchar *source_dir;
+		gchar *mangled_source_dir;
 
-			g_free (i->data);
-			g_free (v->data);
-		}
-		for (i = ctx.mod_ids, v = ctx.mod_cards; i != NULL; i = i->next, v = v->next) {
-			gchar *id = i->data;
-			gchar *vcard = v->data;
+		user_data_dir = e_get_user_data_dir ();
+		source_dir = e_source_peek_relative_uri (source);
 
-			e_dbhash_add (ehash, id, vcard);
-			changes = g_list_prepend (changes,
-						  e_book_backend_change_modify_new (vcard));
+		if (!source_dir || !g_str_equal (source_dir, "system"))
+			source_dir = e_source_peek_uid (source);
 
-			g_free (i->data);
-			g_free (v->data);
-		}
-		for (i = ctx.del_ids, v = ctx.del_cards; i != NULL; i = i->next, v = v->next) {
-			gchar *id = i->data;
-			gchar *vcard = v->data;
-
-			e_dbhash_remove (ehash, id);
+		/* Mangle the URI to not contain invalid characters. */
+		mangled_source_dir = g_strdelimit (g_strdup (source_dir), ":/", '_');
 
-			changes = g_list_prepend (changes,
-						  e_book_backend_change_delete_new (vcard));
-			g_free (i->data);
-			g_free (v->data);
-		}
+		filename = g_build_filename (
+			user_data_dir, "addressbook", mangled_source_dir, NULL);
 
-		e_dbhash_write (ehash);
-
-		*changes_out = changes;
+		g_free (mangled_source_dir);
 	}
 
-	e_dbhash_destroy (ehash);
-}
-
-static gchar *
-e_book_backend_file_extract_path_from_source (ESource *source)
-{
-	const gchar *user_data_dir;
-	const gchar *source_dir;
-	gchar *mangled_source_dir;
-	gchar *filename;
-
-	user_data_dir = e_get_user_data_dir ();
-	source_dir = e_source_peek_relative_uri (source);
-
-	if (!source_dir || !g_str_equal (source_dir, "system"))
-		source_dir = e_source_peek_uid (source);
-
-	/* Mangle the URI to not contain invalid characters. */
-	mangled_source_dir = g_strdelimit (g_strdup (source_dir), ":/", '_');
-
-	filename = g_build_filename (
-		user_data_dir, "addressbook", mangled_source_dir, NULL);
-
-	g_free (mangled_source_dir);
-
 	return filename;
 }
 
 static void
 e_book_backend_file_authenticate_user (EBookBackendSync *backend,
-				       EDataBook *book,
-				       guint32 opid,
-				       const gchar *user,
-				       const gchar *passwd,
-				       const gchar *auth_method,
+				       GCancellable *cancellable,
+				       ECredentials *credentials,
 				       GError **perror)
 {
 	/* Success */
 }
 
-static void
-e_book_backend_file_get_required_fields (EBookBackendSync *backend,
-					  EDataBook *book,
-					  guint32 opid,
-					  GList **fields_out,
-					  GError **perror)
-{
-	GList *fields = NULL;
-
-	fields = g_list_append (fields , g_strdup (e_contact_field_name (E_CONTACT_FILE_AS)));
-	*fields_out = fields;
-}
-
-static void
-e_book_backend_file_get_supported_auth_methods (EBookBackendSync *backend,
-						EDataBook *book,
-						guint32 opid,
-						GList **methods_out,
-						GError **perror)
-{
-	*methods_out = NULL;
-}
-
-static void
-e_book_backend_file_get_supported_fields (EBookBackendSync *backend,
-					  EDataBook *book,
-					  guint32 opid,
-					  GList **fields_out,
-					  GError **perror)
-{
-	GList *fields = NULL;
-	gint i;
-
-	/* XXX we need a way to say "we support everything", since the
-	   file backend does */
-	for (i = 1; i < E_CONTACT_FIELD_LAST; i++)
-		fields = g_list_append (fields, g_strdup (e_contact_field_name (i)));
-
-	*fields_out = fields;
-}
-
 /*
 ** versions:
 **
@@ -1095,14 +892,16 @@ file_errcall (const gchar *buf1, gchar *buf2)
 }
 
 static void
-e_book_backend_file_load_source (EBookBackend           *backend,
-				 ESource                *source,
-				 gboolean                only_if_exists,
-				 GError                **perror)
+e_book_backend_file_open (EBookBackendSync       *backend,
+			  EDataBook              *book,
+			  GCancellable		*cancellable,
+			  gboolean               only_if_exists,
+			  GError	       **perror)
 {
 	EBookBackendFile *bf = E_BOOK_BACKEND_FILE (backend);
 	gchar           *dirname, *filename;
-	gboolean        writable = FALSE;
+	gboolean        readonly = TRUE;
+	ESource *source = e_book_backend_get_source (E_BOOK_BACKEND (backend));
 	gint             db_error;
 	DB *db;
 	DB_ENV *env;
@@ -1208,7 +1007,7 @@ e_book_backend_file_load_source (EBookBackend           *backend,
 	}
 
 	if (db_error == 0) {
-		writable = TRUE;
+		readonly = FALSE;
 	} else {
 		db->close (db, 0);
 		db_error = db_create (&db, env, 0);
@@ -1252,7 +1051,7 @@ e_book_backend_file_load_source (EBookBackend           *backend,
 			db_error = (*db->open) (db, NULL, filename, NULL, DB_HASH, DB_CREATE | DB_THREAD, 0666);
 			if (db_error != 0) {
 				db->close (db, 0);
-				g_warning ("db->open (... DB_CREATE ...) failed with %s", db_strerror (db_error));
+				g_warning ("db->open (... %s ... DB_CREATE ...) failed with %s", filename, db_strerror (db_error));
 			}
 			else {
 #ifdef CREATE_DEFAULT_VCARD
@@ -1264,7 +1063,7 @@ e_book_backend_file_load_source (EBookBackend           *backend,
 					g_object_unref (contact);
 #endif
 
-				writable = TRUE;
+				readonly = FALSE;
 			}
 		}
 	}
@@ -1313,8 +1112,9 @@ e_book_backend_file_load_source (EBookBackend           *backend,
 		}
 	}
 
-	e_book_backend_set_is_loaded (backend, TRUE);
-	e_book_backend_set_is_writable (backend, writable);
+	e_book_backend_notify_online (E_BOOK_BACKEND (backend), TRUE);
+	e_book_backend_notify_readonly (E_BOOK_BACKEND (backend), readonly);
+	e_book_backend_notify_opened (E_BOOK_BACKEND (backend), NULL /* Success */);
 }
 
 static gboolean
@@ -1338,7 +1138,7 @@ select_changes (const gchar *name)
 static void
 e_book_backend_file_remove (EBookBackendSync *backend,
 			    EDataBook        *book,
-			    guint32           opid,
+			    GCancellable *cancellable,
 			    GError          **perror)
 {
 	EBookBackendFile *bf = E_BOOK_BACKEND_FILE (backend);
@@ -1386,25 +1186,43 @@ e_book_backend_file_remove (EBookBackendSync *backend,
 	   that the addressbook is still valid */
 }
 
-static gchar *
-e_book_backend_file_get_static_capabilities (EBookBackend *backend)
+static gboolean
+e_book_backend_file_get_backend_property (EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, const gchar *prop_name, gchar **prop_value, GError **error)
 {
-	return g_strdup("local,do-initial-query,bulk-removes,contact-lists");
-}
+	gboolean processed = TRUE;
 
-static void
-e_book_backend_file_cancel_operation (EBookBackend *backend, EDataBook *book, GError **perror)
-{
-	g_propagate_error (perror, EDB_ERROR (COULD_NOT_CANCEL));
+	g_return_val_if_fail (prop_name != NULL, FALSE);
+	g_return_val_if_fail (prop_value != NULL, FALSE);
+
+	if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
+		*prop_value = g_strdup ("local,do-initial-query,bulk-removes,contact-lists");
+	} else if (g_str_equal (prop_name, BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS)) {
+		*prop_value = g_strdup (e_contact_field_name (E_CONTACT_FILE_AS));
+	} else if (g_str_equal (prop_name, BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS)) {
+		GSList *fields = NULL;
+		gint i;
+
+		/* XXX we need a way to say "we support everything", since the
+		   file backend does */
+		for (i = 1; i < E_CONTACT_FIELD_LAST; i++)
+			fields = g_slist_append (fields, (gpointer) e_contact_field_name (i));
+
+		*prop_value = e_data_book_string_slist_to_comma_string (fields);
+		g_slist_free (fields);
+	} else if (g_str_equal (prop_name, BOOK_BACKEND_PROPERTY_SUPPORTED_AUTH_METHODS)) {
+		*prop_value = NULL;
+	} else {
+		processed = FALSE;
+	}
+
+	return processed;
 }
 
 static void
-e_book_backend_file_set_mode (EBookBackend *backend, EDataBookMode mode)
+e_book_backend_file_set_online (EBookBackend *backend, gboolean is_online)
 {
-	if (e_book_backend_is_loaded (backend)) {
-		e_book_backend_notify_writable (backend, TRUE);
-		e_book_backend_notify_connection_status (backend, TRUE);
-	}
+	if (e_book_backend_is_opened (backend))
+		e_book_backend_notify_online (backend, TRUE);
 }
 
 static void
@@ -1530,24 +1348,20 @@ e_book_backend_file_class_init (EBookBackendFileClass *klass)
 	backend_class = E_BOOK_BACKEND_CLASS (klass);
 
 	/* Set the virtual methods. */
-	backend_class->load_source			= e_book_backend_file_load_source;
-	backend_class->get_static_capabilities		= e_book_backend_file_get_static_capabilities;
-	backend_class->start_book_view			= e_book_backend_file_start_book_view;
-	backend_class->stop_book_view			= e_book_backend_file_stop_book_view;
-	backend_class->cancel_operation			= e_book_backend_file_cancel_operation;
-	backend_class->set_mode				= e_book_backend_file_set_mode;
-	backend_class->sync				= e_book_backend_file_sync;
-	sync_class->remove_sync				= e_book_backend_file_remove;
-	sync_class->create_contact_sync			= e_book_backend_file_create_contact;
-	sync_class->remove_contacts_sync		= e_book_backend_file_remove_contacts;
-	sync_class->modify_contact_sync			= e_book_backend_file_modify_contact;
-	sync_class->get_contact_sync			= e_book_backend_file_get_contact;
-	sync_class->get_contact_list_sync		= e_book_backend_file_get_contact_list;
-	sync_class->get_changes_sync			= e_book_backend_file_get_changes;
-	sync_class->authenticate_user_sync		= e_book_backend_file_authenticate_user;
-	sync_class->get_supported_auth_methods_sync	= e_book_backend_file_get_supported_auth_methods;
-	sync_class->get_supported_fields_sync		= e_book_backend_file_get_supported_fields;
-	sync_class->get_required_fields_sync		= e_book_backend_file_get_required_fields;
+	backend_class->start_book_view		= e_book_backend_file_start_book_view;
+	backend_class->stop_book_view		= e_book_backend_file_stop_book_view;
+	backend_class->set_online		= e_book_backend_file_set_online;
+	backend_class->sync			= e_book_backend_file_sync;
+
+	sync_class->open_sync			= e_book_backend_file_open;
+	sync_class->remove_sync			= e_book_backend_file_remove;
+	sync_class->get_backend_property_sync	= e_book_backend_file_get_backend_property;
+	sync_class->create_contact_sync		= e_book_backend_file_create_contact;
+	sync_class->remove_contacts_sync	= e_book_backend_file_remove_contacts;
+	sync_class->modify_contact_sync		= e_book_backend_file_modify_contact;
+	sync_class->get_contact_sync		= e_book_backend_file_get_contact;
+	sync_class->get_contact_list_sync	= e_book_backend_file_get_contact_list;
+	sync_class->authenticate_user_sync	= e_book_backend_file_authenticate_user;
 
 	object_class->dispose = e_book_backend_file_dispose;
 	object_class->finalize = e_book_backend_file_finalize;
diff --git a/addressbook/backends/google/e-book-backend-google.c b/addressbook/backends/google/e-book-backend-google.c
index 0d39bc2..0ac563e 100644
--- a/addressbook/backends/google/e-book-backend-google.c
+++ b/addressbook/backends/google/e-book-backend-google.c
@@ -51,7 +51,7 @@ typedef enum {
 } CacheType;
 
 struct _EBookBackendGooglePrivate {
-	EDataBookMode mode;
+	gboolean is_online;
 	GList *bookviews;
 
 	CacheType cache_type;
@@ -371,7 +371,7 @@ cache_needs_update (EBookBackend *backend, guint *remaining_secs)
 		*remaining_secs = G_MAXUINT;
 
 	/* We never want to update in offline mode */
-	if (priv->mode != E_DATA_BOOK_MODE_REMOTE)
+	if (!priv->is_online)
 		return FALSE;
 
 	rv = cache_get_last_update_tv (backend, &last);
@@ -463,19 +463,21 @@ on_sequence_complete (EBookBackend *backend, GError *error)
 }
 
 static GCancellable *
-start_operation (EBookBackend *backend, guint32 opid, const gchar *message)
+start_operation (EBookBackend *backend, guint32 opid, GCancellable *cancellable, const gchar *message)
 {
 	EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
-	GCancellable *cancellable;
 	GList *iter;
 
 	/* Insert the operation into the set of active cancellable operations */
-	cancellable = g_cancellable_new ();
+	if (cancellable)
+		g_object_ref (cancellable);
+	else
+		cancellable = g_cancellable_new ();
 	g_hash_table_insert (priv->cancellables, GUINT_TO_POINTER (opid), g_object_ref (cancellable));
 
 	/* Send out a status message to each view */
 	for (iter = priv->bookviews; iter; iter = iter->next)
-		e_data_book_view_notify_status_message (E_DATA_BOOK_VIEW (iter->data), message);
+		e_data_book_view_notify_progress (E_DATA_BOOK_VIEW (iter->data), -1, message);
 
 	return cancellable;
 }
@@ -586,7 +588,7 @@ get_new_contacts (EBookBackend *backend)
 	}
 
 	/* Query for new contacts asynchronously */
-	cancellable = start_operation (backend, 0, _("Querying for updated contactsâ?¦"));
+	cancellable = start_operation (backend, 0, NULL, _("Querying for updated contactsâ?¦"));
 	gdata_contacts_service_query_contacts_async (GDATA_CONTACTS_SERVICE (priv->service), query, cancellable,
 						     (GDataQueryProgressCallback) (last_updated ? process_subsequent_entry : process_initial_entry),
 						     backend, (GAsyncReadyCallback) get_new_contacts_cb, backend);
@@ -704,7 +706,7 @@ get_groups (EBookBackend *backend)
 	}
 
 	/* Run the query asynchronously */
-	cancellable = start_operation (backend, 1, _("Querying for updated groupsâ?¦"));
+	cancellable = start_operation (backend, 1, NULL, _("Querying for updated groupsâ?¦"));
 	gdata_contacts_service_query_groups_async (GDATA_CONTACTS_SERVICE (priv->service), query, cancellable,
 						   (GDataQueryProgressCallback) process_group, backend, (GAsyncReadyCallback) get_groups_cb, backend);
 
@@ -768,8 +770,8 @@ cache_refresh_if_needed (EBookBackend *backend)
 
 	__debug__ (G_STRFUNC);
 
-	if (priv->mode != E_DATA_BOOK_MODE_REMOTE || !priv->service || !gdata_service_is_authenticated (priv->service)) {
-		__debug__ ("We are not connected to Google%s.", (priv->mode != E_DATA_BOOK_MODE_REMOTE) ? " (offline mode)" : "");
+	if (!priv->is_online || !priv->service || !gdata_service_is_authenticated (priv->service)) {
+		__debug__ ("We are not connected to Google%s.", (!priv->is_online) ? " (offline mode)" : "");
 		return TRUE;
 	}
 
@@ -852,20 +854,19 @@ finish:
 }
 
 static void
-e_book_backend_google_create_contact (EBookBackend *backend, EDataBook *book, guint32 opid, const gchar *vcard_str)
+e_book_backend_google_create_contact (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *vcard_str)
 {
 	EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
 	EContact *contact;
 	GDataEntry *entry;
 	gchar *xml;
 	CreateContactData *data;
-	GCancellable *cancellable;
 
 	__debug__ (G_STRFUNC);
 
 	__debug__ ("Creating: %s", vcard_str);
 
-	if (priv->mode != E_DATA_BOOK_MODE_REMOTE) {
+	if (!priv->is_online) {
 		e_data_book_respond_create (book, opid, EDB_ERROR (OFFLINE_UNAVAILABLE), NULL);
 		return;
 	}
@@ -888,7 +889,7 @@ e_book_backend_google_create_contact (EBookBackend *backend, EDataBook *book, gu
 	data->book = g_object_ref (book);
 	data->opid = opid;
 
-	cancellable = start_operation (backend, opid, _("Creating new contactâ?¦"));
+	cancellable = start_operation (backend, opid, cancellable, _("Creating new contactâ?¦"));
 	gdata_contacts_service_insert_contact_async (GDATA_CONTACTS_SERVICE (priv->service), GDATA_CONTACTS_CONTACT (entry), cancellable,
 						     (GAsyncReadyCallback) create_contact_cb, data);
 	g_object_unref (cancellable);
@@ -907,7 +908,7 @@ remove_contact_cb (GDataService *service, GAsyncResult *result, RemoveContactDat
 {
 	GError *gdata_error = NULL;
 	gboolean success;
-	GList *ids;
+	GSList *ids;
 
 	__debug__ (G_STRFUNC);
 
@@ -925,9 +926,9 @@ remove_contact_cb (GDataService *service, GAsyncResult *result, RemoveContactDat
 	}
 
 	/* List the entry's ID in the success list */
-	ids = g_list_prepend (NULL, data->uid);
+	ids = g_slist_prepend (NULL, data->uid);
 	e_data_book_respond_remove_contacts (data->book, data->opid, NULL, ids);
-	g_list_free (ids);
+	g_slist_free (ids);
 
 finish:
 	g_free (data->uid);
@@ -937,18 +938,17 @@ finish:
 }
 
 static void
-e_book_backend_google_remove_contacts (EBookBackend *backend, EDataBook *book, guint32 opid, GList *id_list)
+e_book_backend_google_remove_contacts (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const GSList *id_list)
 {
 	EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
 	const gchar *uid = id_list->data;
 	GDataEntry *entry = NULL;
 	EContact *cached_contact;
-	GCancellable *cancellable;
 	RemoveContactData *data;
 
 	__debug__ (G_STRFUNC);
 
-	if (priv->mode != E_DATA_BOOK_MODE_REMOTE) {
+	if (!priv->is_online) {
 		e_data_book_respond_remove_contacts (book, opid, EDB_ERROR (OFFLINE_UNAVAILABLE), NULL);
 		return;
 	}
@@ -981,7 +981,7 @@ e_book_backend_google_remove_contacts (EBookBackend *backend, EDataBook *book, g
 	data->opid = opid;
 	data->uid = g_strdup (uid);
 
-	cancellable = start_operation (backend, opid, _("Deleting contactâ?¦"));
+	cancellable = start_operation (backend, opid, cancellable, _("Deleting contactâ?¦"));
 	gdata_service_delete_entry_async (GDATA_SERVICE (priv->service), entry, cancellable, (GAsyncReadyCallback) remove_contact_cb, data);
 	g_object_unref (cancellable);
 	g_object_unref (entry);
@@ -1035,20 +1035,19 @@ finish:
 }
 
 static void
-e_book_backend_google_modify_contact (EBookBackend *backend, EDataBook *book, guint32 opid, const gchar *vcard_str)
+e_book_backend_google_modify_contact (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *vcard_str)
 {
 	EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
 	EContact *contact, *cached_contact;
 	GDataEntry *entry = NULL;
 	const gchar *uid;
 	ModifyContactData *data;
-	GCancellable *cancellable;
 
 	__debug__ (G_STRFUNC);
 
 	__debug__ ("Updating: %s", vcard_str);
 
-	if (priv->mode != E_DATA_BOOK_MODE_REMOTE) {
+	if (!priv->is_online) {
 		e_data_book_respond_modify (book, opid, EDB_ERROR (OFFLINE_UNAVAILABLE), NULL);
 		return;
 	}
@@ -1089,14 +1088,14 @@ e_book_backend_google_modify_contact (EBookBackend *backend, EDataBook *book, gu
 	data->book = g_object_ref (book);
 	data->opid = opid;
 
-	cancellable = start_operation (backend, opid, _("Modifying contactâ?¦"));
+	cancellable = start_operation (backend, opid, cancellable, _("Modifying contactâ?¦"));
 	gdata_service_update_entry_async (GDATA_SERVICE (priv->service), entry, cancellable, (GAsyncReadyCallback) modify_contact_cb, data);
 	g_object_unref (cancellable);
 	g_object_unref (entry);
 }
 
 static void
-e_book_backend_google_get_contact (EBookBackend *backend, EDataBook *book, guint32 opid, const gchar *uid)
+e_book_backend_google_get_contact (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *uid)
 {
 	EContact *contact;
 	gchar *vcard_str;
@@ -1120,10 +1119,11 @@ e_book_backend_google_get_contact (EBookBackend *backend, EDataBook *book, guint
 }
 
 static void
-e_book_backend_google_get_contact_list (EBookBackend *backend, EDataBook *book, guint32 opid, const gchar *query)
+e_book_backend_google_get_contact_list (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *query)
 {
 	EBookBackendSExp *sexp;
-	GList *all_contacts, *filtered_contacts = NULL;
+	GList *all_contacts;
+	GSList *filtered_contacts = NULL;
 
 	__debug__ (G_STRFUNC);
 
@@ -1137,7 +1137,7 @@ e_book_backend_google_get_contact_list (EBookBackend *backend, EDataBook *book,
 		/* If the search expression matches the contact, include it in the search results */
 		if (e_book_backend_sexp_match_contact (sexp, contact)) {
 			gchar *vcard_str = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
-			filtered_contacts = g_list_append (filtered_contacts, vcard_str);
+			filtered_contacts = g_slist_append (filtered_contacts, vcard_str);
 		}
 
 		g_object_unref (contact);
@@ -1146,7 +1146,9 @@ e_book_backend_google_get_contact_list (EBookBackend *backend, EDataBook *book,
 	g_object_unref (sexp);
 
 	e_data_book_respond_get_contact_list (book, opid, NULL, filtered_contacts);
-	g_list_free (filtered_contacts);
+
+	g_slist_foreach (filtered_contacts, (GFunc) g_free, NULL);
+	g_slist_free (filtered_contacts);
 }
 
 static gboolean
@@ -1196,7 +1198,7 @@ e_book_backend_google_start_book_view (EBookBackend *backend, EDataBookView *boo
 	priv->bookviews = g_list_append (priv->bookviews, bookview);
 
 	e_data_book_view_ref (bookview);
-	e_data_book_view_notify_status_message (bookview, _("Loadingâ?¦"));
+	e_data_book_view_notify_progress (bookview, -1, _("Loadingâ?¦"));
 
 	/* Ensure that we're ready to support a view */
 	set_live_mode (backend, TRUE);
@@ -1205,7 +1207,7 @@ e_book_backend_google_start_book_view (EBookBackend *backend, EDataBookView *boo
 	if (cache_needs_update (backend, NULL)) {
 		if (!priv->service || !gdata_service_is_authenticated (priv->service)) {
 			/* We need authorization first */
-			e_book_backend_notify_auth_required (backend);
+			e_book_backend_notify_auth_required (backend, TRUE, NULL);
 		} else {
 			/* Update in an idle function, so that this call doesn't block */
 			priv->idle_id = g_idle_add ((GSourceFunc) on_refresh_idle, backend);
@@ -1268,7 +1270,6 @@ proxy_settings_changed (EProxy *proxy, EBookBackend *backend)
 
 typedef struct {
 	EBookBackend *backend;
-	EDataBook *book;
 	guint32 opid;
 } AuthenticateUserData;
 
@@ -1288,40 +1289,38 @@ authenticate_user_cb (GDataService *service, GAsyncResult *result, AuthenticateU
 	}
 
 	finish_operation (data->backend, data->opid);
-	e_book_backend_notify_writable (data->backend, (!gdata_error) ? TRUE : FALSE);
-	e_data_book_respond_authenticate_user (data->book, data->opid, book_error);
+	e_book_backend_notify_readonly (data->backend, gdata_error ? TRUE : FALSE);
+	e_book_backend_notify_opened (data->backend, book_error);
 
-	g_object_unref (data->book);
 	g_object_unref (data->backend);
 	g_slice_free (AuthenticateUserData, data);
 }
 
 static void
-e_book_backend_google_authenticate_user (EBookBackend *backend, EDataBook *book, guint32 opid,
-                                         const gchar *username, const gchar *password, const gchar *auth_method)
+e_book_backend_google_authenticate_user (EBookBackend *backend, GCancellable *cancellable, ECredentials *credentials)
 {
 	EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
 	AuthenticateUserData *data;
-	GCancellable *cancellable;
+	guint32 opid;
 
 	__debug__ (G_STRFUNC);
 
-	if (priv->mode != E_DATA_BOOK_MODE_REMOTE) {
-		e_book_backend_notify_writable (backend, FALSE);
-		e_book_backend_notify_connection_status (backend, FALSE);
-		e_data_book_respond_authenticate_user (book, opid, EDB_ERROR (SUCCESS));
+	if (!priv->is_online) {
+		e_book_backend_notify_readonly (backend, TRUE);
+		e_book_backend_notify_online (backend, FALSE);
+		e_book_backend_notify_opened (backend, EDB_ERROR (SUCCESS));
 		return;
 	}
 
 	if (priv->service && gdata_service_is_authenticated (priv->service)) {
 		g_warning ("Connection to Google already established.");
-		e_book_backend_notify_writable (backend, TRUE);
-		e_data_book_respond_authenticate_user (book, opid, NULL);
+		e_book_backend_notify_readonly (backend, FALSE);
+		e_book_backend_notify_opened (backend, NULL);
 		return;
 	}
 
-	if (!username || username[0] == 0 || !password || password[0] == 0) {
-		e_data_book_respond_authenticate_user (book, opid, EDB_ERROR (AUTHENTICATION_FAILED));
+	if (!credentials || !e_credentials_has_key (credentials, E_CREDENTIALS_KEY_USERNAME) || !e_credentials_has_key (credentials, E_CREDENTIALS_KEY_PASSWORD)) {
+		e_book_backend_notify_opened (backend, EDB_ERROR (AUTHENTICATION_REQUIRED));
 		return;
 	}
 
@@ -1337,183 +1336,40 @@ e_book_backend_google_authenticate_user (EBookBackend *backend, EDataBook *book,
 		g_signal_connect (priv->proxy, "changed", G_CALLBACK (proxy_settings_changed), backend);
 	}
 
+	opid = -1;
+	while (g_hash_table_lookup (priv->cancellables, GUINT_TO_POINTER (opid)))
+		opid--;
+
 	/* Authenticate with the server asynchronously */
 	data = g_slice_new (AuthenticateUserData);
 	data->backend = g_object_ref (backend);
-	data->book = g_object_ref (book);
 	data->opid = opid;
 
-	cancellable = start_operation (backend, opid, _("Authenticating with the serverâ?¦"));
-	gdata_service_authenticate_async (priv->service, username, password, cancellable, (GAsyncReadyCallback) authenticate_user_cb, data);
+	cancellable = start_operation (backend, opid, cancellable, _("Authenticating with the serverâ?¦"));
+	gdata_service_authenticate_async (priv->service, e_credentials_peek (credentials, E_CREDENTIALS_KEY_USERNAME), e_credentials_peek (credentials, E_CREDENTIALS_KEY_PASSWORD), cancellable, (GAsyncReadyCallback) authenticate_user_cb, data);
 	g_object_unref (cancellable);
 }
 
 static void
-e_book_backend_google_get_supported_auth_methods (EBookBackend *backend, EDataBook *book, guint32 opid)
-{
-	GList methods = { (gpointer) "plain/password", NULL, NULL };
-
-	__debug__ (G_STRFUNC);
-	e_data_book_respond_get_supported_auth_methods (book, opid, NULL, &methods);
-}
-
-static void
-e_book_backend_google_get_required_fields (EBookBackend *backend, EDataBook *book, guint32 opid)
-{
-	__debug__ (G_STRFUNC);
-	e_data_book_respond_get_required_fields (book, opid, NULL, NULL);
-}
-
-static void
-e_book_backend_google_get_supported_fields (EBookBackend *backend, EDataBook *book, guint32 opid)
-{
-	GList *fields = NULL;
-	guint i;
-	const gint supported_fields[] = {
-		E_CONTACT_FULL_NAME,
-		E_CONTACT_EMAIL_1,
-		E_CONTACT_EMAIL_2,
-		E_CONTACT_EMAIL_3,
-		E_CONTACT_EMAIL_4,
-		E_CONTACT_ADDRESS_LABEL_HOME,
-		E_CONTACT_ADDRESS_LABEL_WORK,
-		E_CONTACT_ADDRESS_LABEL_OTHER,
-		E_CONTACT_PHONE_HOME,
-		E_CONTACT_PHONE_HOME_FAX,
-		E_CONTACT_PHONE_BUSINESS,
-		E_CONTACT_PHONE_BUSINESS_FAX,
-		E_CONTACT_PHONE_MOBILE,
-		E_CONTACT_PHONE_PAGER,
-		E_CONTACT_IM_AIM,
-		E_CONTACT_IM_JABBER,
-		E_CONTACT_IM_YAHOO,
-		E_CONTACT_IM_MSN,
-		E_CONTACT_IM_ICQ,
-		E_CONTACT_IM_SKYPE,
-		E_CONTACT_IM_GADUGADU,
-		E_CONTACT_IM_GROUPWISE,
-		E_CONTACT_ADDRESS,
-		E_CONTACT_ADDRESS_HOME,
-		E_CONTACT_ADDRESS_WORK,
-		E_CONTACT_ADDRESS_OTHER,
-		E_CONTACT_NAME,
-		E_CONTACT_GIVEN_NAME,
-		E_CONTACT_FAMILY_NAME,
-		E_CONTACT_PHONE_ASSISTANT,
-		E_CONTACT_PHONE_BUSINESS_2,
-		E_CONTACT_PHONE_CALLBACK,
-		E_CONTACT_PHONE_CAR,
-		E_CONTACT_PHONE_COMPANY,
-		E_CONTACT_PHONE_HOME_2,
-		E_CONTACT_PHONE_ISDN,
-		E_CONTACT_PHONE_OTHER,
-		E_CONTACT_PHONE_OTHER_FAX,
-		E_CONTACT_PHONE_PRIMARY,
-		E_CONTACT_PHONE_RADIO,
-		E_CONTACT_PHONE_TELEX,
-		E_CONTACT_PHONE_TTYTDD,
-		E_CONTACT_IM_AIM_HOME_1,
-		E_CONTACT_IM_AIM_HOME_2,
-		E_CONTACT_IM_AIM_HOME_3,
-		E_CONTACT_IM_AIM_WORK_1,
-		E_CONTACT_IM_AIM_WORK_2,
-		E_CONTACT_IM_AIM_WORK_3,
-		E_CONTACT_IM_GROUPWISE_HOME_1,
-		E_CONTACT_IM_GROUPWISE_HOME_2,
-		E_CONTACT_IM_GROUPWISE_HOME_3,
-		E_CONTACT_IM_GROUPWISE_WORK_1,
-		E_CONTACT_IM_GROUPWISE_WORK_2,
-		E_CONTACT_IM_GROUPWISE_WORK_3,
-		E_CONTACT_IM_JABBER_HOME_1,
-		E_CONTACT_IM_JABBER_HOME_2,
-		E_CONTACT_IM_JABBER_HOME_3,
-		E_CONTACT_IM_JABBER_WORK_1,
-		E_CONTACT_IM_JABBER_WORK_2,
-		E_CONTACT_IM_JABBER_WORK_3,
-		E_CONTACT_IM_YAHOO_HOME_1,
-		E_CONTACT_IM_YAHOO_HOME_2,
-		E_CONTACT_IM_YAHOO_HOME_3,
-		E_CONTACT_IM_YAHOO_WORK_1,
-		E_CONTACT_IM_YAHOO_WORK_2,
-		E_CONTACT_IM_YAHOO_WORK_3,
-		E_CONTACT_IM_MSN_HOME_1,
-		E_CONTACT_IM_MSN_HOME_2,
-		E_CONTACT_IM_MSN_HOME_3,
-		E_CONTACT_IM_MSN_WORK_1,
-		E_CONTACT_IM_MSN_WORK_2,
-		E_CONTACT_IM_MSN_WORK_3,
-		E_CONTACT_IM_ICQ_HOME_1,
-		E_CONTACT_IM_ICQ_HOME_2,
-		E_CONTACT_IM_ICQ_HOME_3,
-		E_CONTACT_IM_ICQ_WORK_1,
-		E_CONTACT_IM_ICQ_WORK_2,
-		E_CONTACT_IM_ICQ_WORK_3,
-		E_CONTACT_EMAIL,
-		E_CONTACT_IM_GADUGADU_HOME_1,
-		E_CONTACT_IM_GADUGADU_HOME_2,
-		E_CONTACT_IM_GADUGADU_HOME_3,
-		E_CONTACT_IM_GADUGADU_WORK_1,
-		E_CONTACT_IM_GADUGADU_WORK_2,
-		E_CONTACT_IM_GADUGADU_WORK_3,
-		E_CONTACT_TEL,
-		E_CONTACT_IM_SKYPE_HOME_1,
-		E_CONTACT_IM_SKYPE_HOME_2,
-		E_CONTACT_IM_SKYPE_HOME_3,
-		E_CONTACT_IM_SKYPE_WORK_1,
-		E_CONTACT_IM_SKYPE_WORK_2,
-		E_CONTACT_IM_SKYPE_WORK_3,
-		E_CONTACT_SIP,
-		E_CONTACT_ORG,
-		E_CONTACT_ORG_UNIT,
-		E_CONTACT_TITLE,
-		E_CONTACT_ROLE,
-		E_CONTACT_HOMEPAGE_URL,
-		E_CONTACT_BLOG_URL,
-		E_CONTACT_BIRTH_DATE,
-		E_CONTACT_ANNIVERSARY,
-		E_CONTACT_NOTE,
-		E_CONTACT_CATEGORIES,
-		E_CONTACT_CATEGORY_LIST
-	};
-
-	__debug__ (G_STRFUNC);
-
-	/* Add all the fields above to the list */
-	for (i = 0; i < G_N_ELEMENTS (supported_fields); i++) {
-		const gchar *field_name = e_contact_field_name (supported_fields[i]);
-		fields = g_list_prepend (fields, (gpointer) field_name);
-	}
-
-	e_data_book_respond_get_supported_fields (book, opid, NULL, fields);
-	g_list_free (fields);
-}
-
-static void
-e_book_backend_google_get_changes (EBookBackend *backend, EDataBook *book, guint32 opid, const gchar *change_id)
-{
-	__debug__ (G_STRFUNC);
-	e_data_book_respond_get_changes (book, opid, EDB_ERROR (OTHER_ERROR), NULL);
-}
-
-static void
-e_book_backend_google_remove (EBookBackend *backend, EDataBook *book, guint32 opid)
+e_book_backend_google_remove (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable)
 {
 	__debug__ (G_STRFUNC);
 	e_data_book_respond_remove (book, opid, NULL);
 }
 
 static void
-e_book_backend_google_load_source (EBookBackend *backend, ESource *source, gboolean only_if_exists, GError **error)
+e_book_backend_google_open (EBookBackend *backend, EDataBook *book, guint opid, GCancellable *cancellable, gboolean only_if_exists)
 {
 	EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
 	const gchar *refresh_interval_str, *use_ssl_str, *use_cache_str;
 	guint refresh_interval;
 	gboolean use_ssl, use_cache;
+	ESource *source = e_book_backend_get_source (backend);
 
 	__debug__ (G_STRFUNC);
 
 	if (priv->cancellables) {
-		g_propagate_error (error, EDB_ERROR_EX (OTHER_ERROR, "Source already loaded!"));
+		e_book_backend_respond_opened (backend, book, opid, EDB_ERROR_EX (OTHER_ERROR, "Source already loaded!"));
 		return;
 	}
 
@@ -1551,26 +1407,163 @@ e_book_backend_google_load_source (EBookBackend *backend, ESource *source, gbool
 	}
 
 	/* Set up ready to be interacted with */
-	e_book_backend_set_is_loaded (backend, TRUE);
-	e_book_backend_set_is_writable (backend, FALSE);
-	e_book_backend_notify_connection_status (backend, (priv->mode == E_DATA_BOOK_MODE_REMOTE) ? TRUE : FALSE);
+	e_book_backend_notify_online (backend, priv->is_online);
+	e_book_backend_notify_readonly (backend, TRUE);
 
-	if (priv->mode == E_DATA_BOOK_MODE_REMOTE) {
+	if (priv->is_online) {
 		/* We're going online, so we need to authenticate and create the service and proxy.
 		 * This is done in e_book_backend_google_authenticate_user() when it gets the authentication data. */
-		e_book_backend_notify_auth_required (backend);
+		e_book_backend_notify_auth_required (backend, TRUE, NULL);
+	} else {
+		e_book_backend_notify_opened (backend, NULL /* Success */);
 	}
+
+	e_data_book_respond_open (book, opid, NULL /* Success */);
 }
 
-static gchar *
-e_book_backend_google_get_static_capabilities (EBookBackend *backend)
+static void
+e_book_backend_google_get_backend_property (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *prop_name)
 {
 	__debug__ (G_STRFUNC);
-	return g_strdup ("net,do-initial-query,contact-lists");
+
+	g_return_if_fail (prop_name != NULL);
+
+	if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
+		e_data_book_respond_get_backend_property (book, opid, NULL, "net,do-initial-query,contact-lists");
+	} else if (g_str_equal (prop_name, BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS)) {
+		e_data_book_respond_get_backend_property (book, opid, NULL, "");
+	} else if (g_str_equal (prop_name, BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS)) {
+		GSList *fields = NULL;
+		gchar *fields_str;
+		guint i;
+		const gint supported_fields[] = {
+			E_CONTACT_FULL_NAME,
+			E_CONTACT_EMAIL_1,
+			E_CONTACT_EMAIL_2,
+			E_CONTACT_EMAIL_3,
+			E_CONTACT_EMAIL_4,
+			E_CONTACT_ADDRESS_LABEL_HOME,
+			E_CONTACT_ADDRESS_LABEL_WORK,
+			E_CONTACT_ADDRESS_LABEL_OTHER,
+			E_CONTACT_PHONE_HOME,
+			E_CONTACT_PHONE_HOME_FAX,
+			E_CONTACT_PHONE_BUSINESS,
+			E_CONTACT_PHONE_BUSINESS_FAX,
+			E_CONTACT_PHONE_MOBILE,
+			E_CONTACT_PHONE_PAGER,
+			E_CONTACT_IM_AIM,
+			E_CONTACT_IM_JABBER,
+			E_CONTACT_IM_YAHOO,
+			E_CONTACT_IM_MSN,
+			E_CONTACT_IM_ICQ,
+			E_CONTACT_IM_SKYPE,
+			E_CONTACT_IM_GADUGADU,
+			E_CONTACT_IM_GROUPWISE,
+			E_CONTACT_ADDRESS,
+			E_CONTACT_ADDRESS_HOME,
+			E_CONTACT_ADDRESS_WORK,
+			E_CONTACT_ADDRESS_OTHER,
+			E_CONTACT_NAME,
+			E_CONTACT_GIVEN_NAME,
+			E_CONTACT_FAMILY_NAME,
+			E_CONTACT_PHONE_ASSISTANT,
+			E_CONTACT_PHONE_BUSINESS_2,
+			E_CONTACT_PHONE_CALLBACK,
+			E_CONTACT_PHONE_CAR,
+			E_CONTACT_PHONE_COMPANY,
+			E_CONTACT_PHONE_HOME_2,
+			E_CONTACT_PHONE_ISDN,
+			E_CONTACT_PHONE_OTHER,
+			E_CONTACT_PHONE_OTHER_FAX,
+			E_CONTACT_PHONE_PRIMARY,
+			E_CONTACT_PHONE_RADIO,
+			E_CONTACT_PHONE_TELEX,
+			E_CONTACT_PHONE_TTYTDD,
+			E_CONTACT_IM_AIM_HOME_1,
+			E_CONTACT_IM_AIM_HOME_2,
+			E_CONTACT_IM_AIM_HOME_3,
+			E_CONTACT_IM_AIM_WORK_1,
+			E_CONTACT_IM_AIM_WORK_2,
+			E_CONTACT_IM_AIM_WORK_3,
+			E_CONTACT_IM_GROUPWISE_HOME_1,
+			E_CONTACT_IM_GROUPWISE_HOME_2,
+			E_CONTACT_IM_GROUPWISE_HOME_3,
+			E_CONTACT_IM_GROUPWISE_WORK_1,
+			E_CONTACT_IM_GROUPWISE_WORK_2,
+			E_CONTACT_IM_GROUPWISE_WORK_3,
+			E_CONTACT_IM_JABBER_HOME_1,
+			E_CONTACT_IM_JABBER_HOME_2,
+			E_CONTACT_IM_JABBER_HOME_3,
+			E_CONTACT_IM_JABBER_WORK_1,
+			E_CONTACT_IM_JABBER_WORK_2,
+			E_CONTACT_IM_JABBER_WORK_3,
+			E_CONTACT_IM_YAHOO_HOME_1,
+			E_CONTACT_IM_YAHOO_HOME_2,
+			E_CONTACT_IM_YAHOO_HOME_3,
+			E_CONTACT_IM_YAHOO_WORK_1,
+			E_CONTACT_IM_YAHOO_WORK_2,
+			E_CONTACT_IM_YAHOO_WORK_3,
+			E_CONTACT_IM_MSN_HOME_1,
+			E_CONTACT_IM_MSN_HOME_2,
+			E_CONTACT_IM_MSN_HOME_3,
+			E_CONTACT_IM_MSN_WORK_1,
+			E_CONTACT_IM_MSN_WORK_2,
+			E_CONTACT_IM_MSN_WORK_3,
+			E_CONTACT_IM_ICQ_HOME_1,
+			E_CONTACT_IM_ICQ_HOME_2,
+			E_CONTACT_IM_ICQ_HOME_3,
+			E_CONTACT_IM_ICQ_WORK_1,
+			E_CONTACT_IM_ICQ_WORK_2,
+			E_CONTACT_IM_ICQ_WORK_3,
+			E_CONTACT_EMAIL,
+			E_CONTACT_IM_GADUGADU_HOME_1,
+			E_CONTACT_IM_GADUGADU_HOME_2,
+			E_CONTACT_IM_GADUGADU_HOME_3,
+			E_CONTACT_IM_GADUGADU_WORK_1,
+			E_CONTACT_IM_GADUGADU_WORK_2,
+			E_CONTACT_IM_GADUGADU_WORK_3,
+			E_CONTACT_TEL,
+			E_CONTACT_IM_SKYPE_HOME_1,
+			E_CONTACT_IM_SKYPE_HOME_2,
+			E_CONTACT_IM_SKYPE_HOME_3,
+			E_CONTACT_IM_SKYPE_WORK_1,
+			E_CONTACT_IM_SKYPE_WORK_2,
+			E_CONTACT_IM_SKYPE_WORK_3,
+			E_CONTACT_SIP,
+			E_CONTACT_ORG,
+			E_CONTACT_ORG_UNIT,
+			E_CONTACT_TITLE,
+			E_CONTACT_ROLE,
+			E_CONTACT_HOMEPAGE_URL,
+			E_CONTACT_BLOG_URL,
+			E_CONTACT_BIRTH_DATE,
+			E_CONTACT_ANNIVERSARY,
+			E_CONTACT_NOTE,
+			E_CONTACT_CATEGORIES,
+			E_CONTACT_CATEGORY_LIST
+		};
+
+		/* Add all the fields above to the list */
+		for (i = 0; i < G_N_ELEMENTS (supported_fields); i++) {
+			const gchar *field_name = e_contact_field_name (supported_fields[i]);
+			fields = g_slist_prepend (fields, (gpointer) field_name);
+		}
+
+		fields_str = e_data_book_string_slist_to_comma_string (fields);
+
+		e_data_book_respond_get_backend_property (book, opid, NULL, fields_str);
+
+		g_slist_free (fields);
+		g_free (fields_str);
+	} else if (g_str_equal (prop_name, BOOK_BACKEND_PROPERTY_SUPPORTED_AUTH_METHODS)) {
+		e_data_book_respond_get_backend_property (book, opid, NULL, "plain/password");
+	} else {
+		E_BOOK_BACKEND_CLASS (e_book_backend_google_parent_class)->get_backend_property (backend, book, opid, cancellable, prop_name);
+	}
 }
 
 static void
-e_book_backend_google_cancel_operation (EBookBackend *backend, EDataBook *book, GError **error)
+google_cancel_all_operations (EBookBackend *backend)
 {
 	GHashTableIter iter;
 	gpointer opid_ptr;
@@ -1579,6 +1572,9 @@ e_book_backend_google_cancel_operation (EBookBackend *backend, EDataBook *book,
 
 	__debug__ (G_STRFUNC);
 
+	if (!priv->cancellables)
+		return;
+
 	/* Cancel all active operations */
 	g_hash_table_iter_init (&iter, priv->cancellables);
 	while (g_hash_table_iter_next (&iter, &opid_ptr, (gpointer *) &cancellable)) {
@@ -1587,31 +1583,29 @@ e_book_backend_google_cancel_operation (EBookBackend *backend, EDataBook *book,
 }
 
 static void
-e_book_backend_google_set_mode (EBookBackend *backend, EDataBookMode mode)
+e_book_backend_google_set_online (EBookBackend *backend, gboolean is_online)
 {
 	EBookBackendGooglePrivate *priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
-	gboolean online = (mode == E_DATA_BOOK_MODE_REMOTE);
-
 	__debug__ (G_STRFUNC);
 
-	if (mode == priv->mode)
+	if (is_online == priv->is_online)
 		return;
 
-	priv->mode = mode;
+	priv->is_online = is_online;
 
-	e_book_backend_notify_connection_status (backend, online);
+	e_book_backend_notify_online (backend, is_online);
 
-	if (online) {
+	if (is_online && e_book_backend_is_opened (backend)) {
 		/* Going online, so we need to re-authenticate and re-create the service and proxy.
 		 * This is done in e_book_backend_google_authenticate_user() when it gets the authentication data. */
-		e_book_backend_notify_auth_required (backend);
+		e_book_backend_notify_auth_required (backend, TRUE, NULL);
 	} else {
 		/* Going offline, so cancel all running operations */
-		e_book_backend_google_cancel_operation (backend, NULL, NULL);
+		google_cancel_all_operations (backend);
 
 		/* Mark the book as unwriteable if we're going offline, but don't do the inverse when we go online;
 		 * e_book_backend_google_authenticate_user() will mark us as writeable again once the user's authenticated again. */
-		e_book_backend_notify_writable (backend, FALSE);
+		e_book_backend_notify_readonly (backend, TRUE);
 
 		/* We can free our service and proxy */
 		if (priv->service)
@@ -1632,7 +1626,7 @@ e_book_backend_google_dispose (GObject *object)
 	__debug__ (G_STRFUNC);
 
 	/* Cancel all outstanding operations */
-	e_book_backend_google_cancel_operation (E_BOOK_BACKEND (object), NULL, NULL);
+	google_cancel_all_operations (E_BOOK_BACKEND (object));
 
 	while (priv->bookviews) {
 		e_data_book_view_unref (priv->bookviews->data);
@@ -1664,9 +1658,11 @@ e_book_backend_google_finalize (GObject *object)
 
 	__debug__ (G_STRFUNC);
 
-	g_hash_table_destroy (priv->groups_by_id);
-	g_hash_table_destroy (priv->groups_by_name);
-	g_hash_table_destroy (priv->cancellables);
+	if (priv->cancellables) {
+		g_hash_table_destroy (priv->groups_by_id);
+		g_hash_table_destroy (priv->groups_by_name);
+		g_hash_table_destroy (priv->cancellables);
+	}
 
 	G_OBJECT_CLASS (e_book_backend_google_parent_class)->finalize (object);
 }
@@ -1680,23 +1676,18 @@ e_book_backend_google_class_init (EBookBackendGoogleClass *klass)
 	g_type_class_add_private (klass, sizeof (EBookBackendGooglePrivate));
 
 	/* Set the virtual methods. */
-	backend_class->load_source                  = e_book_backend_google_load_source;
-	backend_class->get_static_capabilities      = e_book_backend_google_get_static_capabilities;
-	backend_class->start_book_view              = e_book_backend_google_start_book_view;
-	backend_class->stop_book_view               = e_book_backend_google_stop_book_view;
-	backend_class->cancel_operation             = e_book_backend_google_cancel_operation;
-	backend_class->set_mode                     = e_book_backend_google_set_mode;
-	backend_class->remove                       = e_book_backend_google_remove;
-	backend_class->create_contact               = e_book_backend_google_create_contact;
-	backend_class->remove_contacts              = e_book_backend_google_remove_contacts;
-	backend_class->modify_contact               = e_book_backend_google_modify_contact;
-	backend_class->get_contact                  = e_book_backend_google_get_contact;
-	backend_class->get_contact_list             = e_book_backend_google_get_contact_list;
-	backend_class->get_changes                  = e_book_backend_google_get_changes;
-	backend_class->authenticate_user            = e_book_backend_google_authenticate_user;
-	backend_class->get_supported_fields         = e_book_backend_google_get_supported_fields;
-	backend_class->get_required_fields          = e_book_backend_google_get_required_fields;
-	backend_class->get_supported_auth_methods   = e_book_backend_google_get_supported_auth_methods;
+	backend_class->open			= e_book_backend_google_open;
+	backend_class->get_backend_property	= e_book_backend_google_get_backend_property;
+	backend_class->start_book_view		= e_book_backend_google_start_book_view;
+	backend_class->stop_book_view		= e_book_backend_google_stop_book_view;
+	backend_class->set_online		= e_book_backend_google_set_online;
+	backend_class->remove			= e_book_backend_google_remove;
+	backend_class->create_contact		= e_book_backend_google_create_contact;
+	backend_class->remove_contacts		= e_book_backend_google_remove_contacts;
+	backend_class->modify_contact		= e_book_backend_google_modify_contact;
+	backend_class->get_contact		= e_book_backend_google_get_contact;
+	backend_class->get_contact_list		= e_book_backend_google_get_contact_list;
+	backend_class->authenticate_user	= e_book_backend_google_authenticate_user;
 
 	object_class->dispose  = e_book_backend_google_dispose;
 	object_class->finalize = e_book_backend_google_finalize;
diff --git a/addressbook/backends/ldap/e-book-backend-ldap.c b/addressbook/backends/ldap/e-book-backend-ldap.c
index 1137557..fd72bb2 100644
--- a/addressbook/backends/ldap/e-book-backend-ldap.c
+++ b/addressbook/backends/ldap/e-book-backend-ldap.c
@@ -199,8 +199,8 @@ struct _EBookBackendLDAPPrivate {
 
 	LDAP     *ldap;
 
-	GList    *supported_fields;
-	GList    *supported_auth_methods;
+	GSList   *supported_fields;
+	GSList   *supported_auth_methods;
 
 	EBookBackendCache *cache;
 
@@ -211,7 +211,7 @@ struct _EBookBackendLDAPPrivate {
 	gboolean evolutionPersonChecked;
 	gboolean marked_for_offline;
 
-	gint mode;
+	gboolean is_online;
 	/* our operations */
 	GStaticRecMutex op_hash_mutex;
 	GHashTable *id_to_op;
@@ -444,46 +444,58 @@ can_browse (EBookBackend *backend)
 		strcmp (e_source_get_property (e_book_backend_get_source (backend), "can-browse"), "1") == 0;
 }
 
+static gboolean
+pick_view_cb (EDataBookView *view, gpointer user_data)
+{
+	EDataBookView **pick = user_data;
+
+	g_return_val_if_fail (user_data != NULL, FALSE);
+
+	/* just always use the first book view */
+	*pick = view;
+
+	return view == NULL;
+}
+
 static EDataBookView*
 find_book_view (EBookBackendLDAP *bl)
 {
-	EList *views = e_book_backend_get_book_views (E_BOOK_BACKEND (bl));
-	EIterator *iter = e_list_get_iterator (views);
-	EDataBookView *rv = NULL;
-
-	if (e_iterator_is_valid (iter)) {
-		/* just always use the first book view */
-		EDataBookView *v = (EDataBookView*) e_iterator_get (iter);
-		if (v)
-			rv = v;
-	}
+	EDataBookView *pick = NULL;
 
-	g_object_unref (iter);
-	g_object_unref (views);
+	e_book_backend_foreach_view (E_BOOK_BACKEND (bl), pick_view_cb, &pick);
 
-	return rv;
+	return pick;
 }
 
+struct check_data
+{
+	EDataBookView *to_find;
+	gboolean found;
+};
+
 static gboolean
-book_view_is_valid (EBookBackendLDAP *bl, EDataBookView *book_view)
+check_view_cb (EDataBookView *view, gpointer user_data)
 {
-	gboolean found = FALSE;
-	EList *views;
-	EIterator *iter;
+	struct check_data *cd = user_data;
 
-	if (!book_view)
-		return FALSE;
+	g_return_val_if_fail (user_data != NULL, FALSE);
 
-	views = e_book_backend_get_book_views (E_BOOK_BACKEND (bl));
+	cd->found = view == cd->to_find;
 
-	for (iter = e_list_get_iterator (views); e_iterator_is_valid (iter) && !found; e_iterator_next (iter)) {
-		found = book_view == e_iterator_get (iter);
-	}
+	return !cd->found;
+}
 
-	g_object_unref (iter);
-	g_object_unref (views);
+static gboolean
+book_view_is_valid (EBookBackendLDAP *bl, EDataBookView *book_view)
+{
+	struct check_data cd;
+
+	cd.to_find = book_view;
+	cd.found = FALSE;
+
+	e_book_backend_foreach_view (E_BOOK_BACKEND (bl), check_view_cb, &cd);
 
-	return found;
+	return cd.found;
 }
 
 static void
@@ -491,7 +503,7 @@ book_view_notify_status (EBookBackendLDAP *bl, EDataBookView *view, const gchar
 {
 	if (!book_view_is_valid (bl, view))
 		return;
-	e_data_book_view_notify_status_message (view, status);
+	e_data_book_view_notify_progress (view, -1, status);
 }
 
 static void
@@ -502,23 +514,23 @@ add_to_supported_fields (EBookBackendLDAP *bl, gchar **attrs, GHashTable *attr_h
 		gchar *query_prop = g_hash_table_lookup (attr_hash, attrs[i]);
 
 		if (query_prop) {
-			bl->priv->supported_fields = g_list_append (bl->priv->supported_fields, g_strdup (query_prop));
+			bl->priv->supported_fields = g_slist_append (bl->priv->supported_fields, g_strdup (query_prop));
 
 			/* handle the list attributes here */
 			if (!strcmp (query_prop, e_contact_field_name (E_CONTACT_EMAIL))) {
-				bl->priv->supported_fields = g_list_append (bl->priv->supported_fields, g_strdup (e_contact_field_name (E_CONTACT_EMAIL_1)));
-				bl->priv->supported_fields = g_list_append (bl->priv->supported_fields, g_strdup (e_contact_field_name (E_CONTACT_EMAIL_2)));
-				bl->priv->supported_fields = g_list_append (bl->priv->supported_fields, g_strdup (e_contact_field_name (E_CONTACT_EMAIL_3)));
-				bl->priv->supported_fields = g_list_append (bl->priv->supported_fields, g_strdup (e_contact_field_name (E_CONTACT_EMAIL_4)));
+				bl->priv->supported_fields = g_slist_append (bl->priv->supported_fields, g_strdup (e_contact_field_name (E_CONTACT_EMAIL_1)));
+				bl->priv->supported_fields = g_slist_append (bl->priv->supported_fields, g_strdup (e_contact_field_name (E_CONTACT_EMAIL_2)));
+				bl->priv->supported_fields = g_slist_append (bl->priv->supported_fields, g_strdup (e_contact_field_name (E_CONTACT_EMAIL_3)));
+				bl->priv->supported_fields = g_slist_append (bl->priv->supported_fields, g_strdup (e_contact_field_name (E_CONTACT_EMAIL_4)));
 			}
 			else if (!strcmp (query_prop, e_contact_field_name (E_CONTACT_PHONE_BUSINESS))) {
-				bl->priv->supported_fields = g_list_append (bl->priv->supported_fields, g_strdup (e_contact_field_name (E_CONTACT_PHONE_BUSINESS_2)));
+				bl->priv->supported_fields = g_slist_append (bl->priv->supported_fields, g_strdup (e_contact_field_name (E_CONTACT_PHONE_BUSINESS_2)));
 			}
 			else if (!strcmp (query_prop, e_contact_field_name (E_CONTACT_PHONE_HOME))) {
-				bl->priv->supported_fields = g_list_append (bl->priv->supported_fields, g_strdup (e_contact_field_name (E_CONTACT_PHONE_HOME_2)));
+				bl->priv->supported_fields = g_slist_append (bl->priv->supported_fields, g_strdup (e_contact_field_name (E_CONTACT_PHONE_HOME_2)));
 			}
 			else if (!strcmp (query_prop, e_contact_field_name (E_CONTACT_CATEGORY_LIST) )) {
-				bl->priv->supported_fields = g_list_append (bl->priv->supported_fields, g_strdup (e_contact_field_name (E_CONTACT_CATEGORIES)));
+				bl->priv->supported_fields = g_slist_append (bl->priv->supported_fields, g_strdup (e_contact_field_name (E_CONTACT_CATEGORIES)));
 			}
 
 		}
@@ -622,7 +634,7 @@ check_schema_support (EBookBackendLDAP *bl)
 			   of draconian acl's that keep subschema
 			   reads from working until the user is
 			   authed. */
-			if (!e_book_backend_is_writable (E_BOOK_BACKEND (bl))) {
+			if (e_book_backend_is_readonly (E_BOOK_BACKEND (bl))) {
 				g_warning ("subschema read returned nothing before successful auth");
 				bl->priv->evolutionPersonChecked = FALSE;
 			}
@@ -756,20 +768,20 @@ query_ldap_root_dse (EBookBackendLDAP *bl)
 	if (values) {
 		gchar *auth_method;
 		if (bl->priv->supported_auth_methods) {
-			g_list_foreach (bl->priv->supported_auth_methods, (GFunc) g_free, NULL);
-			g_list_free (bl->priv->supported_auth_methods);
+			g_slist_foreach (bl->priv->supported_auth_methods, (GFunc) g_free, NULL);
+			g_slist_free (bl->priv->supported_auth_methods);
 		}
 		bl->priv->supported_auth_methods = NULL;
 
 		auth_method = g_strdup_printf ("ldap/simple-binddn|%s", _("Using Distinguished Name (DN)"));
-		bl->priv->supported_auth_methods = g_list_append (bl->priv->supported_auth_methods, auth_method);
+		bl->priv->supported_auth_methods = g_slist_append (bl->priv->supported_auth_methods, auth_method);
 
 		auth_method = g_strdup_printf ("ldap/simple-email|%s", _("Using Email Address"));
-		bl->priv->supported_auth_methods = g_list_append (bl->priv->supported_auth_methods, auth_method);
+		bl->priv->supported_auth_methods = g_slist_append (bl->priv->supported_auth_methods, auth_method);
 
 		for (i = 0; values[i]; i++) {
 			auth_method = g_strdup_printf ("sasl/%s|%s", values[i], values[i]);
-			bl->priv->supported_auth_methods = g_list_append (bl->priv->supported_auth_methods, auth_method);
+			bl->priv->supported_auth_methods = g_slist_append (bl->priv->supported_auth_methods, auth_method);
 			if (enable_debug)
 				g_message ("supported SASL mechanism: %s", values[i]);
 		}
@@ -964,7 +976,6 @@ e_book_backend_ldap_connect (EBookBackendLDAP *bl)
 		if (ldap_error == LDAP_SUCCESS
 		    || ldap_error == LDAP_PARTIAL_RESULTS
 		    || LDAP_NAME_ERROR (ldap_error)) {
-			e_book_backend_set_is_loaded (E_BOOK_BACKEND (bl), TRUE);
 			blpriv->connected = TRUE;
 			g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
 
@@ -984,7 +995,7 @@ e_book_backend_ldap_connect (EBookBackendLDAP *bl)
 			}
 			return EDB_ERROR (SUCCESS);
 		} else if (ldap_error == LDAP_UNWILLING_TO_PERFORM) {
-			e_book_backend_notify_auth_required (E_BOOK_BACKEND (bl));
+			e_book_backend_notify_auth_required (E_BOOK_BACKEND (bl), TRUE, NULL);
 			g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
 			return EDB_ERROR (AUTHENTICATION_REQUIRED);
 		} else {
@@ -1564,6 +1575,7 @@ static void
 e_book_backend_ldap_create_contact (EBookBackend *backend,
 				    EDataBook    *book,
 				    guint32       opid,
+				    GCancellable *cancellable,
 				    const gchar   *vcard)
 {
 	LDAPCreateOp *create_op = g_new0 (LDAPCreateOp, 1);
@@ -1575,128 +1587,123 @@ e_book_backend_ldap_create_contact (EBookBackend *backend,
 	LDAPMod **ldap_mods;
 	gchar *new_uid;
 
-	switch (bl->priv->mode) {
-
-	case E_DATA_BOOK_MODE_LOCAL :
+	if (!bl->priv->is_online) {
 		e_data_book_respond_create (book, opid, EDB_ERROR (REPOSITORY_OFFLINE), NULL);
 		return;
-	case E_DATA_BOOK_MODE_REMOTE :
+	}
 
-		g_static_rec_mutex_lock (&eds_ldap_handler_lock);
-		if (!bl->priv->ldap) {
-			g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
-			e_data_book_respond_create (book, opid, EDB_ERROR_NOT_CONNECTED (), NULL);
-			return;
-		}
+	g_static_rec_mutex_lock (&eds_ldap_handler_lock);
+	if (!bl->priv->ldap) {
 		g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
+		e_data_book_respond_create (book, opid, EDB_ERROR_NOT_CONNECTED (), NULL);
+		return;
+	}
+	g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
 
-		book_view = find_book_view (bl);
+	book_view = find_book_view (bl);
 
-		if (enable_debug)
-			printf ("Create Contact: vcard = %s\n", vcard);
+	if (enable_debug)
+		printf ("Create Contact: vcard = %s\n", vcard);
 
-		create_op->new_contact = e_contact_new_from_vcard (vcard);
+	create_op->new_contact = e_contact_new_from_vcard (vcard);
 
-		new_uid = create_dn_from_contact (create_op->new_contact, bl->priv->ldap_rootdn);
-		create_op->dn = create_full_dn_from_contact (new_uid, bl->priv->ldap_rootdn);
+	new_uid = create_dn_from_contact (create_op->new_contact, bl->priv->ldap_rootdn);
+	create_op->dn = create_full_dn_from_contact (new_uid, bl->priv->ldap_rootdn);
 
-		e_contact_set (create_op->new_contact, E_CONTACT_UID, create_op->dn);
+	e_contact_set (create_op->new_contact, E_CONTACT_UID, create_op->dn);
 
-		/* build our mods */
-		mod_array = build_mods_from_contacts (bl, NULL, create_op->new_contact, NULL, new_uid);
-		g_free (new_uid);
+	/* build our mods */
+	mod_array = build_mods_from_contacts (bl, NULL, create_op->new_contact, NULL, new_uid);
+	g_free (new_uid);
 
 #if 0
-		if (!mod_array) {
-			/* there's an illegal field in there.  report
-			   UnsupportedAttribute back */
-			e_data_book_respond_create (book,
-						    EDB_ERROR (UNSUPPORTED_FIELD),
-						    NULL);
+	if (!mod_array) {
+		/* there's an illegal field in there.  report
+		   UnsupportedAttribute back */
+		e_data_book_respond_create (book,
+					    EDB_ERROR (UNSUPPORTED_FIELD),
+					    NULL);
 
-			g_free (create_op->dn);
-			g_object_unref (create_op->new_contact);
-			g_free (create_op);
-			return;
-		}
+		g_free (create_op->dn);
+		g_object_unref (create_op->new_contact);
+		g_free (create_op);
+		return;
+	}
 #endif
 
-		/* remove the NULL at the end */
-		g_ptr_array_remove (mod_array, NULL);
+	/* remove the NULL at the end */
+	g_ptr_array_remove (mod_array, NULL);
 
-		/* add our objectclass(es) */
-		if (e_contact_get (create_op->new_contact, E_CONTACT_IS_LIST))
-			add_objectclass_mod (bl, mod_array, NULL, TRUE, FALSE);
-		else
-			add_objectclass_mod (bl, mod_array, NULL, FALSE, FALSE);
+	/* add our objectclass(es) */
+	if (e_contact_get (create_op->new_contact, E_CONTACT_IS_LIST))
+		add_objectclass_mod (bl, mod_array, NULL, TRUE, FALSE);
+	else
+		add_objectclass_mod (bl, mod_array, NULL, FALSE, FALSE);
 
-		/* then put the NULL back */
-		g_ptr_array_add (mod_array, NULL);
+	/* then put the NULL back */
+	g_ptr_array_add (mod_array, NULL);
 
 #ifdef LDAP_DEBUG_ADD
-		if (enable_debug) {
-			gint i;
-			printf ("Sending the following to the server as ADD\n");
-			printf ("Adding DN: %s\n", create_op->dn);
-
-			for (i = 0; g_ptr_array_index (mod_array, i); i++) {
-				LDAPMod *mod = g_ptr_array_index (mod_array, i);
-				if (mod->mod_op & LDAP_MOD_DELETE)
-					printf ("del ");
-				else if (mod->mod_op & LDAP_MOD_REPLACE)
-					printf ("rep ");
-				else
-					printf ("add ");
-				if (mod->mod_op & LDAP_MOD_BVALUES)
-					printf ("ber ");
-				else
-					printf ("    ");
+	if (enable_debug) {
+		gint i;
+		printf ("Sending the following to the server as ADD\n");
+		printf ("Adding DN: %s\n", create_op->dn);
+
+		for (i = 0; g_ptr_array_index (mod_array, i); i++) {
+			LDAPMod *mod = g_ptr_array_index (mod_array, i);
+			if (mod->mod_op & LDAP_MOD_DELETE)
+				printf ("del ");
+			else if (mod->mod_op & LDAP_MOD_REPLACE)
+				printf ("rep ");
+			else
+				printf ("add ");
+			if (mod->mod_op & LDAP_MOD_BVALUES)
+				printf ("ber ");
+			else
+				printf ("    ");
 
-				printf (" %s:\n", mod->mod_type);
+			printf (" %s:\n", mod->mod_type);
 
-				if (mod->mod_op & LDAP_MOD_BVALUES) {
-					gint j;
-					for (j = 0; mod->mod_bvalues[j] && mod->mod_bvalues[j]->bv_val; j++)
-						printf ("\t\t'%s'\n", mod->mod_bvalues[j]->bv_val);
-				}
-				else {
-					gint j;
+			if (mod->mod_op & LDAP_MOD_BVALUES) {
+				gint j;
+				for (j = 0; mod->mod_bvalues[j] && mod->mod_bvalues[j]->bv_val; j++)
+					printf ("\t\t'%s'\n", mod->mod_bvalues[j]->bv_val);
+			} else {
+				gint j;
 
-					for (j = 0; mod->mod_values[j]; j++)
-						printf ("\t\t'%s'\n", mod->mod_values[j]);
-				}
+				for (j = 0; mod->mod_values[j]; j++)
+					printf ("\t\t'%s'\n", mod->mod_values[j]);
 			}
 		}
+	}
 #endif
 
-		ldap_mods = (LDAPMod**) mod_array->pdata;
+	ldap_mods = (LDAPMod**) mod_array->pdata;
 
-		do {
-			book_view_notify_status (bl, book_view, _("Adding contact to LDAP server..."));
-			g_static_rec_mutex_lock (&eds_ldap_handler_lock);
-			err = ldap_add_ext (bl->priv->ldap, create_op->dn, ldap_mods,
-					    NULL, NULL, &create_contact_msgid);
-			g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
+	do {
+		book_view_notify_status (bl, book_view, _("Adding contact to LDAP server..."));
+		g_static_rec_mutex_lock (&eds_ldap_handler_lock);
+		err = ldap_add_ext (bl->priv->ldap, create_op->dn, ldap_mods,
+				    NULL, NULL, &create_contact_msgid);
+		g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
 
-		} while (e_book_backend_ldap_reconnect (bl, book_view, err));
+	} while (e_book_backend_ldap_reconnect (bl, book_view, err));
 
-		/* and clean up */
-		free_mods (mod_array);
+	/* and clean up */
+	free_mods (mod_array);
 
-		if (LDAP_SUCCESS != err) {
-			e_data_book_respond_create (create_op->op.book,
-						    opid,
-						    ldap_error_to_response (err),
-						    NULL);
-			create_contact_dtor ((LDAPOp*) create_op);
-			return;
-		}
-		else {
-			g_print ("ldap_add_ext returned %d\n", err);
-			ldap_op_add ((LDAPOp*) create_op, backend, book,
-				     book_view, opid, create_contact_msgid,
-				     create_contact_handler, create_contact_dtor);
-		}
+	if (LDAP_SUCCESS != err) {
+		e_data_book_respond_create (create_op->op.book,
+					    opid,
+					    ldap_error_to_response (err),
+					    NULL);
+		create_contact_dtor ((LDAPOp*) create_op);
+		return;
+	} else {
+		g_print ("ldap_add_ext returned %d\n", err);
+		ldap_op_add ((LDAPOp*) create_op, backend, book,
+			     book_view, opid, create_contact_msgid,
+			     create_contact_handler, create_contact_dtor);
 	}
 }
 
@@ -1712,7 +1719,7 @@ remove_contact_handler (LDAPOp *op, LDAPMessage *res)
 	EBookBackendLDAP *bl = E_BOOK_BACKEND_LDAP (op->backend);
 	gchar *ldap_error_msg;
 	gint ldap_error;
-	GList *ids = NULL;
+	GSList *ids = NULL;
 
 	g_static_rec_mutex_lock (&eds_ldap_handler_lock);
 	if (!bl->priv->ldap) {
@@ -1748,12 +1755,12 @@ remove_contact_handler (LDAPOp *op, LDAPMessage *res)
 
 	ldap_memfree (ldap_error_msg);
 
-	ids = g_list_append (ids, remove_op->id);
+	ids = g_slist_append (ids, remove_op->id);
 	e_data_book_respond_remove_contacts (remove_op->op.book,
 					     op->opid,
 					     ldap_error_to_response (ldap_error),
 					     ldap_error == LDAP_SUCCESS ? ids : NULL);
-	g_list_free (ids);
+	g_slist_free (ids);
 	ldap_op_finished (op);
 }
 
@@ -1770,7 +1777,8 @@ static void
 e_book_backend_ldap_remove_contacts (EBookBackend *backend,
 				     EDataBook    *book,
 				     guint32       opid,
-				     GList        *ids)
+				     GCancellable *cancellable,
+				     const GSList *ids)
 {
 	LDAPRemoveOp *remove_op = g_new (LDAPRemoveOp, 1);
 	EBookBackendLDAP *bl = E_BOOK_BACKEND_LDAP (backend);
@@ -1778,59 +1786,54 @@ e_book_backend_ldap_remove_contacts (EBookBackend *backend,
 	gint remove_msgid;
 	gint ldap_error;
 
-	switch (bl->priv->mode) {
-
-	case E_DATA_BOOK_MODE_LOCAL :
+	if (!bl->priv->is_online) {
 		e_data_book_respond_remove_contacts (book, opid, EDB_ERROR (REPOSITORY_OFFLINE), NULL);
 		g_free (remove_op);
 		return;
-	case E_DATA_BOOK_MODE_REMOTE :
-		g_static_rec_mutex_lock (&eds_ldap_handler_lock);
-		if (!bl->priv->ldap) {
-			g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
-			e_data_book_respond_remove_contacts (book, opid, EDB_ERROR_NOT_CONNECTED (), NULL);
-			g_free (remove_op);
-			return;
-		}
+	}
+
+	g_static_rec_mutex_lock (&eds_ldap_handler_lock);
+	if (!bl->priv->ldap) {
 		g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
+		e_data_book_respond_remove_contacts (book, opid, EDB_ERROR_NOT_CONNECTED (), NULL);
+		g_free (remove_op);
+		return;
+	}
+	g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
 
-		book_view = find_book_view (bl);
+	book_view = find_book_view (bl);
 
-		/*
-		** since we didn't pass "bulk-removes" in our static
-		** capabilities, we should only get 1 length lists here, so
-		** the id we're deleting is the first and only id in the list.
-		*/
-		remove_op->id = g_strdup (ids->data);
+	/*
+	** since we didn't pass "bulk-removes" in our static
+	** capabilities, we should only get 1 length lists here, so
+	** the id we're deleting is the first and only id in the list.
+	*/
+	remove_op->id = g_strdup (ids->data);
 
-		do {
-			book_view_notify_status (bl, book_view, _("Removing contact from LDAP server..."));
+	do {
+		book_view_notify_status (bl, book_view, _("Removing contact from LDAP server..."));
 
-			g_static_rec_mutex_lock (&eds_ldap_handler_lock);
-			ldap_error = ldap_delete_ext (bl->priv->ldap,
-						      remove_op->id,
-						      NULL, NULL, &remove_msgid);
-			g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
-		} while (e_book_backend_ldap_reconnect (bl, book_view, ldap_error));
+		g_static_rec_mutex_lock (&eds_ldap_handler_lock);
+		ldap_error = ldap_delete_ext (bl->priv->ldap,
+					      remove_op->id,
+					      NULL, NULL, &remove_msgid);
+		g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
+	} while (e_book_backend_ldap_reconnect (bl, book_view, ldap_error));
 
-		if (ldap_error != LDAP_SUCCESS) {
-			e_data_book_respond_remove_contacts (remove_op->op.book,
-							     opid,
-							     ldap_error_to_response (ldap_error),
-							     NULL);
-			ldap_op_finished ((LDAPOp*) remove_op);
-			remove_contact_dtor ((LDAPOp*) remove_op);
-			return;
-		}
-		else {
-			g_print ("ldap_delete_ext returned %d\n", ldap_error);
-			ldap_op_add ((LDAPOp*) remove_op, backend, book,
-				     book_view, opid, remove_msgid,
-				     remove_contact_handler, remove_contact_dtor);
-		}
-		break;
+	if (ldap_error != LDAP_SUCCESS) {
+		e_data_book_respond_remove_contacts (remove_op->op.book,
+						     opid,
+						     ldap_error_to_response (ldap_error),
+						     NULL);
+		ldap_op_finished ((LDAPOp*) remove_op);
+		remove_contact_dtor ((LDAPOp*) remove_op);
+		return;
+	} else {
+		g_print ("ldap_delete_ext returned %d\n", ldap_error);
+		ldap_op_add ((LDAPOp*) remove_op, backend, book,
+			     book_view, opid, remove_msgid,
+			     remove_contact_handler, remove_contact_dtor);
 	}
-
 }
 
 /*
@@ -2209,6 +2212,7 @@ static void
 e_book_backend_ldap_modify_contact (EBookBackend *backend,
 				    EDataBook    *book,
 				    guint32       opid,
+				    GCancellable *cancellable,
 				    const gchar   *vcard)
 {
 	LDAPModifyOp *modify_op = g_new0 (LDAPModifyOp, 1);
@@ -2217,54 +2221,51 @@ e_book_backend_ldap_modify_contact (EBookBackend *backend,
 	gint modify_contact_msgid;
 	EDataBookView *book_view;
 
-	switch (bl->priv->mode) {
-
-	case E_DATA_BOOK_MODE_LOCAL :
+	if (!bl->priv->is_online) {
 		e_data_book_respond_modify (book, opid, EDB_ERROR (REPOSITORY_OFFLINE), NULL);
 		return;
-	case E_DATA_BOOK_MODE_REMOTE :
-		g_static_rec_mutex_lock (&eds_ldap_handler_lock);
-		if (!bl->priv->ldap) {
-			g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
-			e_data_book_respond_modify (book, opid, EDB_ERROR_NOT_CONNECTED (), NULL);
-			g_free (modify_op);
-			return;
-		}
+	}
+
+	g_static_rec_mutex_lock (&eds_ldap_handler_lock);
+	if (!bl->priv->ldap) {
 		g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
+		e_data_book_respond_modify (book, opid, EDB_ERROR_NOT_CONNECTED (), NULL);
+		g_free (modify_op);
+		return;
+	}
+	g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
 
-		book_view = find_book_view (bl);
+	book_view = find_book_view (bl);
 
-		if (enable_debug)
-			printf ("Modify Contact: vcard = %s\n", vcard);
-		modify_op->contact = e_contact_new_from_vcard (vcard);
-		modify_op->id = e_contact_get_const (modify_op->contact, E_CONTACT_UID);
+	if (enable_debug)
+		printf ("Modify Contact: vcard = %s\n", vcard);
+	modify_op->contact = e_contact_new_from_vcard (vcard);
+	modify_op->id = e_contact_get_const (modify_op->contact, E_CONTACT_UID);
 
-		do {
-			book_view_notify_status (bl, book_view, _("Modifying contact from LDAP server..."));
+	do {
+		book_view_notify_status (bl, book_view, _("Modifying contact from LDAP server..."));
 
-			g_static_rec_mutex_lock (&eds_ldap_handler_lock);
-			ldap_error = ldap_search_ext (bl->priv->ldap, modify_op->id,
-						      LDAP_SCOPE_BASE,
-						      "(objectclass=*)",
-						      NULL, 0, NULL, NULL,
-						      NULL, /* XXX timeout */
-						      1, &modify_contact_msgid);
-			g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
+		g_static_rec_mutex_lock (&eds_ldap_handler_lock);
+		ldap_error = ldap_search_ext (bl->priv->ldap, modify_op->id,
+					      LDAP_SCOPE_BASE,
+					      "(objectclass=*)",
+					      NULL, 0, NULL, NULL,
+					      NULL, /* XXX timeout */
+					      1, &modify_contact_msgid);
+		g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
 
-		} while (e_book_backend_ldap_reconnect (bl, book_view, ldap_error));
+	} while (e_book_backend_ldap_reconnect (bl, book_view, ldap_error));
 
-		if (ldap_error == LDAP_SUCCESS) {
-			ldap_op_add ((LDAPOp*) modify_op, backend, book,
-				     book_view, opid, modify_contact_msgid,
-				     modify_contact_search_handler, modify_contact_dtor);
-		}
-		else {
-			e_data_book_respond_modify (book,
-						    opid,
-						    ldap_error_to_response (ldap_error),
-						    NULL);
-			modify_contact_dtor ((LDAPOp*) modify_op);
-		}
+	if (ldap_error == LDAP_SUCCESS) {
+		ldap_op_add ((LDAPOp*) modify_op, backend, book,
+			     book_view, opid, modify_contact_msgid,
+			     modify_contact_search_handler, modify_contact_dtor);
+	} else {
+		e_data_book_respond_modify (book,
+					    opid,
+					    ldap_error_to_response (ldap_error),
+					    NULL);
+		modify_contact_dtor ((LDAPOp*) modify_op);
 	}
 }
 
@@ -2381,6 +2382,7 @@ static void
 e_book_backend_ldap_get_contact (EBookBackend *backend,
 				 EDataBook    *book,
 				 guint32       opid,
+				 GCancellable *cancellable,
 				 const gchar   *id)
 {
 	LDAPGetContactOp *get_contact_op;
@@ -2391,9 +2393,7 @@ e_book_backend_ldap_get_contact (EBookBackend *backend,
 	GTimeVal start, end;
 	gulong diff;
 
-	switch (bl->priv->mode) {
-
-	case E_DATA_BOOK_MODE_LOCAL :
+	if (!bl->priv->is_online) {
 		if (bl->priv->marked_for_offline && bl->priv->cache) {
 			EContact *contact = e_book_backend_cache_get_contact (bl->priv->cache, id);
 			gchar *vcard_str;
@@ -2416,65 +2416,62 @@ e_book_backend_ldap_get_contact (EBookBackend *backend,
 
 		e_data_book_respond_get_contact(book, opid, EDB_ERROR (REPOSITORY_OFFLINE), "");
 		return;
+	}
 
-	case E_DATA_BOOK_MODE_REMOTE :
-
-		if (enable_debug) {
-			printf("e_book_backend_ldap_get_contact ... \n");
-			g_get_current_time (&start);
-		}
+	if (enable_debug) {
+		printf("e_book_backend_ldap_get_contact ... \n");
+		g_get_current_time (&start);
+	}
 
-		g_static_rec_mutex_lock (&eds_ldap_handler_lock);
-		if (!bl->priv->ldap) {
-			g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
-			e_data_book_respond_get_contact (book, opid, EDB_ERROR_NOT_CONNECTED (), "");
-			if (enable_debug)
-				printf("e_book_backend_ldap_get_contact ... ldap handler is NULL\n");
-			return;
-		}
+	g_static_rec_mutex_lock (&eds_ldap_handler_lock);
+	if (!bl->priv->ldap) {
 		g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
+		e_data_book_respond_get_contact (book, opid, EDB_ERROR_NOT_CONNECTED (), "");
+		if (enable_debug)
+			printf("e_book_backend_ldap_get_contact ... ldap handler is NULL\n");
+		return;
+	}
+	g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
 
-		get_contact_op = g_new0 (LDAPGetContactOp, 1);
-		book_view = find_book_view (bl);
+	get_contact_op = g_new0 (LDAPGetContactOp, 1);
+	book_view = find_book_view (bl);
 
-		do {
-			g_static_rec_mutex_lock (&eds_ldap_handler_lock);
-			ldap_error = ldap_search_ext (bl->priv->ldap, id,
-						      LDAP_SCOPE_BASE,
-						      "(objectclass=*)",
-						      NULL, 0, NULL, NULL,
-						      NULL, /* XXX timeout */
-						      1, &get_contact_msgid);
-			g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
-		} while (e_book_backend_ldap_reconnect (bl, book_view, ldap_error));
+	do {
+		g_static_rec_mutex_lock (&eds_ldap_handler_lock);
+		ldap_error = ldap_search_ext (bl->priv->ldap, id,
+					      LDAP_SCOPE_BASE,
+					      "(objectclass=*)",
+					      NULL, 0, NULL, NULL,
+					      NULL, /* XXX timeout */
+					      1, &get_contact_msgid);
+		g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
+	} while (e_book_backend_ldap_reconnect (bl, book_view, ldap_error));
 
-		if (ldap_error == LDAP_SUCCESS) {
-			ldap_op_add ((LDAPOp*) get_contact_op, backend, book,
-				     book_view, opid, get_contact_msgid,
-				     get_contact_handler, get_contact_dtor);
+	if (ldap_error == LDAP_SUCCESS) {
+		ldap_op_add ((LDAPOp*) get_contact_op, backend, book,
+			     book_view, opid, get_contact_msgid,
+			     get_contact_handler, get_contact_dtor);
 
-			if (enable_debug) {
-				printf("e_book_backend_ldap_get_contact invoked get_contact_handler\n");
-				g_get_current_time (&end);
-				diff = end.tv_sec * 1000 + end.tv_usec/1000;
-				diff -= start.tv_sec * 1000 + start.tv_usec/1000;
-				printf("and took %ld.%03ld seconds\n",
-							diff/1000, diff%1000);
-			}
-		}
-		else {
-			e_data_book_respond_get_contact (book,
-							 opid,
-							 ldap_error_to_response (ldap_error),
-							 "");
-			get_contact_dtor ((LDAPOp*) get_contact_op);
+		if (enable_debug) {
+			printf("e_book_backend_ldap_get_contact invoked get_contact_handler\n");
+			g_get_current_time (&end);
+			diff = end.tv_sec * 1000 + end.tv_usec/1000;
+			diff -= start.tv_sec * 1000 + start.tv_usec/1000;
+			printf("and took %ld.%03ld seconds\n",
+						diff/1000, diff%1000);
 		}
+	} else {
+		e_data_book_respond_get_contact (book,
+						 opid,
+						 ldap_error_to_response (ldap_error),
+						 "");
+		get_contact_dtor ((LDAPOp*) get_contact_op);
 	}
 }
 
 typedef struct {
 	LDAPOp op;
-	GList *contacts;
+	GSList *contacts;
 } LDAPGetContactListOp;
 
 static void
@@ -2520,8 +2517,7 @@ contact_list_handler (LDAPOp *op, LDAPMessage *res)
 			if (enable_debug)
 				printf ("vcard = %s\n", vcard);
 
-			contact_list_op->contacts = g_list_append (contact_list_op->contacts,
-								   vcard);
+			contact_list_op->contacts = g_slist_append (contact_list_op->contacts, vcard);
 
 			g_object_unref (contact);
 
@@ -2593,6 +2589,9 @@ contact_list_dtor (LDAPOp *op)
 {
 	LDAPGetContactListOp *contact_list_op = (LDAPGetContactListOp*) op;
 
+	g_slist_foreach (contact_list_op->contacts, (GFunc) g_free, NULL);
+	g_slist_free (contact_list_op->contacts);
+
 	g_free (contact_list_op);
 }
 
@@ -2600,6 +2599,7 @@ static void
 e_book_backend_ldap_get_contact_list (EBookBackend *backend,
 				      EDataBook    *book,
 				      guint32       opid,
+				      GCancellable *cancellable,
 				      const gchar   *query)
 {
 	LDAPGetContactListOp *contact_list_op;
@@ -2616,85 +2616,83 @@ e_book_backend_ldap_get_contact_list (EBookBackend *backend,
 		g_get_current_time (&start);
 	}
 
-	switch (bl->priv->mode) {
-
-	case E_DATA_BOOK_MODE_LOCAL :
+	if (!bl->priv->is_online) {
 		if (bl->priv->marked_for_offline && bl->priv->cache) {
 			GList *contacts;
-			GList *vcard_strings = NULL;
+			GSList *vcard_strings = NULL;
 			GList *l;
 
 			contacts = e_book_backend_cache_get_contacts (bl->priv->cache, query);
 
 			for (l = contacts; l; l = g_list_next (l)) {
 				EContact *contact = l->data;
-				vcard_strings = g_list_prepend (vcard_strings, e_vcard_to_string (E_VCARD (contact),
-								EVC_FORMAT_VCARD_30));
+				vcard_strings = g_slist_prepend (vcard_strings, e_vcard_to_string (E_VCARD (contact),
+								 EVC_FORMAT_VCARD_30));
 				g_object_unref (contact);
 			}
 
 			g_list_free (contacts);
 			e_data_book_respond_get_contact_list (book, opid, EDB_ERROR (SUCCESS), vcard_strings);
+			g_slist_foreach (vcard_strings, (GFunc) g_free, NULL);
+			g_slist_free (vcard_strings);
 			return;
 		}
 
 		e_data_book_respond_get_contact_list (book, opid, EDB_ERROR (REPOSITORY_OFFLINE), NULL);
 		return;
+	}
 
-	case E_DATA_BOOK_MODE_REMOTE:
-		g_static_rec_mutex_lock (&eds_ldap_handler_lock);
-		if (!bl->priv->ldap) {
-			g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
-			e_data_book_respond_get_contact_list (book, opid, EDB_ERROR_NOT_CONNECTED (), NULL);
-			if (enable_debug)
-				printf ("e_book_backend_ldap_get_contact_list... ldap handler is NULL\n");
-			return;
-		}
+	g_static_rec_mutex_lock (&eds_ldap_handler_lock);
+	if (!bl->priv->ldap) {
 		g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
+		e_data_book_respond_get_contact_list (book, opid, EDB_ERROR_NOT_CONNECTED (), NULL);
+		if (enable_debug)
+			printf ("e_book_backend_ldap_get_contact_list... ldap handler is NULL\n");
+		return;
+	}
+	g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
 
-		contact_list_op = g_new0 (LDAPGetContactListOp, 1);
-		book_view = find_book_view (bl);
+	contact_list_op = g_new0 (LDAPGetContactListOp, 1);
+	book_view = find_book_view (bl);
 
-		ldap_query = e_book_backend_ldap_build_query (bl, query);
+	ldap_query = e_book_backend_ldap_build_query (bl, query);
 
-		if (enable_debug)
-			printf ("getting contact list with filter: %s\n", ldap_query);
+	if (enable_debug)
+		printf ("getting contact list with filter: %s\n", ldap_query);
 
-		do {
-			g_static_rec_mutex_lock (&eds_ldap_handler_lock);
-			ldap_error = ldap_search_ext (bl->priv->ldap,
-						      bl->priv->ldap_rootdn,
-						      bl->priv->ldap_scope,
-						      ldap_query,
-						      NULL, 0, NULL, NULL,
-						      NULL, /* XXX timeout */
-						      LDAP_NO_LIMIT, &contact_list_msgid);
-			g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
-		} while (e_book_backend_ldap_reconnect (bl, book_view, ldap_error));
+	do {
+		g_static_rec_mutex_lock (&eds_ldap_handler_lock);
+		ldap_error = ldap_search_ext (bl->priv->ldap,
+					      bl->priv->ldap_rootdn,
+					      bl->priv->ldap_scope,
+					      ldap_query,
+					      NULL, 0, NULL, NULL,
+					      NULL, /* XXX timeout */
+					      LDAP_NO_LIMIT, &contact_list_msgid);
+		g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
+	} while (e_book_backend_ldap_reconnect (bl, book_view, ldap_error));
 
-		g_free (ldap_query);
+	g_free (ldap_query);
 
-		if (ldap_error == LDAP_SUCCESS) {
-			ldap_op_add ((LDAPOp*) contact_list_op, backend, book,
-				     book_view, opid, contact_list_msgid,
-				     contact_list_handler, contact_list_dtor);
-			if (enable_debug) {
-				g_get_current_time (&end);
+	if (ldap_error == LDAP_SUCCESS) {
+		ldap_op_add ((LDAPOp*) contact_list_op, backend, book,
+			     book_view, opid, contact_list_msgid,
+			     contact_list_handler, contact_list_dtor);
+		if (enable_debug) {
+			g_get_current_time (&end);
 
-				diff = end.tv_sec * 1000 + end.tv_usec/1000;
-				diff -= start.tv_sec * 1000 + start.tv_usec/1000;
+			diff = end.tv_sec * 1000 + end.tv_usec/1000;
+			diff -= start.tv_sec * 1000 + start.tv_usec/1000;
 
-				printf ("e_book_backend_ldap_get_contact_list invoked contact_list_handler ");
-				printf ("and took %ld.%03ld seconds\n", diff/1000, diff%1000);
-			}
-		}
-		else {
-			e_data_book_respond_get_contact_list (book,
-							      opid,
-							      ldap_error_to_response (ldap_error),
-							      NULL);
-			contact_list_dtor ((LDAPOp*) contact_list_op);
+			printf ("e_book_backend_ldap_get_contact_list invoked contact_list_handler ");
+			printf ("and took %ld.%03ld seconds\n", diff/1000, diff%1000);
 		}
+	} else {
+		e_data_book_respond_get_contact_list (book,
+						      opid,
+						      ldap_error_to_response (ldap_error),
+						      NULL);
+		contact_list_dtor ((LDAPOp*) contact_list_op);
 	}
 }
 
@@ -4172,8 +4170,6 @@ build_contact_from_entry (EBookBackendLDAP *bl,
 							/* get the e-mail id for each member and add them to the list */
 
 							book_view = find_book_view (bl);
-							if (book_view)
-								view_limit = e_data_book_view_get_max_results (book_view);
 							if (view_limit == -1 || view_limit > bl->priv->ldap_limit)
 								view_limit = bl->priv->ldap_limit;
 
@@ -4457,8 +4453,7 @@ e_book_backend_ldap_search (EBookBackendLDAP *bl,
 		g_get_current_time (&start);
 	}
 
-	switch (bl->priv->mode) {
-	case E_DATA_BOOK_MODE_LOCAL :
+	if (!bl->priv->is_online) {
 		if (!(bl->priv->marked_for_offline && bl->priv->cache)) {
 			GError *edb_err = EDB_ERROR (REPOSITORY_OFFLINE);
 			e_data_book_view_notify_complete (view, edb_err);
@@ -4479,86 +4474,82 @@ e_book_backend_ldap_search (EBookBackendLDAP *bl,
 
 		e_data_book_view_notify_complete (view, NULL /* Success */);
 		return;
+	}
 
-	case E_DATA_BOOK_MODE_REMOTE :
-		ldap_query = e_book_backend_ldap_build_query (bl, e_data_book_view_get_card_query (view));
+	ldap_query = e_book_backend_ldap_build_query (bl, e_data_book_view_get_card_query (view));
 
-		/* search for nonempty full names */
-		if (!ldap_query && can_browse ((EBookBackend *) bl))
-			ldap_query = g_strdup ("(cn=*)");
+	/* search for nonempty full names */
+	if (!ldap_query && can_browse ((EBookBackend *) bl))
+		ldap_query = g_strdup ("(cn=*)");
 
-		g_static_rec_mutex_lock (&eds_ldap_handler_lock);
-		if (ldap_query != NULL && bl->priv->ldap) {
-			gint ldap_err;
-			gint search_msgid;
-			gint view_limit;
+	g_static_rec_mutex_lock (&eds_ldap_handler_lock);
+	if (ldap_query != NULL && bl->priv->ldap) {
+		gint ldap_err;
+		gint search_msgid;
+		gint view_limit;
 
-			g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
+		g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
 
-			view_limit = e_data_book_view_get_max_results (view);
-			if (view_limit == -1 || view_limit > bl->priv->ldap_limit)
-				view_limit = bl->priv->ldap_limit;
+		view_limit = -1;
+		if (view_limit == -1 || view_limit > bl->priv->ldap_limit)
+			view_limit = bl->priv->ldap_limit;
 
-			if (enable_debug)
-				printf ("searching server using filter: %s (expecting max %d results)\n", ldap_query, view_limit);
+		if (enable_debug)
+			printf ("searching server using filter: %s (expecting max %d results)\n", ldap_query, view_limit);
 
-			do {
-				book_view_notify_status (bl, view, _("Searching..."));
+		do {
+			book_view_notify_status (bl, view, _("Searching..."));
 
-				g_static_rec_mutex_lock (&eds_ldap_handler_lock);
-				ldap_err = ldap_search_ext (bl->priv->ldap, bl->priv->ldap_rootdn,
-							    bl->priv->ldap_scope,
-							    ldap_query,
-							    NULL, 0,
-							    NULL, /* XXX */
-							    NULL, /* XXX */
-							    NULL, /* XXX timeout */
-							    view_limit, &search_msgid);
-				g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
-			} while (e_book_backend_ldap_reconnect (bl, view, ldap_err));
+			g_static_rec_mutex_lock (&eds_ldap_handler_lock);
+			ldap_err = ldap_search_ext (bl->priv->ldap, bl->priv->ldap_rootdn,
+						    bl->priv->ldap_scope,
+						    ldap_query,
+						    NULL, 0,
+						    NULL, /* XXX */
+						    NULL, /* XXX */
+						    NULL, /* XXX timeout */
+						    view_limit, &search_msgid);
+			g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
+		} while (e_book_backend_ldap_reconnect (bl, view, ldap_err));
 
-			g_free (ldap_query);
+		g_free (ldap_query);
 
-			if (ldap_err != LDAP_SUCCESS) {
-				book_view_notify_status (bl, view, ldap_err2string (ldap_err));
-				return;
-			}
-			else if (search_msgid == -1) {
-				book_view_notify_status (bl, view,
-							 _("Error performing search"));
-				return;
-			}
-			else {
-				LDAPSearchOp *op = g_new0 (LDAPSearchOp, 1);
+		if (ldap_err != LDAP_SUCCESS) {
+			book_view_notify_status (bl, view, ldap_err2string (ldap_err));
+			return;
+		} else if (search_msgid == -1) {
+			book_view_notify_status (bl, view,
+						 _("Error performing search"));
+			return;
+		} else {
+			LDAPSearchOp *op = g_new0 (LDAPSearchOp, 1);
 
-				d(printf ("adding search_op (%p, %d)\n", view, search_msgid));
+			d(printf ("adding search_op (%p, %d)\n", view, search_msgid));
 
-				op->view = view;
-				op->aborted = FALSE;
-				e_data_book_view_ref (view);
+			op->view = view;
+			op->aborted = FALSE;
+			e_data_book_view_ref (view);
 
-				ldap_op_add ((LDAPOp*) op, E_BOOK_BACKEND (bl), book, view,
-					     0, search_msgid,
-					     ldap_search_handler, ldap_search_dtor);
+			ldap_op_add ((LDAPOp*) op, E_BOOK_BACKEND (bl), book, view,
+				     0, search_msgid,
+				     ldap_search_handler, ldap_search_dtor);
 
-				if (enable_debug) {
-					printf ("e_book_backend_ldap_search invoked ldap_search_handler ");
-					g_get_current_time (&end);
-					diff = end.tv_sec * 1000 + end.tv_usec/1000;
-					diff -= start.tv_sec * 1000 + start.tv_usec/1000;
-					printf("and took  %ld.%03ld seconds\n", diff/1000,diff%1000);
-				}
-
-				g_object_set_data (G_OBJECT (view), "EBookBackendLDAP.BookView::search_op", op);
+			if (enable_debug) {
+				printf ("e_book_backend_ldap_search invoked ldap_search_handler ");
+				g_get_current_time (&end);
+				diff = end.tv_sec * 1000 + end.tv_usec/1000;
+				diff -= start.tv_sec * 1000 + start.tv_usec/1000;
+				printf("and took  %ld.%03ld seconds\n", diff/1000,diff%1000);
 			}
-			return;
-		}
-		else {
-			g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
-			/* Ignore NULL query */
-			e_data_book_view_notify_complete (view, NULL /* Success */);
-			return;
+
+			g_object_set_data (G_OBJECT (view), "EBookBackendLDAP.BookView::search_op", op);
 		}
+		return;
+	} else {
+		g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
+		/* Ignore NULL query */
+		e_data_book_view_notify_complete (view, NULL /* Success */);
+		return;
 	}
 }
 
@@ -4570,11 +4561,6 @@ e_book_backend_ldap_start_book_view (EBookBackend  *backend,
 
 	d(printf ("start_book_view (%p)\n", view));
 
-	/* we start at 1 so the user sees stuff as it appears and we
-	   aren't left waiting for more cards to show up, if the
-	   connection is slow. */
-	e_data_book_view_set_thresholds (view, 1, 3000);
-
 	e_book_backend_ldap_search (bl, NULL /* XXX ugh */, view);
 }
 
@@ -4594,15 +4580,6 @@ e_book_backend_ldap_stop_book_view (EBookBackend  *backend,
 	}
 }
 
-static void
-e_book_backend_ldap_get_changes (EBookBackend *backend,
-				 EDataBook    *book,
-				 guint32       opid,
-				 const gchar   *change_id)
-{
-	/* FIXME: implement */
-}
-
 #define LDAP_SIMPLE_PREFIX "ldap/simple-"
 #define SASL_PREFIX "sasl/"
 
@@ -4643,21 +4620,21 @@ generate_cache_handler (LDAPOp *op, LDAPMessage *res)
 		while (e != NULL) {
 			EContact *contact = build_contact_from_entry (bl, e, NULL, NULL);
 
-			contact_list_op->contacts = g_list_prepend (contact_list_op->contacts, contact);
+			contact_list_op->contacts = g_slist_prepend (contact_list_op->contacts, contact);
 
 			g_static_rec_mutex_lock (&eds_ldap_handler_lock);
 			e = ldap_next_entry (bl->priv->ldap, e);
 			g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
 		}
 	} else {
-		GList *l;
+		GSList *l;
 		gint contact_num = 0;
 		gchar *status_msg;
 
 		e_file_cache_clean (E_FILE_CACHE (bl->priv->cache));
 
 		e_file_cache_freeze_changes (E_FILE_CACHE (bl->priv->cache));
-		for (l = contact_list_op->contacts; l; l = g_list_next (l)) {
+		for (l = contact_list_op->contacts; l; l = g_slist_next (l)) {
 			EContact *contact = l->data;
 
 			contact_num++;
@@ -4688,13 +4665,13 @@ static void
 generate_cache_dtor (LDAPOp *op)
 {
 	LDAPGetContactListOp *contact_list_op = (LDAPGetContactListOp *) op;
-	GList *l;
+	GSList *l;
 
-	for (l = contact_list_op->contacts; l; l = g_list_next (l)) {
+	for (l = contact_list_op->contacts; l; l = g_slist_next (l)) {
 		g_object_unref (l->data);
 	}
 
-	g_list_free (contact_list_op->contacts);
+	g_slist_free (contact_list_op->contacts);
 	g_free (contact_list_op);
 }
 
@@ -4755,33 +4732,30 @@ generate_cache (EBookBackendLDAP *book_backend_ldap)
 
 static void
 e_book_backend_ldap_authenticate_user (EBookBackend *backend,
-				       EDataBook    *book,
-				       guint32       opid,
-				       const gchar   *user,
-				       const gchar   *passwd,
-				       const gchar   *auth_method)
+				       GCancellable *cancellable,
+				       ECredentials *credentials)
 {
 	EBookBackendLDAP *bl = E_BOOK_BACKEND_LDAP (backend);
 	gint ldap_error;
 	gchar *dn = NULL;
+	const gchar *auth_method = e_credentials_peek (credentials, E_CREDENTIALS_KEY_AUTH_METHOD);
+	const gchar *user = e_credentials_peek (credentials, E_CREDENTIALS_KEY_USERNAME);
 
 	if (enable_debug)
 		printf ("e_book_backend_ldap_authenticate_user ... \n");
 
 	g_static_rec_mutex_lock (&eds_ldap_handler_lock);
-	if (bl->priv->mode == E_DATA_BOOK_MODE_LOCAL) {
-		e_book_backend_notify_writable (backend, FALSE);
-		e_book_backend_notify_connection_status (backend, FALSE);
-		e_data_book_respond_authenticate_user (book,
-						       opid,
-						       EDB_ERROR (SUCCESS));
+	if (!bl->priv->is_online) {
+		e_book_backend_notify_readonly (backend, TRUE);
+		e_book_backend_notify_online (backend, FALSE);
+		e_book_backend_notify_opened (backend, EDB_ERROR (SUCCESS));
 		g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
 		return;
 	}
 
 	if (bl->priv->connected) {
 		/* other client connected meanwhile, report success and return */
-		e_data_book_respond_authenticate_user (book, opid, EDB_ERROR (SUCCESS));
+		e_book_backend_notify_opened (backend, EDB_ERROR (SUCCESS));
 		g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
 		return;
 	}
@@ -4811,9 +4785,7 @@ e_book_backend_ldap_authenticate_user (EBookBackend *backend,
 				if (!e) {
 					g_warning ("Failed to get the DN for %s", user);
 					ldap_msgfree (res);
-					e_data_book_respond_authenticate_user (book,
-									       opid,
-									       EDB_ERROR (AUTHENTICATION_FAILED));
+					e_book_backend_notify_opened (backend, EDB_ERROR (AUTHENTICATION_FAILED));
 					return;
 				}
 
@@ -4825,11 +4797,8 @@ e_book_backend_ldap_authenticate_user (EBookBackend *backend,
 
 				ldap_memfree (entry_dn);
 				ldap_msgfree (res);
-			}
-			else {
-				e_data_book_respond_authenticate_user (book,
-								       opid,
-								       EDB_ERROR (PERMISSION_DENIED));
+			} else {
+				e_book_backend_notify_opened (backend, EDB_ERROR (PERMISSION_DENIED));
 				return;
 			}
 		}
@@ -4838,10 +4807,10 @@ e_book_backend_ldap_authenticate_user (EBookBackend *backend,
 		}
 
 		g_free (bl->priv->auth_dn);
-		g_free (bl->priv->auth_passwd);
+		e_credentials_util_safe_free_string (bl->priv->auth_passwd);
 
 		bl->priv->auth_dn = dn;
-		bl->priv->auth_passwd = g_strdup (passwd);
+		bl->priv->auth_passwd = e_credentials_get (credentials, E_CREDENTIALS_KEY_PASSWORD);
 
 		/* now authenticate against the DN we were either supplied or queried for */
 		if (enable_debug)
@@ -4854,7 +4823,7 @@ e_book_backend_ldap_authenticate_user (EBookBackend *backend,
 
 			error = e_book_backend_ldap_connect (bl);
 			if (error) {
-				e_data_book_respond_authenticate_user (book, opid, error);
+				e_book_backend_notify_opened (backend, error);
 				return;
 			}
 		}
@@ -4876,9 +4845,7 @@ e_book_backend_ldap_authenticate_user (EBookBackend *backend,
 
 		}
 
-		e_data_book_respond_authenticate_user (book,
-						       opid,
-						       ldap_error_to_response (ldap_error));
+		e_book_backend_notify_opened (backend, ldap_error_to_response (ldap_error));
 	}
 #ifdef ENABLE_SASL_BINDS
 	else if (!g_ascii_strncasecmp (auth_method, SASL_PREFIX, strlen (SASL_PREFIX))) {
@@ -4891,39 +4858,32 @@ e_book_backend_ldap_authenticate_user (EBookBackend *backend,
 
 			error = e_book_backend_ldap_connect (bl);
 			if (error) {
-				e_data_book_respond_authenticate_user (book, opid, error);
+				e_book_backend_notify_opened (backend, error);
 				return;
 			}
 		}
 		ldap_error = ldap_sasl_bind_s (bl->priv->ldap,
 					       NULL,
 					       auth_method + strlen (SASL_PREFIX),
-					       passwd,
+					       e_credentials_peek (credentials, E_CREDENTIALS_KEY_PASSWORD),
 					       NULL,
 					       NULL,
 					       NULL);
 		g_static_rec_mutex_unlock (&eds_ldap_handler_lock);
 
 		if (ldap_error == LDAP_NOT_SUPPORTED)
-			e_data_book_respond_authenticate_user (book,
-							       opid,
-							       EDB_ERROR (UNSUPPORTED_AUTHENTICATION_METHOD));
+			e_book_backend_notify_opened (backend, EDB_ERROR (UNSUPPORTED_AUTHENTICATION_METHOD));
 		else
-			e_data_book_respond_authenticate_user (book,
-							       opid,
-							       ldap_error_to_response (ldap_error));
+			e_book_backend_notify_opened (backend, ldap_error_to_response (ldap_error));
 	}
 #endif
 	else {
-		e_data_book_respond_authenticate_user (book,
-						       opid,
-						       EDB_ERROR (UNSUPPORTED_AUTHENTICATION_METHOD));
+		e_book_backend_notify_opened (backend, EDB_ERROR (UNSUPPORTED_AUTHENTICATION_METHOD));
 		return;
 	}
 
 	if (ldap_error == LDAP_SUCCESS) {
-
-		e_book_backend_set_is_writable (backend, TRUE);
+		e_book_backend_notify_readonly (backend, FALSE);
 
 		/* force a requery on the root dse since some ldap
 		   servers are set up such that they don't report
@@ -4940,63 +4900,12 @@ e_book_backend_ldap_authenticate_user (EBookBackend *backend,
 				g_warning ("Failed to perform root dse query after authenticating, (ldap_error 0x%02x)", ldap_error);
 		}
 
-		e_data_book_report_writable (book, TRUE);
-
 		if (bl->priv->marked_for_offline && bl->priv->cache)
 			generate_cache (bl);
 	}
 }
 
 static void
-e_book_backend_ldap_get_required_fields (EBookBackend *backend,
-					  EDataBook    *book,
-					  guint32       opid)
-
-{
-	GList *fields = NULL;
-
-	/*FIMEME we should look at mandatory attributs in the schema
-	  and return all those fields here */
-	fields = g_list_append (fields, (gchar *) e_contact_field_name (E_CONTACT_FILE_AS));
-	fields = g_list_append (fields, (gchar *) e_contact_field_name (E_CONTACT_FULL_NAME));
-	fields = g_list_append (fields, (gchar *) e_contact_field_name (E_CONTACT_FAMILY_NAME));
-
-	e_data_book_respond_get_required_fields (book,
-						  opid,
-						  EDB_ERROR (SUCCESS),
-						  fields);
-	g_list_free (fields);
-}
-
-static void
-e_book_backend_ldap_get_supported_fields (EBookBackend *backend,
-					  EDataBook    *book,
-					  guint32       opid)
-
-{
-	EBookBackendLDAP *bl = E_BOOK_BACKEND_LDAP (backend);
-
-	e_data_book_respond_get_supported_fields (book,
-						  opid,
-						  EDB_ERROR (SUCCESS),
-						  bl->priv->supported_fields);
-}
-
-static void
-e_book_backend_ldap_get_supported_auth_methods (EBookBackend *backend,
-						EDataBook    *book,
-						guint32       opid)
-
-{
-	EBookBackendLDAP *bl = E_BOOK_BACKEND_LDAP (backend);
-
-	e_data_book_respond_get_supported_auth_methods (book,
-							opid,
-							EDB_ERROR (SUCCESS),
-							bl->priv->supported_auth_methods);
-}
-
-static void
 ldap_cancel_op (gpointer key, gpointer value, gpointer data)
 {
 	EBookBackendLDAP *bl = data;
@@ -5010,7 +4919,7 @@ ldap_cancel_op (gpointer key, gpointer value, gpointer data)
 }
 
 static void
-e_book_backend_ldap_cancel_operation (EBookBackend *backend, EDataBook *book, GError **perror)
+ldap_cancel_all_operations (EBookBackend *backend)
 {
 	EBookBackendLDAP *bl = E_BOOK_BACKEND_LDAP (backend);
 
@@ -5020,12 +4929,14 @@ e_book_backend_ldap_cancel_operation (EBookBackend *backend, EDataBook *book, GE
 }
 
 static void
-e_book_backend_ldap_load_source (EBookBackend             *backend,
-				 ESource                  *source,
-				 gboolean                  only_if_exists,
-				 GError                  **perror)
+e_book_backend_ldap_open (EBookBackend	*backend,
+			  EDataBook	*book,
+			  guint		 opid,
+			  GCancellable	*cancellable,
+			  gboolean	 only_if_exists)
 {
 	EBookBackendLDAP *bl = E_BOOK_BACKEND_LDAP (backend);
+	ESource *source = e_book_backend_get_source (backend);
 	LDAPURLDesc    *lud;
 	gint ldap_error;
 	gint limit = 100;
@@ -5041,7 +4952,7 @@ e_book_backend_ldap_load_source (EBookBackend             *backend,
 	g_assert (bl->priv->connected == FALSE);
 
 	if (enable_debug)
-		printf ("e_book_backend_ldap_load_source ... \n");
+		printf ("%s ... \n", G_STRFUNC);
 
 	uri = e_source_get_uri (source);
 	cache_dir = e_book_backend_get_cache_dir (backend);
@@ -5088,9 +4999,9 @@ e_book_backend_ldap_load_source (EBookBackend             *backend,
 		ldap_free_urldesc (lud);
 	} else {
 		if (enable_debug)
-			printf ("e_book_backend_ldap_load_source ... failed to parse the ldap URI %s\n", uri);
+			printf ("%s ... failed to parse the ldap URI %s\n", G_STRFUNC, uri);
 		g_free (uri);
-		g_propagate_error (perror, EDB_ERROR_EX (OTHER_ERROR, "Failed to parse LDAP URI"));
+		e_book_backend_respond_opened (backend, book, opid, EDB_ERROR_EX (OTHER_ERROR, "Failed to parse LDAP URI"));
 		return;
 	}
 
@@ -5105,31 +5016,28 @@ e_book_backend_ldap_load_source (EBookBackend             *backend,
 
 	g_free (uri);
 
-	if (bl->priv->mode == E_DATA_BOOK_MODE_LOCAL) {
+	if (!bl->priv->is_online) {
 		/* Offline */
 
-		e_book_backend_set_is_loaded (backend, TRUE);
-		e_book_backend_set_is_writable (backend, FALSE);
-		e_book_backend_notify_writable (backend, FALSE);
-		e_book_backend_notify_connection_status (backend, FALSE);
+		e_book_backend_notify_readonly (backend, TRUE);
+		e_book_backend_notify_online (backend, FALSE);
 
 		if (!bl->priv->marked_for_offline) {
-			g_propagate_error (perror, EDB_ERROR (OFFLINE_UNAVAILABLE));
+			e_book_backend_respond_opened (backend, book, opid, EDB_ERROR (OFFLINE_UNAVAILABLE));
 			return;
 		}
 
 #if 0
 		if (!e_book_backend_cache_is_populated (bl->priv->cache)) {
-			g_propagate_error (perror, EDB_ERROR (OFFLINE_UNAVAILABLE));
+			e_book_backend_respond_opened (backend, book, opid, EDB_ERROR (OFFLINE_UNAVAILABLE));
 			return;
 		}
 #endif
-
+		e_book_backend_respond_opened (backend, book, opid, NULL /* Success */);
 		return;
 	} else {
-		e_book_backend_set_is_writable (backend, TRUE);
-		e_book_backend_notify_writable (backend, TRUE);
-		e_book_backend_notify_connection_status (backend, TRUE);
+		e_book_backend_notify_readonly (backend, FALSE);
+		e_book_backend_notify_online (backend, TRUE);
 	}
 
 	str = e_source_get_property (source, "auth");
@@ -5138,11 +5046,13 @@ e_book_backend_ldap_load_source (EBookBackend             *backend,
 		/* Requires authentication, do not try to bind without it,
 		   but report success instead, as we are loaded. */
 		if (enable_debug)
-			printf ("e_book_backend_ldap_load_source ... skipping anonymous bind, because auth required\n");
+			printf ("%s ... skipping anonymous bind, because auth required\n", G_STRFUNC);
 
-		if (!e_book_backend_is_loaded (backend))
-			e_book_backend_notify_auth_required (backend);
-		e_book_backend_set_is_loaded (backend, TRUE);
+		if (!e_book_backend_is_opened (backend))
+			e_book_backend_notify_auth_required (backend, TRUE, NULL);
+		else
+			e_book_backend_notify_opened (backend, NULL);
+		e_book_backend_respond_opened (backend, book, opid, NULL /* Success */);
 		return;
 	}
 
@@ -5150,22 +5060,25 @@ e_book_backend_ldap_load_source (EBookBackend             *backend,
 	err = e_book_backend_ldap_connect (bl);
 	if (err) {
 		if (enable_debug)
-			printf ("e_book_backend_ldap_load_source ... failed to connect to server \n");
-		g_propagate_error (perror, err);
+			printf ("%s ... failed to connect to server \n", G_STRFUNC);
+		e_book_backend_respond_opened (backend, book, opid, err);
 		return;
 	}
 
-	if (auth_required && !e_book_backend_is_loaded (backend)) {
-		e_book_backend_notify_auth_required (E_BOOK_BACKEND (bl));
+	if (auth_required && !e_book_backend_is_opened (backend)) {
+		e_book_backend_notify_auth_required (E_BOOK_BACKEND (bl), TRUE, NULL);
+		e_data_book_respond_open (book, opid, NULL /* Success */);
 		return;
 	}
 
 	if (bl->priv->marked_for_offline)
 		generate_cache (bl);
+
+	e_book_backend_respond_opened (backend, book, opid, NULL /* Success */);
 }
 
 static void
-e_book_backend_ldap_remove (EBookBackend *backend, EDataBook *book, guint32 opid)
+e_book_backend_ldap_remove (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable)
 {
 	/* if we ever add caching, we'll remove it here, but for now,
 	   just report back Success */
@@ -5173,78 +5086,120 @@ e_book_backend_ldap_remove (EBookBackend *backend, EDataBook *book, guint32 opid
 	e_data_book_respond_remove (book, opid, EDB_ERROR (SUCCESS));
 }
 
-static gchar *
-e_book_backend_ldap_get_static_capabilities (EBookBackend *backend)
+static void
+e_book_backend_ldap_get_backend_property (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *prop_name)
 {
-	if (can_browse (backend) || E_BOOK_BACKEND_LDAP (backend)->priv->marked_for_offline)
-		return g_strdup ("net,anon-access,contact-lists,do-initial-query");
-	else
-		return g_strdup("net,anon-access,contact-lists");
+	g_return_if_fail (prop_name != NULL);
+
+	if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
+		if (can_browse (backend) || E_BOOK_BACKEND_LDAP (backend)->priv->marked_for_offline)
+			e_data_book_respond_get_backend_property (book, opid, NULL, "net,anon-access,contact-lists,do-initial-query");
+		else
+			e_data_book_respond_get_backend_property (book, opid, NULL, "net,anon-access,contact-lists");
+	} else if (g_str_equal (prop_name, BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS)) {
+		gchar *fields_str;
+		GSList *fields = NULL;
+
+		/*FIMEME we should look at mandatory attributs in the schema
+		  and return all those fields here */
+		fields = g_slist_append (fields, (gpointer) e_contact_field_name (E_CONTACT_FILE_AS));
+		fields = g_slist_append (fields, (gpointer) e_contact_field_name (E_CONTACT_FULL_NAME));
+		fields = g_slist_append (fields, (gpointer) e_contact_field_name (E_CONTACT_FAMILY_NAME));
+
+		fields_str = e_data_book_string_slist_to_comma_string (fields);
+
+		e_data_book_respond_get_backend_property (book, opid, NULL, fields_str);
+
+		g_slist_free (fields);
+		g_free (fields_str);
+	} else if (g_str_equal (prop_name, BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS)) {
+		EBookBackendLDAP *bl = E_BOOK_BACKEND_LDAP (backend);
+		gchar *str;
+
+		str = e_data_book_string_slist_to_comma_string (bl->priv->supported_fields);
+
+		e_data_book_respond_get_backend_property (book, opid, NULL, str);
+
+		g_free (str);
+	} else if (g_str_equal (prop_name, BOOK_BACKEND_PROPERTY_SUPPORTED_AUTH_METHODS)) {
+		EBookBackendLDAP *bl = E_BOOK_BACKEND_LDAP (backend);
+		gchar *str;
+
+		str = e_data_book_string_slist_to_comma_string (bl->priv->supported_auth_methods);
+
+		e_data_book_respond_get_backend_property (book, opid, NULL, str);
+
+		g_free (str);
+	} else {
+		E_BOOK_BACKEND_CLASS (e_book_backend_ldap_parent_class)->get_backend_property (backend, book, opid, cancellable, prop_name);
+	}
 }
 
 #if 0
+
+struct call_data {
+	EBookBackend *backend;
+	static void (* func) (EBookBackend  *backend, EDataBookView *view);
+};
+
+static gboolean
+call_cb (EDataBookView *view, gpointer user_data)
+{
+	struct call_data *cd = user_data;
+
+	g_return_val_if_fail (user_data != NULL, FALSE);
+	g_return_val_if_fail (cd->func != NULL, FALSE);
+	g_return_val_if_fail (cd->backend != NULL, FALSE);
+
+	(* cd->func) (cd->backend, view);
+
+	return TRUE;
+}
+
 static void
 stop_views (EBookBackend *backend)
 {
-	EList     *book_views;
-	EIterator *iter;
+	struct call_data cd;
 
-	book_views = e_book_backend_get_book_views (backend);
-	iter = e_list_get_iterator (book_views);
+	cd.backend = backend;
+	cd.func = e_book_backend_ldap_stop_book_view;
 
-	while (e_iterator_is_valid (iter)) {
-		EDataBookView *data_book_view = (EDataBookView *) e_iterator_get (iter);
-		e_book_backend_ldap_stop_book_view (backend, data_book_view);
-		e_iterator_next (iter);
-	}
-
-	g_object_unref (iter);
-	g_object_unref (book_views);
+	e_book_backend_foreach_view (backend, call_cb, &cd);
 }
 
 static void
 start_views (EBookBackend *backend)
 {
-	EList     *book_views;
-	EIterator *iter;
+	struct call_data cd;
 
-	book_views = e_book_backend_get_book_views (backend);
-	iter = e_list_get_iterator (book_views);
+	cd.backend = backend;
+	cd.func = e_book_backend_ldap_start_book_view;
 
-	while (e_iterator_is_valid (iter)) {
-		EDataBookView *data_book_view = (EDataBookView *) e_iterator_get (iter);
-		e_book_backend_ldap_start_book_view (backend, data_book_view);
-		e_iterator_next (iter);
-	}
-
-	g_object_unref (iter);
-	g_object_unref (book_views);
+	e_book_backend_foreach_view (backend, call_cb, &cd);
 }
 #endif
 
 static void
-e_book_backend_ldap_set_mode (EBookBackend *backend,
-                              EDataBookMode mode)
+e_book_backend_ldap_set_online (EBookBackend *backend, gboolean is_online)
 {
 	EBookBackendLDAP *bl = E_BOOK_BACKEND_LDAP (backend);
 
-	if (bl->priv->mode == mode)
+	if (bl->priv->is_online == is_online)
 		return;
 
-	bl->priv->mode = mode;
+	bl->priv->is_online = is_online;
 #if 0
 	stop_views (backend);
 #endif
 
 	/* Cancel all running operations */
-	e_book_backend_ldap_cancel_operation (backend, NULL, NULL);
+	ldap_cancel_all_operations (backend);
 
-	if (mode == E_DATA_BOOK_MODE_LOCAL) {
+	if (!is_online) {
 		/* Go offline */
 
-		e_book_backend_set_is_writable (backend, FALSE);
-		e_book_backend_notify_writable (backend, FALSE);
-		e_book_backend_notify_connection_status (backend, FALSE);
+		e_book_backend_notify_readonly (backend, TRUE);
+		e_book_backend_notify_online (backend, FALSE);
 
 #if 0
 		g_static_rec_mutex_lock (&eds_ldap_handler_lock);
@@ -5258,22 +5213,20 @@ e_book_backend_ldap_set_mode (EBookBackend *backend,
 		bl->priv->connected = FALSE;
 
 #if 0
-		if (e_book_backend_is_loaded (backend))
+		if (e_book_backend_is_opened (backend))
 			start_views (backend);
 #endif
-	}
-	else if (mode == E_DATA_BOOK_MODE_REMOTE) {
+	} else {
 		/* Go online */
 
-		e_book_backend_set_is_writable (backend, TRUE);
-		e_book_backend_notify_writable (backend, TRUE);
-		e_book_backend_notify_connection_status (backend, TRUE);
+		e_book_backend_notify_readonly (backend, FALSE);
+		e_book_backend_notify_online (backend, TRUE);
 
-		if (e_book_backend_is_loaded (backend)) {
+		if (e_book_backend_is_opened (backend)) {
 			GError *error;
 
 			error = e_book_backend_ldap_connect (bl);
-			e_book_backend_notify_auth_required (backend);
+			e_book_backend_notify_auth_required (backend, TRUE, NULL);
 
 			if (error)
 				g_error_free (error);
@@ -5337,13 +5290,13 @@ e_book_backend_ldap_dispose (GObject *object)
 		}
 
 		if (bl->priv->supported_fields) {
-			g_list_foreach (bl->priv->supported_fields, (GFunc) g_free, NULL);
-			g_list_free (bl->priv->supported_fields);
+			g_slist_foreach (bl->priv->supported_fields, (GFunc) g_free, NULL);
+			g_slist_free (bl->priv->supported_fields);
 		}
 
 		if (bl->priv->supported_auth_methods) {
-			g_list_foreach (bl->priv->supported_auth_methods, (GFunc) g_free, NULL);
-			g_list_free (bl->priv->supported_auth_methods);
+			g_slist_foreach (bl->priv->supported_auth_methods, (GFunc) g_free, NULL);
+			g_slist_free (bl->priv->supported_auth_methods);
 		}
 		if (bl->priv->summary_file_name) {
 			g_free (bl->priv->summary_file_name);
@@ -5355,6 +5308,11 @@ e_book_backend_ldap_dispose (GObject *object)
 			bl->priv->summary = NULL;
 		}
 
+		if (bl->priv->cache) {
+			g_object_unref (bl->priv->cache);
+			bl->priv->cache = NULL;
+		}
+
 		g_free (bl->priv->ldap_host);
 		g_free (bl->priv->ldap_rootdn);
 		g_free (bl->priv->ldap_search_filter);
@@ -5380,24 +5338,19 @@ e_book_backend_ldap_class_init (EBookBackendLDAPClass *klass)
 	parent_class = E_BOOK_BACKEND_CLASS (klass);
 
 	/* Set the virtual methods. */
-	parent_class->load_source             = e_book_backend_ldap_load_source;
-	parent_class->remove                  = e_book_backend_ldap_remove;
-	parent_class->get_static_capabilities = e_book_backend_ldap_get_static_capabilities;
-
-	parent_class->create_contact          = e_book_backend_ldap_create_contact;
-	parent_class->remove_contacts         = e_book_backend_ldap_remove_contacts;
-	parent_class->modify_contact          = e_book_backend_ldap_modify_contact;
-	parent_class->get_contact             = e_book_backend_ldap_get_contact;
-	parent_class->get_contact_list        = e_book_backend_ldap_get_contact_list;
-	parent_class->start_book_view         = e_book_backend_ldap_start_book_view;
-	parent_class->stop_book_view          = e_book_backend_ldap_stop_book_view;
-	parent_class->get_changes             = e_book_backend_ldap_get_changes;
-	parent_class->authenticate_user       = e_book_backend_ldap_authenticate_user;
-	parent_class->get_required_fields    = e_book_backend_ldap_get_required_fields;
-	parent_class->get_supported_fields    = e_book_backend_ldap_get_supported_fields;
-	parent_class->get_supported_auth_methods = e_book_backend_ldap_get_supported_auth_methods;
-	parent_class->cancel_operation	      = e_book_backend_ldap_cancel_operation;
-	parent_class->set_mode                = e_book_backend_ldap_set_mode;
+	parent_class->open			= e_book_backend_ldap_open;
+	parent_class->remove			= e_book_backend_ldap_remove;
+	parent_class->get_backend_property	= e_book_backend_ldap_get_backend_property;
+
+	parent_class->create_contact		= e_book_backend_ldap_create_contact;
+	parent_class->remove_contacts		= e_book_backend_ldap_remove_contacts;
+	parent_class->modify_contact		= e_book_backend_ldap_modify_contact;
+	parent_class->get_contact		= e_book_backend_ldap_get_contact;
+	parent_class->get_contact_list		= e_book_backend_ldap_get_contact_list;
+	parent_class->start_book_view		= e_book_backend_ldap_start_book_view;
+	parent_class->stop_book_view		= e_book_backend_ldap_stop_book_view;
+	parent_class->authenticate_user		= e_book_backend_ldap_authenticate_user;
+	parent_class->set_online		= e_book_backend_ldap_set_online;
 
 	object_class->dispose = e_book_backend_ldap_dispose;
 }
@@ -5415,7 +5368,7 @@ e_book_backend_ldap_init (EBookBackendLDAP *backend)
 	priv->id_to_op		     = g_hash_table_new (g_int_hash, g_int_equal);
 	priv->poll_timeout	     = -1;
 	priv->marked_for_offline     = FALSE;
-	priv->mode                   = E_DATA_BOOK_MODE_REMOTE;
+	priv->is_online              = TRUE;
 	priv->is_summary_ready	     = FALSE;
 	priv->reserved1	     = NULL;
 	priv->reserved2	     = NULL;
diff --git a/addressbook/backends/vcf/e-book-backend-vcf.c b/addressbook/backends/vcf/e-book-backend-vcf.c
index a9515f8..3d9d9f6 100644
--- a/addressbook/backends/vcf/e-book-backend-vcf.c
+++ b/addressbook/backends/vcf/e-book-backend-vcf.c
@@ -273,7 +273,7 @@ do_create (EBookBackendVCF  *bvcf,
 static void
 e_book_backend_vcf_create_contact (EBookBackendSync *backend,
 				   EDataBook *book,
-				   guint32 opid,
+				   GCancellable *cancellable,
 				   const gchar *vcard,
 				   EContact **contact,
 				   GError **perror)
@@ -291,14 +291,14 @@ e_book_backend_vcf_create_contact (EBookBackendSync *backend,
 static void
 e_book_backend_vcf_remove_contacts (EBookBackendSync *backend,
 				    EDataBook *book,
-				    guint32 opid,
-				    GList *id_list,
-				    GList **ids,
+				    GCancellable *cancellable,
+				    const GSList *id_list,
+				    GSList **ids,
 				    GError **perror)
 {
 	/* FIXME: make this handle bulk deletes like the file backend does */
 	EBookBackendVCF *bvcf = E_BOOK_BACKEND_VCF (backend);
-	gchar *id = id_list->data;
+	const gchar *id = id_list->data;
 	GList *elem;
 
 	g_mutex_lock (bvcf->priv->mutex);
@@ -324,13 +324,13 @@ e_book_backend_vcf_remove_contacts (EBookBackendSync *backend,
 							       vcf_flush_file, bvcf);
 	g_mutex_unlock (bvcf->priv->mutex);
 
-	*ids = g_list_append (*ids, id);
+	*ids = g_slist_append (*ids, g_strdup (id));
 }
 
 static void
 e_book_backend_vcf_modify_contact (EBookBackendSync *backend,
 				   EDataBook *book,
-				   guint32 opid,
+				   GCancellable *cancellable,
 				   const gchar *vcard,
 				   EContact **contact,
 				   GError **perror)
@@ -363,7 +363,7 @@ e_book_backend_vcf_modify_contact (EBookBackendSync *backend,
 static void
 e_book_backend_vcf_get_contact (EBookBackendSync *backend,
 				EDataBook *book,
-				guint32 opid,
+				GCancellable *cancellable,
 				const gchar *id,
 				gchar **vcard,
 				GError **perror)
@@ -385,23 +385,23 @@ typedef struct {
 	EBookBackendVCF      *bvcf;
 	gboolean            search_needed;
 	EBookBackendSExp *card_sexp;
-	GList              *list;
+	GSList              *list;
 } GetContactListClosure;
 
 static void
 foreach_get_contact_compare (gchar *vcard_string, GetContactListClosure *closure)
 {
 	if ((!closure->search_needed) || e_book_backend_sexp_match_vcard  (closure->card_sexp, vcard_string)) {
-		closure->list = g_list_append (closure->list, g_strdup (vcard_string));
+		closure->list = g_slist_append (closure->list, g_strdup (vcard_string));
 	}
 }
 
 static void
 e_book_backend_vcf_get_contact_list (EBookBackendSync *backend,
 				     EDataBook *book,
-				     guint32 opid,
+				     GCancellable *cancellable,
 				     const gchar *query,
-				     GList **contacts,
+				     GSList **contacts,
 				     GError **perror)
 {
 	EBookBackendVCF *bvcf = E_BOOK_BACKEND_VCF (backend);
@@ -472,9 +472,9 @@ book_view_thread (gpointer data)
 	query = e_data_book_view_get_card_query (book_view);
 
 	if ( !strcmp (query, "(contains \"x-evolution-any-field\" \"\")"))
-		e_data_book_view_notify_status_message (book_view, _("Loading..."));
+		e_data_book_view_notify_progress (book_view, -1, _("Loading..."));
 	else
-		e_data_book_view_notify_status_message (book_view, _("Searching..."));
+		e_data_book_view_notify_progress (book_view, -1, _("Searching..."));
 
 	d(printf ("signalling parent thread\n"));
 	e_flag_set (closure->running);
@@ -541,60 +541,28 @@ e_book_backend_vcf_extract_path_from_uri (const gchar *uri)
 
 static void
 e_book_backend_vcf_authenticate_user (EBookBackendSync *backend,
-				      EDataBook *book,
-				      guint32 opid,
-				      const gchar *user,
-				      const gchar *passwd,
-				      const gchar *auth_method,
+				      GCancellable *cancellable,
+				      ECredentials *credentials,
 				      GError **perror)
 {
 	/* Success */
 }
 
-static void
-e_book_backend_vcf_get_required_fields (EBookBackendSync *backend,
-					EDataBook *book,
-					guint32 opid,
-					GList **fields_out,
-					GError **perror)
-{
-	GList *fields = NULL;
-
-	fields = g_list_append (fields , g_strdup (e_contact_field_name (E_CONTACT_FILE_AS)));
-	*fields_out = fields;
-}
-
-static void
-e_book_backend_vcf_get_supported_fields (EBookBackendSync *backend,
-					 EDataBook *book,
-					 guint32 opid,
-					 GList **fields_out,
-					 GError **perror)
-{
-	GList *fields = NULL;
-	gint i;
-
-	/* XXX we need a way to say "we support everything", since the
-	   vcf backend does */
-	for (i = 0; i < E_CONTACT_FIELD_LAST; i++)
-		fields = g_list_append (fields, (gchar *) e_contact_field_name (i));
-
-	*fields_out = fields;
-}
-
 #ifdef CREATE_DEFAULT_VCARD
 # include <libedata-book/ximian-vcard.h>
 #endif
 
 static void
-e_book_backend_vcf_load_source (EBookBackend             *backend,
-				ESource                  *source,
-				gboolean                  only_if_exists,
-				GError                  **perror)
+e_book_backend_vcf_open (EBookBackendSync        *backend,
+			 EDataBook		 *book,
+			 GCancellable		 *cancellable,
+			 gboolean		  only_if_exists,
+			 GError			**perror)
 {
 	EBookBackendVCF *bvcf = E_BOOK_BACKEND_VCF (backend);
+	ESource *source = e_book_backend_get_source (E_BOOK_BACKEND (backend));
 	gchar           *dirname;
-	gboolean        writable = FALSE;
+	gboolean        readonly = TRUE;
 	gchar          *uri;
 	gint fd;
 
@@ -611,7 +579,7 @@ e_book_backend_vcf_load_source (EBookBackend             *backend,
 		(GDestroyNotify) NULL);
 
 	if (fd != -1) {
-		writable = TRUE;
+		readonly = FALSE;
 	} else {
 		fd = g_open (bvcf->priv->filename, O_RDONLY | O_BINARY, 0);
 
@@ -644,7 +612,7 @@ e_book_backend_vcf_load_source (EBookBackend             *backend,
 				g_object_unref (contact);
 #endif
 
-				writable = TRUE;
+				readonly = FALSE;
 			}
 		}
 	}
@@ -659,32 +627,50 @@ e_book_backend_vcf_load_source (EBookBackend             *backend,
 
 	load_file (bvcf, fd);
 
-	e_book_backend_set_is_loaded (backend, TRUE);
-	e_book_backend_set_is_writable (backend, writable);
+	e_book_backend_notify_readonly (E_BOOK_BACKEND (backend), readonly);
+	e_book_backend_notify_online (E_BOOK_BACKEND (backend), TRUE);
+	e_book_backend_notify_opened (E_BOOK_BACKEND (backend), NULL);
 
 	g_free (uri);
 }
 
-static gchar *
-e_book_backend_vcf_get_static_capabilities (EBookBackend *backend)
+static gboolean
+e_book_backend_vcf_get_backend_property (EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, const gchar *prop_name, gchar **prop_value, GError **error)
 {
-	return g_strdup("local,do-initial-query,contact-lists");
-}
+	gboolean processed = TRUE;
+
+	g_return_val_if_fail (prop_name != NULL, FALSE);
+	g_return_val_if_fail (prop_value != NULL, FALSE);
+
+	if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
+		*prop_value = g_strdup ("local,do-initial-query,contact-lists");
+	} else if (g_str_equal (prop_name, BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS)) {
+		*prop_value = g_strdup (e_contact_field_name (E_CONTACT_FILE_AS));
+	} else if (g_str_equal (prop_name, BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS)) {
+		GSList *fields = NULL;
+		gint i;
+
+		/* XXX we need a way to say "we support everything", since the
+		   vcf backend does */
+		for (i = 1; i < E_CONTACT_FIELD_LAST; i++)
+			fields = g_slist_append (fields, (gpointer) e_contact_field_name (i));
+
+		*prop_value = e_data_book_string_slist_to_comma_string (fields);
+		g_slist_free (fields);
+	} else if (g_str_equal (prop_name, BOOK_BACKEND_PROPERTY_SUPPORTED_AUTH_METHODS)) {
+		*prop_value = NULL;
+	} else {
+		processed = FALSE;
+	}
 
-static void
-e_book_backend_vcf_cancel_operation (EBookBackend *backend, EDataBook *book, GError **perror)
-{
-	g_propagate_error (perror, EDB_ERROR (COULD_NOT_CANCEL));
+	return processed;
 }
 
 static void
-e_book_backend_vcf_set_mode (EBookBackend *backend,
-                             EDataBookMode mode)
+e_book_backend_vcf_set_online (EBookBackend *backend, gboolean is_online)
 {
-	if (e_book_backend_is_loaded (backend)) {
-		e_book_backend_notify_writable (backend, TRUE);
-		e_book_backend_notify_connection_status (backend, TRUE);
-	}
+	if (e_book_backend_is_opened (backend))
+		e_book_backend_notify_online (backend, TRUE);
 }
 
 /**
@@ -743,20 +729,18 @@ e_book_backend_vcf_class_init (EBookBackendVCFClass *klass)
 	backend_class = E_BOOK_BACKEND_CLASS (klass);
 
 	/* Set the virtual methods. */
-	backend_class->load_source             = e_book_backend_vcf_load_source;
-	backend_class->get_static_capabilities = e_book_backend_vcf_get_static_capabilities;
-	backend_class->start_book_view         = e_book_backend_vcf_start_book_view;
-	backend_class->stop_book_view          = e_book_backend_vcf_stop_book_view;
-	backend_class->cancel_operation        = e_book_backend_vcf_cancel_operation;
-	backend_class->set_mode                = e_book_backend_vcf_set_mode;
-	sync_class->create_contact_sync        = e_book_backend_vcf_create_contact;
-	sync_class->remove_contacts_sync       = e_book_backend_vcf_remove_contacts;
-	sync_class->modify_contact_sync        = e_book_backend_vcf_modify_contact;
-	sync_class->get_contact_sync           = e_book_backend_vcf_get_contact;
-	sync_class->get_contact_list_sync      = e_book_backend_vcf_get_contact_list;
-	sync_class->authenticate_user_sync     = e_book_backend_vcf_authenticate_user;
-	sync_class->get_required_fields_sync   = e_book_backend_vcf_get_required_fields;
-	sync_class->get_supported_fields_sync  = e_book_backend_vcf_get_supported_fields;
+	backend_class->start_book_view		= e_book_backend_vcf_start_book_view;
+	backend_class->stop_book_view		= e_book_backend_vcf_stop_book_view;
+	backend_class->set_online		= e_book_backend_vcf_set_online;
+
+	sync_class->open_sync			= e_book_backend_vcf_open;
+	sync_class->get_backend_property_sync	= e_book_backend_vcf_get_backend_property;
+	sync_class->create_contact_sync		= e_book_backend_vcf_create_contact;
+	sync_class->remove_contacts_sync	= e_book_backend_vcf_remove_contacts;
+	sync_class->modify_contact_sync		= e_book_backend_vcf_modify_contact;
+	sync_class->get_contact_sync		= e_book_backend_vcf_get_contact;
+	sync_class->get_contact_list_sync	= e_book_backend_vcf_get_contact_list;
+	sync_class->authenticate_user_sync	= e_book_backend_vcf_authenticate_user;
 
 	object_class->dispose = e_book_backend_vcf_dispose;
 }
diff --git a/addressbook/backends/webdav/e-book-backend-webdav.c b/addressbook/backends/webdav/e-book-backend-webdav.c
index 5b0213a..53033a8 100644
--- a/addressbook/backends/webdav/e-book-backend-webdav.c
+++ b/addressbook/backends/webdav/e-book-backend-webdav.c
@@ -65,7 +65,7 @@ G_DEFINE_TYPE (EBookBackendWebdav, e_book_backend_webdav, E_TYPE_BOOK_BACKEND)
 static EBookBackendClass *parent_class;
 
 struct _EBookBackendWebdavPrivate {
-	gint                mode;
+	gboolean           is_online;
 	gboolean           marked_for_offline;
 	SoupSession       *session;
 	EProxy		  *proxy;
@@ -288,7 +288,7 @@ webdav_handle_auth_request (EBookBackendWebdav *webdav)
 	if (priv->username != NULL) {
 		g_free (priv->username);
 		priv->username = NULL;
-		g_free (priv->password);
+		e_credentials_util_safe_free_string (priv->password);
 		priv->password = NULL;
 
 		return EDB_ERROR (AUTHENTICATION_FAILED);
@@ -298,8 +298,7 @@ webdav_handle_auth_request (EBookBackendWebdav *webdav)
 }
 
 static void
-e_book_backend_webdav_create_contact (EBookBackend *backend,
-		EDataBook *book, guint32 opid, const gchar *vcard)
+e_book_backend_webdav_create_contact (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *vcard)
 {
 	EBookBackendWebdav        *webdav = E_BOOK_BACKEND_WEBDAV (backend);
 	EBookBackendWebdavPrivate *priv   = webdav->priv;
@@ -308,7 +307,7 @@ e_book_backend_webdav_create_contact (EBookBackend *backend,
 	guint                      status;
 	gchar			  *status_reason = NULL;
 
-	if (priv->mode == E_DATA_BOOK_MODE_LOCAL) {
+	if (!priv->is_online) {
 		e_data_book_respond_create (book, opid, EDB_ERROR (REPOSITORY_OFFLINE), NULL);
 		return;
 	}
@@ -386,15 +385,14 @@ delete_contact (EBookBackendWebdav *webdav, const gchar *uri)
 }
 
 static void
-e_book_backend_webdav_remove_contacts (EBookBackend *backend,
-		EDataBook *book, guint32 opid, GList *id_list)
+e_book_backend_webdav_remove_contacts (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const GSList *id_list)
 {
 	EBookBackendWebdav        *webdav      = E_BOOK_BACKEND_WEBDAV (backend);
 	EBookBackendWebdavPrivate *priv        = webdav->priv;
-	GList                     *deleted_ids = NULL;
-	GList                     *list;
+	GSList                    *deleted_ids = NULL;
+	const GSList              *list;
 
-	if (priv->mode == E_DATA_BOOK_MODE_LOCAL) {
+	if (!priv->is_online) {
 		e_data_book_respond_remove_contacts (book, opid,
 				EDB_ERROR (REPOSITORY_OFFLINE), NULL);
 		return;
@@ -415,16 +413,17 @@ e_book_backend_webdav_remove_contacts (EBookBackend *backend,
 			continue;
 		}
 		e_book_backend_cache_remove_contact (priv->cache, uid);
-		deleted_ids = g_list_append (deleted_ids, list->data);
+		deleted_ids = g_slist_append (deleted_ids, list->data);
 	}
 
 	e_data_book_respond_remove_contacts (book, opid,
 			EDB_ERROR (SUCCESS),  deleted_ids);
+
+	g_slist_free (deleted_ids);
 }
 
 static void
-e_book_backend_webdav_modify_contact (EBookBackend *backend,
-		EDataBook *book, guint32 opid, const gchar *vcard)
+e_book_backend_webdav_modify_contact (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *vcard)
 {
 	EBookBackendWebdav        *webdav  = E_BOOK_BACKEND_WEBDAV (backend);
 	EBookBackendWebdavPrivate *priv    = webdav->priv;
@@ -434,7 +433,7 @@ e_book_backend_webdav_modify_contact (EBookBackend *backend,
 	guint status;
 	gchar *status_reason = NULL;
 
-	if (priv->mode == E_DATA_BOOK_MODE_LOCAL) {
+	if (!priv->is_online) {
 		e_data_book_respond_create (book, opid,
 				EDB_ERROR (REPOSITORY_OFFLINE), NULL);
 		g_object_unref (contact);
@@ -494,15 +493,14 @@ e_book_backend_webdav_modify_contact (EBookBackend *backend,
 }
 
 static void
-e_book_backend_webdav_get_contact (EBookBackend *backend, EDataBook *book,
-		guint32 opid, const gchar *uid)
+e_book_backend_webdav_get_contact (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *uid)
 {
 	EBookBackendWebdav        *webdav = E_BOOK_BACKEND_WEBDAV (backend);
 	EBookBackendWebdavPrivate *priv   = webdav->priv;
 	EContact                  *contact;
 	gchar                      *vcard;
 
-	if (priv->mode == E_DATA_BOOK_MODE_LOCAL) {
+	if (!priv->is_online) {
 		contact = e_book_backend_cache_get_contact (priv->cache, uid);
 	} else {
 		contact = download_contact (webdav, uid);
@@ -860,7 +858,7 @@ download_contacts (EBookBackendWebdav *webdav, EFlag *running,
 	}
 
 	if (book_view != NULL) {
-		e_data_book_view_notify_status_message (book_view,
+		e_data_book_view_notify_progress (book_view, -1,
 				"Loading Addressbook summary...");
 	}
 
@@ -920,7 +918,7 @@ download_contacts (EBookBackendWebdav *webdav, EFlag *running,
 			gfloat percent = 100.0 / count * i;
 			gchar buf[100];
 			snprintf(buf, sizeof(buf), "Loading Contacts (%d%%)", (gint)percent);
-			e_data_book_view_notify_status_message (book_view, buf);
+			e_data_book_view_notify_progress (book_view, -1, buf);
 		}
 
 		/* skip collections */
@@ -1012,7 +1010,7 @@ e_book_backend_webdav_start_book_view (EBookBackend *backend,
 	EBookBackendWebdav        *webdav = E_BOOK_BACKEND_WEBDAV (backend);
 	EBookBackendWebdavPrivate *priv   = webdav->priv;
 
-	if (priv->mode == E_DATA_BOOK_MODE_REMOTE) {
+	if (priv->is_online) {
 		WebdavBackendSearchClosure *closure
 			= init_closure (book_view, E_BOOK_BACKEND_WEBDAV (backend));
 
@@ -1043,7 +1041,7 @@ e_book_backend_webdav_stop_book_view (EBookBackend *backend,
 	WebdavBackendSearchClosure *closure;
 	gboolean                    need_join;
 
-	if (webdav->priv->mode == E_DATA_BOOK_MODE_LOCAL)
+	if (!webdav->priv->is_online)
 		return;
 
 	closure = get_closure (book_view);
@@ -1059,16 +1057,15 @@ e_book_backend_webdav_stop_book_view (EBookBackend *backend,
 }
 
 static void
-e_book_backend_webdav_get_contact_list (EBookBackend *backend, EDataBook *book,
-		guint32 opid, const gchar *query)
+e_book_backend_webdav_get_contact_list (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *query)
 {
 	EBookBackendWebdav        *webdav = E_BOOK_BACKEND_WEBDAV (backend);
 	EBookBackendWebdavPrivate *priv   = webdav->priv;
 	GList                     *contact_list;
-	GList                     *vcard_list;
+	GSList                    *vcard_list;
 	GList                     *c;
 
-	if (priv->mode == E_DATA_BOOK_MODE_REMOTE) {
+	if (priv->is_online) {
 		/* make sure the cache is up to date */
 		GError *error = download_contacts (webdav, NULL, NULL);
 
@@ -1085,26 +1082,27 @@ e_book_backend_webdav_get_contact_list (EBookBackend *backend, EDataBook *book,
 		EContact *contact = c->data;
 		gchar     *vcard
 			= e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
-		vcard_list = g_list_append (vcard_list, vcard);
+		vcard_list = g_slist_append (vcard_list, vcard);
 		g_object_unref (contact);
 	}
 	g_list_free (contact_list);
 
 	e_data_book_respond_get_contact_list (book, opid, EDB_ERROR (SUCCESS), vcard_list);
+
+	g_slist_foreach (vcard_list, (GFunc) g_free, NULL);
+	g_slist_free (vcard_list);
 }
 
 static void
-e_book_backend_webdav_authenticate_user (EBookBackend *backend, EDataBook *book,
-		guint32 opid, const gchar *user, const gchar *password,
-		const gchar *auth_method)
+e_book_backend_webdav_authenticate_user (EBookBackend *backend, GCancellable *cancellable, ECredentials *credentials)
 {
 	EBookBackendWebdav        *webdav = E_BOOK_BACKEND_WEBDAV (backend);
 	EBookBackendWebdavPrivate *priv   = webdav->priv;
 	SoupMessage               *message;
 	guint                      status;
 
-	priv->username = g_strdup (user);
-	priv->password = g_strdup (password);
+	priv->username = e_credentials_get (credentials, E_CREDENTIALS_KEY_USERNAME);
+	priv->password = e_credentials_get (credentials, E_CREDENTIALS_KEY_PASSWORD);
 
 	/* Evolution API requires a direct feedback on the authentication,
 	 * so we send a PROPFIND to test wether user/password is correct */
@@ -1115,60 +1113,15 @@ e_book_backend_webdav_authenticate_user (EBookBackend *backend, EDataBook *book,
 	if (status == 401 || status == 407) {
 		g_free (priv->username);
 		priv->username = NULL;
-		g_free (priv->password);
+		e_credentials_util_safe_free_string (priv->password);
 		priv->password = NULL;
 
-		e_data_book_respond_authenticate_user (book, opid, EDB_ERROR (AUTHENTICATION_FAILED));
+		e_book_backend_notify_opened (backend, EDB_ERROR (AUTHENTICATION_FAILED));
 	} else {
-		e_data_book_respond_authenticate_user (book, opid, EDB_ERROR (SUCCESS));
+		e_book_backend_notify_opened (backend, EDB_ERROR (SUCCESS));
 	}
 }
 
-static void
-e_book_backend_webdav_get_supported_fields (EBookBackend *backend,
-		EDataBook *book, guint32 opid)
-{
-	GList *fields = NULL;
-	gint    i;
-
-	/* we support everything */
-	for (i = 1; i < E_CONTACT_FIELD_LAST; ++i) {
-		fields = g_list_append (fields, g_strdup (e_contact_field_name (i)));
-	}
-
-	e_data_book_respond_get_supported_fields (book, opid, EDB_ERROR (SUCCESS), fields);
-	g_list_foreach (fields, (GFunc) g_free, NULL);
-	g_list_free (fields);
-}
-
-static void
-e_book_backend_webdav_get_supported_auth_methods (EBookBackend *backend,
-		EDataBook *book, guint32 opid)
-{
-	GList *auth_methods = NULL;
-
-	auth_methods = g_list_append(auth_methods, g_strdup("plain/password"));
-
-	e_data_book_respond_get_supported_auth_methods (book, opid, EDB_ERROR (SUCCESS), auth_methods);
-
-	g_list_foreach (auth_methods, (GFunc) g_free, NULL);
-	g_list_free (auth_methods);
-}
-
-static void
-e_book_backend_webdav_get_required_fields (EBookBackend *backend,
-		EDataBook *book, guint32 opid)
-{
-	GList       *fields = NULL;
-	const gchar *field_name;
-
-	field_name = e_contact_field_name (E_CONTACT_FILE_AS);
-	fields     = g_list_append (fields , g_strdup (field_name));
-
-	e_data_book_respond_get_supported_fields (book, opid, EDB_ERROR (SUCCESS), fields);
-	g_list_free (fields);
-}
-
 /** authentication callback for libsoup */
 static void soup_authenticate (SoupSession *session, SoupMessage *message,
                               SoupAuth *auth, gboolean retrying, gpointer data)
@@ -1180,8 +1133,7 @@ static void soup_authenticate (SoupSession *session, SoupMessage *message,
 		return;
 
 	if (priv->username != NULL) {
-		soup_auth_authenticate (auth, g_strdup (priv->username),
-				       g_strdup (priv->password));
+		soup_auth_authenticate (auth, priv->username, priv->password);
 	}
 }
 
@@ -1203,11 +1155,11 @@ proxy_settings_changed (EProxy *proxy, gpointer user_data)
 }
 
 static void
-e_book_backend_webdav_load_source (EBookBackend *backend,
-                                  ESource *source, gboolean only_if_exists, GError **perror)
+e_book_backend_webdav_open (EBookBackend *backend, EDataBook *book, guint opid, GCancellable *cancellable, gboolean only_if_exists)
 {
 	EBookBackendWebdav        *webdav = E_BOOK_BACKEND_WEBDAV (backend);
 	EBookBackendWebdavPrivate *priv   = webdav->priv;
+	ESource			  *source = e_book_backend_get_source (backend);
 	gchar                     *uri;
 	const gchar               *cache_dir;
 	const gchar               *offline;
@@ -1224,7 +1176,7 @@ e_book_backend_webdav_load_source (EBookBackend *backend,
 
 	uri = e_source_get_uri (source);
 	if (uri == NULL) {
-		g_propagate_error (perror, EDB_ERROR_EX (OTHER_ERROR, "No uri given for addressbook"));
+		e_book_backend_respond_opened (backend, book, opid, EDB_ERROR_EX (OTHER_ERROR, "No uri given for addressbook"));
 		return;
 	}
 
@@ -1232,7 +1184,7 @@ e_book_backend_webdav_load_source (EBookBackend *backend,
 	g_free (uri);
 
 	if (!suri) {
-		g_propagate_error (perror, EDB_ERROR_EX (OTHER_ERROR, "Invalid uri given for addressbook"));
+		e_book_backend_respond_opened (backend, book, opid, EDB_ERROR_EX (OTHER_ERROR, "Invalid uri given for addressbook"));
 		return;
 	}
 
@@ -1240,17 +1192,16 @@ e_book_backend_webdav_load_source (EBookBackend *backend,
 	if (offline && g_str_equal(offline, "1"))
 		priv->marked_for_offline = TRUE;
 
-	if (priv->mode == E_DATA_BOOK_MODE_LOCAL
-			&& !priv->marked_for_offline ) {
+	if (!priv->is_online && !priv->marked_for_offline ) {
 		soup_uri_free (suri);
-		g_propagate_error (perror, EDB_ERROR (OFFLINE_UNAVAILABLE));
+		e_book_backend_respond_opened (backend, book, opid, EDB_ERROR (OFFLINE_UNAVAILABLE));
 		return;
 	}
 
 	if (!suri->scheme || !g_str_equal (suri->scheme, "webdav")) {
 		/* the book is not for us */
 		soup_uri_free (suri);
-		g_propagate_error (perror, EDB_ERROR_EX (OTHER_ERROR, "Not a webdav uri"));
+		e_book_backend_respond_opened (backend, book, opid, EDB_ERROR_EX (OTHER_ERROR, "Not a webdav uri"));
 		return;
 	}
 
@@ -1291,7 +1242,7 @@ e_book_backend_webdav_load_source (EBookBackend *backend,
 	priv->uri = soup_uri_to_string (suri, FALSE);
 	if (!priv->uri) {
 		soup_uri_free (suri);
-		g_propagate_error (perror, EDB_ERROR_EX (OTHER_ERROR, "Cannot transform SoupURI to string"));
+		e_book_backend_respond_opened (backend, book, opid, EDB_ERROR_EX (OTHER_ERROR, "Cannot transform SoupURI to string"));
 		return;
 	}
 
@@ -1310,55 +1261,71 @@ e_book_backend_webdav_load_source (EBookBackend *backend,
 	proxy_settings_changed (priv->proxy, priv);
 	webdav_debug_setup (priv->session);
 
-	e_book_backend_notify_auth_required (backend);
-	e_book_backend_set_is_loaded (backend, TRUE);
-	e_book_backend_notify_connection_status (backend, TRUE);
-	e_book_backend_set_is_writable (backend, TRUE);
-	e_book_backend_notify_writable (backend, TRUE);
+	e_book_backend_notify_auth_required (backend, TRUE, NULL);
+	e_book_backend_notify_online (backend, TRUE);
+	e_book_backend_notify_readonly (backend, FALSE);
 
 	soup_uri_free (suri);
+
+	e_data_book_respond_open (book, opid, NULL /* Success */);
 }
 
 static void
-e_book_backend_webdav_remove (EBookBackend *backend,	EDataBook *book,
-		guint32 opid)
+e_book_backend_webdav_remove (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable)
 {
 	e_data_book_respond_remove (book, opid, EDB_ERROR (SUCCESS));
 }
 
 static void
-e_book_backend_webdav_set_mode (EBookBackend *backend,
-                               EDataBookMode mode)
+e_book_backend_webdav_set_online (EBookBackend *backend, gboolean is_online)
 {
 	EBookBackendWebdav *webdav = E_BOOK_BACKEND_WEBDAV (backend);
 
-	webdav->priv->mode = mode;
+	webdav->priv->is_online = is_online;
 
 	/* set_mode is called before the backend is loaded */
-	if (!e_book_backend_is_loaded (backend))
+	if (!e_book_backend_is_opened (backend))
 		return;
 
-	if (mode == E_DATA_BOOK_MODE_LOCAL) {
-		e_book_backend_set_is_writable (backend, FALSE);
-		e_book_backend_notify_writable (backend, FALSE);
-		e_book_backend_notify_connection_status (backend, FALSE);
-	} else if (mode == E_DATA_BOOK_MODE_REMOTE) {
-		e_book_backend_set_is_writable (backend, TRUE);
-		e_book_backend_notify_writable (backend, TRUE);
-		e_book_backend_notify_connection_status (backend, TRUE);
+	if (!is_online) {
+		e_book_backend_notify_readonly (backend, TRUE);
+		e_book_backend_notify_online (backend, FALSE);
+	} else {
+		e_book_backend_notify_readonly (backend, FALSE);
+		e_book_backend_notify_online (backend, TRUE);
 	}
 }
 
-static gchar *
-e_book_backend_webdav_get_static_capabilities (EBookBackend *backend)
-{
-	return g_strdup("net,do-initial-query,contact-lists");
-}
-
 static void
-e_book_backend_webdav_cancel_operation (EBookBackend *backend, EDataBook *book, GError **perror)
+e_book_backend_webdav_get_backend_property (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *prop_name)
 {
-	g_propagate_error (perror, EDB_ERROR (COULD_NOT_CANCEL));
+	g_return_if_fail (prop_name != NULL);
+
+	if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
+		e_data_book_respond_get_backend_property (book, opid, NULL, "net,do-initial-query,contact-lists");
+	} else if (g_str_equal (prop_name, BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS)) {
+		e_data_book_respond_get_backend_property (book, opid, NULL, e_contact_field_name (E_CONTACT_FILE_AS));
+	} else if (g_str_equal (prop_name, BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS)) {
+		gchar *fields_str;
+		GSList *fields = NULL;
+		gint    i;
+
+		/* we support everything */
+		for (i = 1; i < E_CONTACT_FIELD_LAST; ++i) {
+			fields = g_slist_append (fields, (gpointer) e_contact_field_name (i));
+		}
+
+		fields_str = e_data_book_string_slist_to_comma_string (fields);
+
+		e_data_book_respond_get_backend_property (book, opid, NULL, fields_str);
+
+		g_slist_free (fields);
+		g_free (fields_str);
+	} else if (g_str_equal (prop_name, BOOK_BACKEND_PROPERTY_SUPPORTED_AUTH_METHODS)) {
+		e_data_book_respond_get_backend_property (book, opid, NULL, "plain/password");
+	} else {
+		E_BOOK_BACKEND_CLASS (e_book_backend_webdav_parent_class)->get_backend_property (backend, book, opid, cancellable, prop_name);
+	}
 }
 
 EBookBackend *
@@ -1381,7 +1348,7 @@ e_book_backend_webdav_dispose (GObject *object)
 	do_unref (priv->cache);
 	do_free (priv->uri);
 	do_free (priv->username);
-	do_free (priv->password);
+	if (priv->password) { e_credentials_util_safe_free_string (priv->password); priv->password = NULL; }
 
 	#undef do_unref
 	#undef do_free
@@ -1400,25 +1367,21 @@ e_book_backend_webdav_class_init (EBookBackendWebdavClass *klass)
 	backend_class = E_BOOK_BACKEND_CLASS (klass);
 
 	/* Set the virtual methods. */
-	backend_class->load_source                = e_book_backend_webdav_load_source;
-	backend_class->get_static_capabilities    = e_book_backend_webdav_get_static_capabilities;
-
-	backend_class->create_contact             = e_book_backend_webdav_create_contact;
-	backend_class->remove_contacts            = e_book_backend_webdav_remove_contacts;
-	backend_class->modify_contact             = e_book_backend_webdav_modify_contact;
-	backend_class->get_contact                = e_book_backend_webdav_get_contact;
-	backend_class->get_contact_list           = e_book_backend_webdav_get_contact_list;
-	backend_class->start_book_view            = e_book_backend_webdav_start_book_view;
-	backend_class->stop_book_view             = e_book_backend_webdav_stop_book_view;
-	backend_class->authenticate_user          = e_book_backend_webdav_authenticate_user;
-	backend_class->get_supported_fields       = e_book_backend_webdav_get_supported_fields;
-	backend_class->get_required_fields        = e_book_backend_webdav_get_required_fields;
-	backend_class->cancel_operation           = e_book_backend_webdav_cancel_operation;
-	backend_class->get_supported_auth_methods = e_book_backend_webdav_get_supported_auth_methods;
-	backend_class->remove                     = e_book_backend_webdav_remove;
-	backend_class->set_mode                   = e_book_backend_webdav_set_mode;
-
-	object_class->dispose                     = e_book_backend_webdav_dispose;
+	backend_class->open			= e_book_backend_webdav_open;
+	backend_class->get_backend_property	= e_book_backend_webdav_get_backend_property;
+
+	backend_class->create_contact		= e_book_backend_webdav_create_contact;
+	backend_class->remove_contacts		= e_book_backend_webdav_remove_contacts;
+	backend_class->modify_contact		= e_book_backend_webdav_modify_contact;
+	backend_class->get_contact		= e_book_backend_webdav_get_contact;
+	backend_class->get_contact_list		= e_book_backend_webdav_get_contact_list;
+	backend_class->start_book_view		= e_book_backend_webdav_start_book_view;
+	backend_class->stop_book_view		= e_book_backend_webdav_stop_book_view;
+	backend_class->authenticate_user	= e_book_backend_webdav_authenticate_user;
+	backend_class->remove			= e_book_backend_webdav_remove;
+	backend_class->set_online		= e_book_backend_webdav_set_online;
+
+	object_class->dispose			= e_book_backend_webdav_dispose;
 
 	g_type_class_add_private (object_class, sizeof (EBookBackendWebdavPrivate));
 }
diff --git a/addressbook/libebook/Makefile.am b/addressbook/libebook/Makefile.am
index de9f7f1..99e3edc 100644
--- a/addressbook/libebook/Makefile.am
+++ b/addressbook/libebook/Makefile.am
@@ -23,6 +23,9 @@ libebook_1_2_la_CPPFLAGS = \
 libebook_1_2_la_SOURCES =				\
 	$(MARSHAL_GENERATED)				\
 	e-address-western.c				\
+	e-book-client.c					\
+	e-book-client-view.c				\
+	e-book-client-view-private.h			\
 	e-book-query.c					\
 	e-book-view-private.h				\
 	e-book-view.c					\
@@ -48,6 +51,8 @@ libebookincludedir = $(privincludedir)/libebook
 
 libebookinclude_HEADERS =				\
 	e-address-western.h				\
+	e-book-client.h					\
+	e-book-client-view.h				\
 	e-book-query.h					\
 	e-book-view.h					\
 	e-book-types.h					\
diff --git a/addressbook/libedata-book/opid.h b/addressbook/libebook/e-book-client-view-private.h
similarity index 73%
rename from addressbook/libedata-book/opid.h
rename to addressbook/libebook/e-book-client-view-private.h
index 20bbf1a..26d8a7f 100644
--- a/addressbook/libedata-book/opid.h
+++ b/addressbook/libebook/e-book-client-view-private.h
@@ -19,10 +19,16 @@
  * Author: Ross Burton <ross linux intel com>
  */
 
-#include <glib.h>
+#ifndef E_BOOK_CLIENT_VIEW_PRIVATE_H
+#define E_BOOK_CLIENT_VIEW_PRIVATE_H
 
-/* Stupid EDS internal API */
+#include "e-book-client.h"
+#include "e-book-view.h"
 
-guint32 opid_store (gpointer p);
+struct _EGdbusBookView;
 
-gpointer opid_fetch (guint32 id);
+EBookClientView *_e_book_client_view_new (EBookClient *book_client, struct _EGdbusBookView *gdbus_bookview);
+
+G_END_DECLS
+
+#endif /* E_BOOK_CLIENT_VIEW_PRIVATE_H */
diff --git a/addressbook/libebook/e-book-client-view.c b/addressbook/libebook/e-book-client-view.c
new file mode 100644
index 0000000..8b99cf2
--- /dev/null
+++ b/addressbook/libebook/e-book-client-view.c
@@ -0,0 +1,384 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2006 OpenedHand Ltd
+ * Copyright (C) 2009 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of version 2.1 of the GNU Lesser General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Author: Ross Burton <ross linux intel com>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+
+#include "e-book-client.h"
+#include "e-book-client-view.h"
+#include "e-book-client-view-private.h"
+#include "e-book-marshal.h"
+#include "libedata-book/e-data-book-types.h"
+#include "e-gdbus-book-view.h"
+
+G_DEFINE_TYPE (EBookClientView, e_book_client_view, G_TYPE_OBJECT);
+
+struct _EBookClientViewPrivate {
+	GDBusProxy *gdbus_bookview;
+	EBookClient *client;
+	gboolean running;
+};
+
+enum {
+	OBJECTS_ADDED,
+	OBJECTS_MODIFIED,
+	OBJECTS_REMOVED,
+	PROGRESS,
+	COMPLETE,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+static void
+objects_added_cb (EGdbusBookView *object, const gchar * const *vcards, EBookClientView *view)
+{
+	const gchar * const *p;
+	GSList *contacts = NULL;
+
+	if (!view->priv->running)
+		return;
+
+	for (p = vcards; *p; p++) {
+		contacts = g_slist_prepend (contacts, e_contact_new_from_vcard (*p));
+	}
+
+	contacts = g_slist_reverse (contacts);
+
+	g_signal_emit (view, signals[OBJECTS_ADDED], 0, contacts);
+
+	g_slist_foreach (contacts, (GFunc) g_object_unref, NULL);
+	g_slist_free (contacts);
+}
+
+static void
+objects_modified_cb (EGdbusBookView *object, const gchar * const *vcards, EBookClientView *view)
+{
+	const gchar * const *p;
+	GSList *contacts = NULL;
+
+	if (!view->priv->running)
+		return;
+
+	for (p = vcards; *p; p++) {
+		contacts = g_slist_prepend (contacts, e_contact_new_from_vcard (*p));
+	}
+	contacts = g_slist_reverse (contacts);
+
+	g_signal_emit (view, signals[OBJECTS_MODIFIED], 0, contacts);
+
+	g_slist_foreach (contacts, (GFunc) g_object_unref, NULL);
+	g_slist_free (contacts);
+}
+
+static void
+objects_removed_cb (EGdbusBookView *object, const gchar * const *ids, EBookClientView *view)
+{
+	const gchar * const *p;
+	GSList *list = NULL;
+
+	if (!view->priv->running)
+		return;
+
+	for (p = ids; *p; p++) {
+		list = g_slist_prepend (list, (gchar *) *p);
+	}
+	list = g_slist_reverse (list);
+
+	g_signal_emit (view, signals[OBJECTS_REMOVED], 0, list);
+
+	/* No need to free the values, our caller will */
+	g_slist_free (list);
+}
+
+static void
+progress_cb (EGdbusBookView *object, guint percent, const gchar *message, EBookClientView *view)
+{
+	if (!view->priv->running)
+		return;
+
+	g_signal_emit (view, signals[PROGRESS], 0, percent, message);
+}
+
+static void
+complete_cb (EGdbusBookView *object, const gchar * const *in_error_strv, EBookClientView *view)
+{
+	GError *error = NULL;
+
+	if (!view->priv->running)
+		return;
+
+	g_return_if_fail (e_gdbus_templates_decode_error (in_error_strv, &error));
+
+	g_signal_emit (view, signals[COMPLETE], 0, error);
+
+	if (error)
+		g_error_free (error);
+}
+
+/*
+ * _e_book_client_view_new:
+ * @book_client: an #EBookClient
+ * @gdbus_bookview: The #EGdbusBookView to get signals from
+ *
+ * Creates a new #EBookClientView based on #EBookClient and listening to @gdbus_bookview.
+ * This is a private function, applications should call e_book_client_get_view() or
+ * e_book_client_get_view_sync().
+ *
+ * Returns: A new #EBookClientView.
+ **/
+EBookClientView *
+_e_book_client_view_new (EBookClient *book_client, EGdbusBookView *gdbus_bookview)
+{
+	EBookClientView *view;
+	EBookClientViewPrivate *priv;
+
+	view = g_object_new (E_TYPE_BOOK_CLIENT_VIEW, NULL);
+	priv = view->priv;
+
+	priv->client = g_object_ref (book_client);
+
+	/* Take ownership of the gdbus_bookview object */
+	priv->gdbus_bookview = g_object_ref (G_DBUS_PROXY (gdbus_bookview));
+
+	g_object_add_weak_pointer (G_OBJECT (gdbus_bookview), (gpointer) &priv->gdbus_bookview);
+	g_signal_connect (priv->gdbus_bookview, "objects-added", G_CALLBACK (objects_added_cb), view);
+	g_signal_connect (priv->gdbus_bookview, "objects-modified", G_CALLBACK (objects_modified_cb), view);
+	g_signal_connect (priv->gdbus_bookview, "objects-removed", G_CALLBACK (objects_removed_cb), view);
+	g_signal_connect (priv->gdbus_bookview, "progress", G_CALLBACK (progress_cb), view);
+	g_signal_connect (priv->gdbus_bookview, "complete", G_CALLBACK (complete_cb), view);
+
+	return view;
+}
+
+/**
+ * e_book_client_view_get_client:
+ * @view: an #EBookClientView
+ *
+ * Returns the #EBookClient that this book view is monitoring.
+ *
+ * Returns: an #EBookClient.
+ **/
+EBookClient *
+e_book_client_view_get_client (EBookClientView *view)
+{
+	g_return_val_if_fail (E_IS_BOOK_CLIENT_VIEW (view), NULL);
+
+	return view->priv->client;
+}
+
+/**
+ * e_book_client_view_start:
+ * @error: A #GError
+ * @view: an #EBookClientView
+ *
+ * Tells @view to start processing events.
+ */
+void
+e_book_client_view_start (EBookClientView *view, GError **error)
+{
+	EBookClientViewPrivate *priv;
+
+	g_return_if_fail (view != NULL);
+	g_return_if_fail (E_IS_BOOK_CLIENT_VIEW (view));
+
+	priv = view->priv;
+
+	if (priv->gdbus_bookview) {
+		GError *local_error = NULL;
+
+		if (e_gdbus_book_view_call_start_sync (priv->gdbus_bookview, NULL, &local_error))
+			priv->running = TRUE;
+
+		e_client_util_unwrap_dbus_error (local_error, error, NULL, 0, 0, FALSE);
+	} else {
+		g_set_error (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR, _("Cannot start view, D-Bus proxy gone"));
+	}
+}
+
+/**
+ * e_book_client_view_stop:
+ * @view: an #EBookClientView
+ * @error: A #GError
+ *
+ * Tells @view to stop processing events.
+ **/
+void
+e_book_client_view_stop (EBookClientView *view, GError **error)
+{
+	EBookClientViewPrivate *priv;
+
+	g_return_if_fail (view != NULL);
+	g_return_if_fail (E_IS_BOOK_CLIENT_VIEW (view));
+
+	priv = view->priv;
+	priv->running = FALSE;
+
+	if (priv->gdbus_bookview) {
+		GError *local_error = NULL;
+
+		e_gdbus_book_view_call_stop_sync (priv->gdbus_bookview, NULL, &local_error);
+
+		e_client_util_unwrap_dbus_error (local_error, error, NULL, 0, 0, FALSE);
+	} else {
+		g_set_error (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR, _("Cannot stop view, D-Bus proxy gone"));
+	}
+}
+
+/**
+ * e_book_client_view_set_fields_of_interest:
+ * @view: An #EBookClientView object
+ * @fields_of_interest: List of field names in which the client is interested
+ * @error: A #GError
+ *
+ * Client can instruct server to which fields it is interested in only, thus
+ * the server can return less data over the wire. The server can still return
+ * complete objects, this is just a hint to it that the listed fields will
+ * be used only. The UID field is returned always. Initial views has no fields
+ * of interest and using %NULL for @fields_of_interest will unset any previous
+ * changes.
+ *
+ * Some backends can use summary information of its cache to create artifical
+ * objects, which will omit stored object parsing. If this cannot be done then
+ * it will simply return object as is stored in the cache.
+ **/
+void
+e_book_client_view_set_fields_of_interest (EBookClientView *view, const GSList *fields_of_interest, GError **error)
+{
+	EBookClientViewPrivate *priv;
+
+	g_return_if_fail (view != NULL);
+	g_return_if_fail (E_IS_BOOK_CLIENT_VIEW (view));
+
+	priv = view->priv;
+
+	if (priv->gdbus_bookview) {
+		GError *local_error = NULL;
+		gchar **strv;
+
+		strv = e_client_util_slist_to_strv (fields_of_interest);
+		e_gdbus_book_view_call_set_fields_of_interest_sync (priv->gdbus_bookview, (const gchar * const *) strv, NULL, &local_error);
+		g_strfreev (strv);
+
+		e_client_util_unwrap_dbus_error (local_error, error, NULL, 0, 0, FALSE);
+	} else {
+		g_set_error (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR, _("Cannot set fields of interest, D-Bus proxy gone"));
+	}
+}
+
+static void
+e_book_client_view_init (EBookClientView *view)
+{
+	view->priv = G_TYPE_INSTANCE_GET_PRIVATE (view, E_TYPE_BOOK_CLIENT_VIEW, EBookClientViewPrivate);
+	view->priv->gdbus_bookview = NULL;
+
+	view->priv->client = NULL;
+	view->priv->running = FALSE;
+}
+
+static void
+book_client_view_dispose (GObject *object)
+{
+	EBookClientView *view = E_BOOK_CLIENT_VIEW (object);
+
+	if (view->priv->gdbus_bookview) {
+		GError *error = NULL;
+
+		g_signal_handlers_disconnect_matched (view->priv->gdbus_bookview, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, view);
+		e_gdbus_book_view_call_dispose_sync (G_DBUS_PROXY (view->priv->gdbus_bookview), NULL, &error);
+		g_object_unref (view->priv->gdbus_bookview);
+		view->priv->gdbus_bookview = NULL;
+
+		if (error) {
+			g_warning ("Failed to dispose book view: %s", error->message);
+			g_error_free (error);
+		}
+	}
+
+	if (view->priv->client) {
+		g_object_unref (view->priv->client);
+		view->priv->client = NULL;
+	}
+
+	/* Chain up to parent's dispose() method. */
+	G_OBJECT_CLASS (e_book_client_view_parent_class)->dispose (object);
+}
+
+static void
+e_book_client_view_class_init (EBookClientViewClass *klass)
+{
+	GObjectClass *object_class;
+
+	g_type_class_add_private (klass, sizeof (EBookClientViewPrivate));
+
+	object_class = G_OBJECT_CLASS (klass);
+	object_class->dispose = book_client_view_dispose;
+
+	signals [OBJECTS_ADDED] =
+		g_signal_new ("objects-added",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (EBookClientViewClass, objects_added),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__POINTER,
+			      G_TYPE_NONE, 1, G_TYPE_POINTER);
+
+	signals [OBJECTS_MODIFIED] =
+		g_signal_new ("objects-modified",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (EBookClientViewClass, objects_modified),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__POINTER,
+			      G_TYPE_NONE, 1, G_TYPE_POINTER);
+
+	signals [OBJECTS_REMOVED] =
+		g_signal_new ("objects-removed",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (EBookClientViewClass, objects_removed),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__POINTER,
+			      G_TYPE_NONE, 1, G_TYPE_POINTER);
+
+	signals [PROGRESS] =
+		g_signal_new ("progress",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (EBookClientViewClass, progress),
+			      NULL, NULL,
+			      e_gdbus_marshallers_VOID__UINT_STRING,
+			      G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING);
+
+	signals [COMPLETE] =
+		g_signal_new ("complete",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (EBookClientViewClass, complete),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__BOXED,
+			      G_TYPE_NONE, 1, G_TYPE_ERROR);
+}
diff --git a/addressbook/libebook/e-book-client-view.h b/addressbook/libebook/e-book-client-view.h
new file mode 100644
index 0000000..c11495d
--- /dev/null
+++ b/addressbook/libebook/e-book-client-view.h
@@ -0,0 +1,71 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 2011 Red Hat, Inc. (www.redhat.com)
+ *
+ */
+
+#ifndef E_BOOK_CLIENT_VIEW_H
+#define E_BOOK_CLIENT_VIEW_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#define E_TYPE_BOOK_CLIENT_VIEW           (e_book_client_view_get_type ())
+#define E_BOOK_CLIENT_VIEW(o)             (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_BOOK_CLIENT_VIEW, EBookClientView))
+#define E_BOOK_CLIENT_VIEW_CLASS(k)       (G_TYPE_CHECK_CLASS_CAST((k), E_TYPE_BOOK_CLIENT_VIEW, EBookClientViewClass))
+#define E_IS_BOOK_CLIENT_VIEW(o)          (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_BOOK_CLIENT_VIEW))
+#define E_IS_BOOK_CLIENT_VIEW_CLASS(k)    (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_BOOK_CLIENT_VIEW))
+#define E_BOOK_CLIENT_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_BOOK_CLIENT_VIEW, EBookClientViewClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EBookClientView        EBookClientView;
+typedef struct _EBookClientViewClass   EBookClientViewClass;
+typedef struct _EBookClientViewPrivate EBookClientViewPrivate;
+
+struct _EBookClient;  /* Forward reference */
+
+struct _EBookClientView {
+	GObject     parent;
+	/*< private >*/
+	EBookClientViewPrivate *priv;
+};
+
+struct _EBookClientViewClass {
+	GObjectClass parent;
+
+	/*
+	 * Signals.
+	 */
+	void (* objects_added)		(EBookClientView *view, const GSList *objects);
+	void (* objects_modified)	(EBookClientView *view, const GSList *objects);
+	void (* objects_removed)	(EBookClientView *view, const GSList *uids);
+
+	void (* progress)		(EBookClientView *view, const gchar *message);
+	void (* complete)		(EBookClientView *view, const GError *error);
+};
+
+GType			e_book_client_view_get_type		(void);
+struct _EBookClient *	e_book_client_view_get_client		(EBookClientView *view);
+gboolean		e_book_client_view_is_running		(EBookClientView *view);
+void			e_book_client_view_set_fields_of_interest(EBookClientView *view, const GSList *fields_of_interest, GError **error);
+void			e_book_client_view_start		(EBookClientView *view, GError **error);
+void			e_book_client_view_stop			(EBookClientView *view, GError **error);
+
+G_END_DECLS
+
+#endif /* E_BOOK_CLIENT_VIEW_H */
diff --git a/addressbook/libebook/e-book-client.c b/addressbook/libebook/e-book-client.c
new file mode 100644
index 0000000..be9ceb9
--- /dev/null
+++ b/addressbook/libebook/e-book-client.c
@@ -0,0 +1,2093 @@
+/*
+ * e-book-client.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 2011 Red Hat, Inc. (www.redhat.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <gio/gio.h>
+
+#include "libedataserver/e-data-server-util.h"
+#include "libedataserver/e-client-private.h"
+
+#include "e-book-client.h"
+#include "e-contact.h"
+#include "e-name-western.h"
+#include "e-book-client-view-private.h"
+
+#include "e-gdbus-book.h"
+#include "e-gdbus-book-factory.h"
+#include "e-gdbus-book-view.h"
+
+struct _EBookClientPrivate
+{
+	/* GDBus data */
+	GDBusProxy *gdbus_book;
+	guint gone_signal_id;
+};
+
+G_DEFINE_TYPE (EBookClient, e_book_client, E_TYPE_CLIENT)
+
+/**
+ * Well-known book backend properties:
+ * @BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS: Retrieves comma-separated list
+ *   of required fields by the backend. Use e_client_util_parse_comma_strings()
+ *   to parse returned string value into a #GSList. These fields are required
+ *   to be filled in for all contacts.
+ * @BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS: Retrieves comma-separated list
+ *   of supported fields by the backend. Use e_client_util_parse_comma_strings()
+ *   to parse returned string value into a #GSList. These fields can be
+ *   stored for contacts.
+ * @BOOK_BACKEND_PROPERTY_SUPPORTED_AUTH_METHODS: Retrieves comma-separated list
+ *   of supported authentication methods by the backend.
+ *   Use e_client_util_parse_comma_strings() to parse returned string value
+ *   into a #GSList.
+ *
+ * See also: @CLIENT_BACKEND_PROPERTY_OPENED, @CLIENT_BACKEND_PROPERTY_OPENING,
+ *   @CLIENT_BACKEND_PROPERTY_ONLINE, @CLIENT_BACKEND_PROPERTY_READONLY
+ *   @CLIENT_BACKEND_PROPERTY_CACHE_DIR, @CLIENT_BACKEND_PROPERTY_CAPABILITIES
+ **/
+
+GQuark
+e_book_client_error_quark (void)
+{
+	static GQuark q = 0;
+	if (q == 0)
+		q = g_quark_from_static_string ("e-book-client-error-quark");
+
+	return q;
+}
+
+const gchar *
+e_book_client_error_to_string (EBookClientError code)
+{
+	switch (code) {
+	case E_BOOK_CLIENT_ERROR_NO_SUCH_BOOK:
+		return C_("BookClientError", "No such book");
+	case E_BOOK_CLIENT_ERROR_CONTACT_NOT_FOUND:
+		return C_("BookClientError", "Contact not found");
+	case E_BOOK_CLIENT_ERROR_CONTACT_ID_ALREADY_EXISTS:
+		return C_("BookClientError", "Contact ID already exists");
+	case E_BOOK_CLIENT_ERROR_TLS_NOT_AVAILABLE:
+		return C_("BookClientError", "TLS not available");
+	case E_BOOK_CLIENT_ERROR_NO_SUCH_SOURCE:
+		return C_("BookClientError", "No such source");
+	case E_BOOK_CLIENT_ERROR_OFFLINE_UNAVAILABLE:
+		return C_("BookClientError", "Offline unavailable");
+	case E_BOOK_CLIENT_ERROR_UNSUPPORTED_AUTHENTICATION_METHOD:
+		return C_("BookClientError", "Unsupported authentication method");
+	case E_BOOK_CLIENT_ERROR_NO_SPACE:
+		return C_("BookClientError", "No space");
+	}
+
+	return C_("BookClientError", "Unknown error");
+}
+
+/**
+ * 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_dbus_error (GError *error, GError **client_error)
+{
+	#define err(a,b) "org.gnome.evolution.dataserver.AddressBook." a, b
+	static struct EClientErrorsList
+	book_errors[] = {
+		{ err ("Success",				-1) },
+		{ err ("ContactNotFound",			E_BOOK_CLIENT_ERROR_CONTACT_NOT_FOUND) },
+		{ err ("ContactIDAlreadyExists",		E_BOOK_CLIENT_ERROR_CONTACT_ID_ALREADY_EXISTS) },
+		{ err ("UnsupportedAuthenticationMethod",	E_BOOK_CLIENT_ERROR_UNSUPPORTED_AUTHENTICATION_METHOD) },
+		{ err ("TLSNotAvailable",			E_BOOK_CLIENT_ERROR_TLS_NOT_AVAILABLE) },
+		{ err ("NoSuchBook",				E_BOOK_CLIENT_ERROR_NO_SUCH_BOOK) },
+		{ err ("BookRemoved",				E_BOOK_CLIENT_ERROR_NO_SUCH_SOURCE) },
+		{ err ("OfflineUnavailable",			E_BOOK_CLIENT_ERROR_OFFLINE_UNAVAILABLE) },
+		{ err ("NoSpace",				E_BOOK_CLIENT_ERROR_NO_SPACE) }
+	}, cl_errors[] = {
+		{ err ("Busy",					E_CLIENT_ERROR_BUSY) },
+		{ err ("RepositoryOffline",			E_CLIENT_ERROR_REPOSITORY_OFFLINE) },
+		{ err ("PermissionDenied",			E_CLIENT_ERROR_PERMISSION_DENIED) },
+		{ err ("AuthenticationFailed",			E_CLIENT_ERROR_AUTHENTICATION_FAILED) },
+		{ err ("AuthenticationRequired",		E_CLIENT_ERROR_AUTHENTICATION_REQUIRED) },
+		{ err ("CouldNotCancel",			E_CLIENT_ERROR_COULD_NOT_CANCEL) },
+		{ err ("InvalidArg",				E_CLIENT_ERROR_INVALID_ARG) },
+		{ err ("NotSupported",				E_CLIENT_ERROR_NOT_SUPPORTED) },
+		{ err ("UnsupportedField",			E_CLIENT_ERROR_OTHER_ERROR) },
+		{ err ("SearchSizeLimitExceeded",		E_CLIENT_ERROR_OTHER_ERROR) },
+		{ err ("SearchTimeLimitExceeded",		E_CLIENT_ERROR_OTHER_ERROR) },
+		{ err ("InvalidQuery",				E_CLIENT_ERROR_OTHER_ERROR) },
+		{ err ("QueryRefused",				E_CLIENT_ERROR_OTHER_ERROR) },
+		{ err ("InvalidServerVersion",			E_CLIENT_ERROR_OTHER_ERROR) },
+		{ err ("OtherError",				E_CLIENT_ERROR_OTHER_ERROR) }
+	};
+	#undef err
+
+	if (error == NULL)
+		return TRUE;
+
+	if (!e_client_util_unwrap_dbus_error (error, client_error, book_errors, G_N_ELEMENTS (book_errors), E_BOOK_CLIENT_ERROR, TRUE))
+		e_client_util_unwrap_dbus_error (error, client_error, cl_errors, G_N_ELEMENTS (cl_errors), E_CLIENT_ERROR, FALSE);
+
+	return FALSE;
+}
+
+static void
+set_proxy_gone_error (GError **error)
+{
+	g_set_error_literal (error, E_CLIENT_ERROR, E_CLIENT_ERROR_DBUS_ERROR, _("D-Bus book proxy gone"));
+}
+
+static guint active_book_clients = 0, book_connection_closed_id = 0;
+static EGdbusBookFactory *book_factory_proxy = NULL;
+static GStaticRecMutex book_factory_proxy_lock = G_STATIC_REC_MUTEX_INIT;
+#define LOCK_FACTORY()   g_static_rec_mutex_lock (&book_factory_proxy_lock)
+#define UNLOCK_FACTORY() g_static_rec_mutex_unlock (&book_factory_proxy_lock)
+
+static void gdbus_book_factory_proxy_closed_cb (GDBusConnection *connection, gboolean remote_peer_vanished, GError *error, gpointer user_data);
+
+static void
+gdbus_book_factory_proxy_disconnect (GDBusConnection *connection)
+{
+	LOCK_FACTORY ();
+
+	if (!connection && book_factory_proxy)
+		connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (book_factory_proxy));
+
+	if (connection && book_connection_closed_id) {
+		g_dbus_connection_signal_unsubscribe (connection, book_connection_closed_id);
+		g_signal_handlers_disconnect_by_func (connection, gdbus_book_factory_proxy_closed_cb, NULL);
+	}
+
+	if (book_factory_proxy)
+		g_object_unref (book_factory_proxy);
+
+	book_connection_closed_id = 0;
+	book_factory_proxy = NULL;
+
+	UNLOCK_FACTORY ();
+}
+
+static void
+gdbus_book_factory_proxy_closed_cb (GDBusConnection *connection, gboolean remote_peer_vanished, GError *error, gpointer user_data)
+{
+	GError *err = NULL;
+
+	LOCK_FACTORY ();
+
+	gdbus_book_factory_proxy_disconnect (connection);
+
+	if (error)
+		unwrap_dbus_error (g_error_copy (error), &err);
+
+	if (err) {
+		g_debug ("GDBus connection is closed%s: %s", remote_peer_vanished ? ", remote peer vanished" : "", err->message);
+		g_error_free (err);
+	} else if (active_book_clients) {
+		g_debug ("GDBus connection is closed%s", remote_peer_vanished ? ", remote peer vanished" : "");
+	}
+
+	UNLOCK_FACTORY ();
+}
+
+static void
+gdbus_book_factory_connection_gone_cb (GDBusConnection *connection, const gchar *sender_name, const gchar *object_path, const gchar *interface_name, const gchar *signal_name, GVariant *parameters, gpointer user_data)
+{
+	/* signal subscription takes care of correct parameters,
+	   thus just do what is to be done here */
+	gdbus_book_factory_proxy_closed_cb (connection, TRUE, NULL, user_data);
+}
+
+static gboolean
+gdbus_book_factory_activate (GError **error)
+{
+	GDBusConnection *connection;
+
+	LOCK_FACTORY ();
+
+	if (G_LIKELY (book_factory_proxy)) {
+		UNLOCK_FACTORY ();
+		return TRUE;
+	}
+
+	book_factory_proxy = e_gdbus_book_factory_proxy_new_for_bus_sync (
+		G_BUS_TYPE_SESSION,
+		G_DBUS_PROXY_FLAGS_NONE,
+		ADDRESS_BOOK_DBUS_SERVICE_NAME,
+		"/org/gnome/evolution/dataserver/AddressBookFactory",
+		NULL,
+		error);
+
+	if (!book_factory_proxy) {
+		UNLOCK_FACTORY ();
+		return FALSE;
+	}
+
+	connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (book_factory_proxy));
+	book_connection_closed_id = g_dbus_connection_signal_subscribe (connection,
+		NULL,						/* sender */
+		"org.freedesktop.DBus",				/* interface */
+		"NameOwnerChanged",				/* member */
+		"/org/freedesktop/DBus",			/* object_path */
+		"org.gnome.evolution.dataserver.AddressBook",	/* arg0 */
+		G_DBUS_SIGNAL_FLAGS_NONE,
+		gdbus_book_factory_connection_gone_cb, NULL, NULL);
+
+	g_signal_connect (connection, "closed", G_CALLBACK (gdbus_book_factory_proxy_closed_cb), NULL);
+
+	UNLOCK_FACTORY ();
+
+	return TRUE;
+}
+
+static void gdbus_book_client_disconnect (EBookClient *client);
+
+/*
+ * Called when the addressbook server dies.
+ */
+static void
+gdbus_book_client_closed_cb (GDBusConnection *connection, gboolean remote_peer_vanished, GError *error, EBookClient *client)
+{
+	GError *err = NULL;
+
+	g_assert (E_IS_BOOK_CLIENT (client));
+
+	if (error)
+		unwrap_dbus_error (g_error_copy (error), &err);
+
+	if (err) {
+		g_debug (G_STRLOC ": EBookClient GDBus connection is closed%s: %s", remote_peer_vanished ? ", remote peer vanished" : "", err->message);
+		g_error_free (err);
+	} else {
+		g_debug (G_STRLOC ": EBookClient GDBus connection is closed%s", remote_peer_vanished ? ", remote peer vanished" : "");
+	}
+
+	gdbus_book_client_disconnect (client);
+
+	e_client_emit_backend_died (E_CLIENT (client));
+}
+
+static void
+gdbus_book_client_connection_gone_cb (GDBusConnection *connection, const gchar *sender_name, const gchar *object_path, const gchar *interface_name, const gchar *signal_name, GVariant *parameters, gpointer user_data)
+{
+	/* signal subscription takes care of correct parameters,
+	   thus just do what is to be done here */
+	gdbus_book_client_closed_cb (connection, TRUE, NULL, user_data);
+}
+
+static void
+gdbus_book_client_disconnect (EBookClient *client)
+{
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_BOOK_CLIENT (client));
+	g_return_if_fail (client->priv != NULL);
+
+	/* Ensure that everything relevant is NULL */
+	LOCK_FACTORY ();
+
+	if (client->priv->gdbus_book) {
+		GDBusConnection *connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (client->priv->gdbus_book));
+
+		g_signal_handlers_disconnect_by_func (connection, gdbus_book_client_closed_cb, client);
+		g_dbus_connection_signal_unsubscribe (connection, client->priv->gone_signal_id);
+		client->priv->gone_signal_id = 0;
+
+		e_gdbus_book_call_close_sync (client->priv->gdbus_book, NULL, NULL);
+		g_object_unref (client->priv->gdbus_book);
+		client->priv->gdbus_book = NULL;
+	}
+
+	UNLOCK_FACTORY ();
+}
+
+static void
+backend_error_cb (EGdbusBook *object, const gchar *message, EBookClient *client)
+{
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_BOOK_CLIENT (client));
+	g_return_if_fail (message != NULL);
+
+	e_client_emit_backend_error (E_CLIENT (client), message);
+}
+
+static void
+readonly_cb (EGdbusBook *object, gboolean readonly, EBookClient *client)
+{
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_BOOK_CLIENT (client));
+
+	e_client_set_readonly (E_CLIENT (client), readonly);
+}
+
+static void
+online_cb (EGdbusBook *object, gboolean is_online, EBookClient *client)
+{
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_BOOK_CLIENT (client));
+
+	e_client_set_online (E_CLIENT (client), is_online);
+}
+
+static void
+auth_required_cb (EGdbusBook *object, const gchar * const *credentials_strv, EBookClient *client)
+{
+	ECredentials *credentials;
+
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_BOOK_CLIENT (client));
+
+	if (credentials_strv)
+		credentials = e_credentials_new_strv (credentials_strv);
+	else
+		credentials = e_credentials_new ();
+
+	e_client_process_authentication (E_CLIENT (client), credentials);
+
+	e_credentials_free (credentials);
+}
+
+static void
+opened_cb (EGdbusBook *object, const gchar * const *error_strv, EBookClient *client)
+{
+	GError *error = NULL;
+
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_BOOK_CLIENT (client));
+	g_return_if_fail (error_strv != NULL);
+	g_return_if_fail (e_gdbus_templates_decode_error (error_strv, &error));
+
+	e_client_emit_opened (E_CLIENT (client), error);
+
+	if (error)
+		g_error_free (error);
+}
+
+/**
+ * e_book_client_new:
+ * @source: An #ESource pointer
+ * @error: A #GError pointer
+ *
+ * Creates a new #EBookClient corresponding to the given source.  There are
+ * only two operations that are valid on this book at this point:
+ * e_client_open(), and e_client_remove().
+ *
+ * Returns: a new but unopened #EBookClient.
+ *
+ * Since: 3.2
+ **/
+EBookClient *
+e_book_client_new (ESource *source, GError **error)
+{
+	EBookClient *client;
+	GError *err = NULL;
+	GDBusConnection *connection;
+	gchar *xml, *gdbus_xml = NULL;
+	gchar *path = NULL;
+
+	g_return_val_if_fail (source != NULL, NULL);
+	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
+
+	if (!gdbus_book_factory_activate (&err)) {
+		if (err) {
+			unwrap_dbus_error (err, &err);
+			g_warning ("%s: Failed to run book factory: %s", G_STRFUNC, err->message);
+			g_propagate_error (error, err);
+		} else {
+			g_warning ("%s: Failed to run book factory: Unknown error", G_STRFUNC);
+			g_set_error_literal (error, E_CLIENT_ERROR, E_CLIENT_ERROR_DBUS_ERROR, _("Failed to run book factory"));
+		}
+
+		return NULL;
+	}
+
+	xml = e_source_to_standalone_xml (source);
+	if (!xml || !*xml) {
+		g_free (xml);
+		g_set_error_literal (error, E_CLIENT_ERROR, E_CLIENT_ERROR_INVALID_ARG, _("Invalid source"));
+		return NULL;
+	}
+
+	client = g_object_new (E_TYPE_BOOK_CLIENT, "source", source, NULL);
+
+	if (!e_gdbus_book_factory_call_get_book_sync (G_DBUS_PROXY (book_factory_proxy), e_util_ensure_gdbus_string (xml, &gdbus_xml), &path, NULL, &err)) {
+		unwrap_dbus_error (err, &err);
+		g_free (xml);
+		g_free (gdbus_xml);
+		g_warning ("%s: Cannot get book from factory: %s", G_STRFUNC, err ? err->message : "[no error]");
+		if (err)
+			g_propagate_error (error, err);
+		g_object_unref (client);
+
+		return NULL;
+	}
+
+	g_free (xml);
+	g_free (gdbus_xml);
+
+	client->priv->gdbus_book = G_DBUS_PROXY (e_gdbus_book_proxy_new_sync (g_dbus_proxy_get_connection (G_DBUS_PROXY (book_factory_proxy)),
+						      G_DBUS_PROXY_FLAGS_NONE,
+						      ADDRESS_BOOK_DBUS_SERVICE_NAME,
+						      path,
+						      NULL,
+						      &err));
+
+	if (!client->priv->gdbus_book) {
+		g_free (path);
+		unwrap_dbus_error (err, &err);
+		g_warning ("%s: Cannot create cal proxy: %s", G_STRFUNC, err ? err->message : "Unknown error");
+		if (err)
+			g_propagate_error (error, err);
+
+		g_object_unref (client);
+
+		return NULL;
+	}
+
+	g_free (path);
+
+	connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (client->priv->gdbus_book));
+	client->priv->gone_signal_id = g_dbus_connection_signal_subscribe (connection,
+		"org.freedesktop.DBus",				/* sender */
+		"org.freedesktop.DBus",				/* interface */
+		"NameOwnerChanged",				/* member */
+		"/org/freedesktop/DBus",			/* object_path */
+		"org.gnome.evolution.dataserver.AddressBook",	/* arg0 */
+		G_DBUS_SIGNAL_FLAGS_NONE,
+		gdbus_book_client_connection_gone_cb, client, NULL);
+
+	g_signal_connect (connection, "closed", G_CALLBACK (gdbus_book_client_closed_cb), client);
+
+	g_signal_connect (client->priv->gdbus_book, "backend_error", G_CALLBACK (backend_error_cb), client);
+	g_signal_connect (client->priv->gdbus_book, "readonly", G_CALLBACK (readonly_cb), client);
+	g_signal_connect (client->priv->gdbus_book, "online", G_CALLBACK (online_cb), client);
+	g_signal_connect (client->priv->gdbus_book, "auth-required", G_CALLBACK (auth_required_cb), client);
+	g_signal_connect (client->priv->gdbus_book, "opened", G_CALLBACK (opened_cb), client);
+
+	return client;
+}
+
+/**
+ * e_book_client_new_from_uri:
+ * @uri: the URI to load
+ * @error: A #GError pointer
+ *
+ * Creates a new #EBookClient corresponding to the given uri.  See the
+ * documentation for e_book_client_new() for further information.
+ *
+ * Returns: a new but unopened #EBookClient.
+ *
+ * Since: 3.2
+ **/
+EBookClient *
+e_book_client_new_from_uri (const gchar *uri, GError **error)
+{
+	ESourceList *source_list = NULL;
+	ESource *source;
+	EBookClient *client;
+
+	g_return_val_if_fail (uri != NULL, NULL);
+
+	if (!e_book_client_get_sources (&source_list, error))
+		return NULL;
+
+	source = e_client_util_get_source_for_uri (source_list, uri);
+	if (!source && g_str_has_prefix (uri, "file://")) {
+		gchar *local_uri;
+
+		local_uri = g_strconcat ("local://", uri + 7, NULL);
+		source = e_client_util_get_source_for_uri (source_list, uri);
+
+		g_free (local_uri);
+	}
+
+	if (!source) {
+		g_object_unref (source_list);
+		g_set_error (error, E_CLIENT_ERROR, E_CLIENT_ERROR_INVALID_ARG, _("Incorrect uri '%s'"), uri);
+
+		return NULL;
+	}
+
+	client = e_book_client_new (source, error);
+
+	g_object_unref (source);
+	g_object_unref (source_list);
+
+	return client;
+}
+
+/**
+ * e_book_client_new_system:
+ * @error: A #GError pointer
+ *
+ * Creates a new #EBookClient corresponding to the user's system
+ * addressbook.  See the documentation for e_book_client_new() for further
+ * information.
+ *
+ * Returns: a new but unopened #EBookClient.
+ *
+ * Since: 3.2
+ **/
+EBookClient *
+e_book_client_new_system (GError **error)
+{
+	ESourceList *source_list = NULL;
+	ESource *source;
+	EBookClient *client;
+
+	if (!e_book_client_get_sources (&source_list, error))
+		return NULL;
+
+	source = e_client_util_get_system_source (source_list);
+	if (!source) {
+		g_object_unref (source_list);
+		g_set_error_literal (error, E_BOOK_CLIENT_ERROR, E_BOOK_CLIENT_ERROR_NO_SUCH_SOURCE, _("Failed to find system book"));
+
+		return NULL;
+	}
+
+	client = e_book_client_new (source, error);
+
+	g_object_unref (source);
+	g_object_unref (source_list);
+
+	return client;
+}
+
+/**
+ * e_book_client_new_default:
+ * @error: return location for a #GError, or %NULL
+ *
+ * Creates a new #EBookClient corresponding to the user's default
+ * address book.  See the documentation for e_book_client_new() for
+ * further information.
+ *
+ * Returns: a new but unopened #EBookClient
+ *
+ * Since: 3.2
+ **/
+EBookClient *
+e_book_client_new_default (GError **error)
+{
+	ESourceList *source_list = NULL;
+	ESource *source;
+	EBookClient *client;
+
+	if (!e_book_client_get_sources (&source_list, error))
+		return NULL;
+
+	source = e_source_list_peek_default_source (source_list);
+	if (!source) {
+		g_set_error_literal (error, E_BOOK_CLIENT_ERROR, E_BOOK_CLIENT_ERROR_NO_SUCH_BOOK, _("Address book does not exist"));
+		g_object_unref (source_list);
+
+		return NULL;
+	}
+
+	client = e_book_client_new (source, error);
+
+	g_object_unref (source_list);
+
+	return client;
+}
+
+/**
+ * e_book_client_set_default:
+ * @client: An #EBookClient pointer
+ * @error: A #GError pointer
+ *
+ * Sets the #ESource of the #EBookClient as the "default" addressbook.  This is the source
+ * that will be loaded in the e_book_client_get_default_addressbook() call.
+ *
+ * Returns: %TRUE if the setting was stored in libebook's ESourceList, otherwise %FALSE.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_book_client_set_default (EBookClient *client, GError **error)
+{
+	ESource *source;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+
+	source = e_client_get_source (E_CLIENT (client));
+	g_return_val_if_fail (source != NULL, FALSE);
+
+	return e_book_client_set_default_source (source, error);
+}
+
+/**
+ * e_book_client_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_client_get_default_addressbook() call.
+ *
+ * Returns: %TRUE if the setting was stored in libebook's ESourceList, otherwise %FALSE.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_book_client_set_default_source (ESource *source, GError **error)
+{
+	ESourceList *source_list = NULL;
+	gboolean res = FALSE;
+
+	g_return_val_if_fail (source != NULL, FALSE);
+	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+
+	if (!e_book_client_get_sources (&source_list, error))
+		return FALSE;
+
+	res = e_client_util_set_default (source_list, source);
+
+	if (res)
+		res = e_source_list_sync (source_list, error);
+	else
+		g_set_error (error, E_CLIENT_ERROR, E_CLIENT_ERROR_INVALID_ARG,
+			_("There was no source for UID '%s' stored in a source list."), e_source_peek_uid (source));
+
+	g_object_unref (source_list);
+
+	return res;
+}
+
+/**
+ * e_book_client_get_sources:
+ * @sources: (out): A pointer to an #ESourceList to set
+ * @error: A pointer to a GError to set on error
+ *
+ * Populate @*sources with the list of all sources which have been
+ * added to Evolution.
+ *
+ * Returns: %TRUE if @sources was set, otherwise %FALSE.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_book_client_get_sources (ESourceList **sources, GError **error)
+{
+	GConfClient *gconf;
+
+	g_return_val_if_fail (sources != NULL, FALSE);
+
+	gconf = gconf_client_get_default ();
+	*sources = e_source_list_new_for_gconf (gconf, "/apps/evolution/addressbook/sources");
+	g_object_unref (gconf);
+
+	return TRUE;
+}
+
+#define SELF_UID_KEY "/apps/evolution/addressbook/self/self_uid"
+
+static EContact *
+make_me_card (void)
+{
+	GString *vcard;
+	const gchar *s;
+	EContact *contact;
+
+	vcard = g_string_new ("BEGIN:VCARD\nVERSION:3.0\n");
+
+	s = g_get_user_name ();
+	if (s)
+		g_string_append_printf (vcard, "NICKNAME:%s\n", s);
+
+	s = g_get_real_name ();
+	if (s && strcmp (s, "Unknown") != 0) {
+		ENameWestern *western;
+
+		g_string_append_printf (vcard, "FN:%s\n", s);
+
+		western = e_name_western_parse (s);
+		g_string_append_printf (vcard, "N:%s;%s;%s;%s;%s\n",
+					western->last ? western->last : "",
+					western->first ? western->first : "",
+					western->middle ? western->middle : "",
+					western->prefix ? western->prefix : "",
+					western->suffix ? western->suffix : "");
+		e_name_western_free (western);
+	}
+	g_string_append (vcard, "END:VCARD");
+
+	contact = e_contact_new_from_vcard (vcard->str);
+
+	g_string_free (vcard, TRUE);
+
+	return contact;
+}
+
+/**
+ * e_book_client_get_self:
+ * @contact: an #EContact pointer to set
+ * @client: an #EBookClient pointer to set
+ * @error: a #GError to set on failure
+ *
+ * Get the #EContact referring to the user of the address book
+ * and set it in @contact and @client.
+ *
+ * Returns: %TRUE if successful, otherwise %FALSE.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_book_client_get_self (EContact **contact, EBookClient **client, GError **error)
+{
+	GError *local_error = NULL;
+	GConfClient *gconf;
+	gchar *uid;
+
+	g_return_val_if_fail (contact != NULL, FALSE);
+	g_return_val_if_fail (client != NULL, FALSE);
+
+	*client = e_book_client_new_system (&local_error);
+	if (!*client) {
+		g_propagate_error (error, local_error);
+		return FALSE;
+	}
+
+	if (!e_client_open_sync (E_CLIENT (*client), FALSE, NULL, &local_error)) {
+		g_object_unref (*client);
+		*client = NULL;
+		g_propagate_error (error, local_error);
+
+		return FALSE;
+	}
+
+	gconf = gconf_client_get_default ();
+	uid = gconf_client_get_string (gconf, SELF_UID_KEY, NULL);
+	g_object_unref (gconf);
+
+	if (uid) {
+		gboolean got;
+
+		/* Don't care about errors because we'll create a new card on failure */
+		got = e_book_client_get_contact_sync (*client, uid, contact, NULL, NULL);
+		g_free (uid);
+		if (got)
+			return TRUE;
+	}
+
+	uid = NULL;
+	*contact = make_me_card ();
+	if (!e_book_client_add_contact_sync (*client, *contact, &uid, NULL, &local_error)) {
+		g_object_unref (*client);
+		*client = NULL;
+		g_object_unref (*contact);
+		*contact = NULL;
+		g_propagate_error (error, local_error);
+		return FALSE;
+	}
+
+	if (uid) {
+		e_contact_set (*contact, E_CONTACT_UID, uid);
+		g_free (uid);
+	}
+
+	e_book_client_set_self (*client, *contact, NULL);
+
+	return TRUE;
+}
+
+/**
+ * e_book_client_set_self:
+ * @client: an #EBookClient
+ * @contact: an #EContact
+ * @error: a #GError to set on failure
+ *
+ * Specify that @contact residing in @client is the #EContact that
+ * refers to the user of the address book.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_book_client_set_self (EBookClient *client, EContact *contact, GError **error)
+{
+	GConfClient *gconf;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (contact != NULL, FALSE);
+	g_return_val_if_fail (e_contact_get_const (contact, E_CONTACT_UID) != NULL, FALSE);
+
+	gconf = gconf_client_get_default ();
+	gconf_client_set_string (gconf, SELF_UID_KEY, e_contact_get_const (contact, E_CONTACT_UID), NULL);
+	g_object_unref (gconf);
+
+	return TRUE;
+}
+
+/**
+ * e_book_client_is_self:
+ * @contact: an #EContact
+ *
+ * Check if @contact is the user of the address book.
+ *
+ * Returns: %TRUE if @contact is the user, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_book_client_is_self (EContact *contact)
+{
+	GConfClient *gconf;
+	gchar *uid;
+	gboolean is_self;
+
+	g_return_val_if_fail (contact && E_IS_CONTACT (contact), FALSE);
+
+	gconf = gconf_client_get_default ();
+	uid = gconf_client_get_string (gconf, SELF_UID_KEY, NULL);
+	g_object_unref (gconf);
+
+	is_self = uid && !g_strcmp0 (uid, e_contact_get_const (contact, E_CONTACT_UID));
+
+	g_free (uid);
+
+	return is_self;
+}
+
+static void
+book_client_get_backend_property (EClient *client, const gchar *prop_name, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_client_proxy_call_string (client, prop_name, cancellable, callback, user_data, book_client_get_backend_property,
+			e_gdbus_book_call_get_backend_property,
+			NULL, NULL, e_gdbus_book_call_get_backend_property_finish, NULL, NULL);
+}
+
+static gboolean
+book_client_get_backend_property_finish (EClient *client, GAsyncResult *result, gchar **prop_value, GError **error)
+{
+	return e_client_proxy_call_finish_string (client, result, prop_value, error, book_client_get_backend_property);
+}
+
+static gboolean
+book_client_get_backend_property_sync (EClient *client, const gchar *prop_name, gchar **prop_value, GCancellable *cancellable, GError **error)
+{
+	EBookClient *book_client;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
+
+	book_client = E_BOOK_CLIENT (client);
+	g_return_val_if_fail (book_client != NULL, FALSE);
+	g_return_val_if_fail (book_client->priv != NULL, FALSE);
+
+	if (!book_client->priv->gdbus_book) {
+		set_proxy_gone_error (error);
+		return FALSE;
+	}
+
+	return e_client_proxy_call_sync_string__string (client, prop_name, prop_value, cancellable, error, e_gdbus_book_call_get_backend_property_sync);
+}
+
+static void
+book_client_set_backend_property (EClient *client, const gchar *prop_name, const gchar *prop_value, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	gchar **prop_name_value;
+
+	prop_name_value = e_gdbus_book_encode_set_backend_property (prop_name, prop_value);
+
+	e_client_proxy_call_strv (client, (const gchar * const *) prop_name_value, cancellable, callback, user_data, book_client_set_backend_property,
+			e_gdbus_book_call_set_backend_property,
+			e_gdbus_book_call_set_backend_property_finish, NULL, NULL, NULL, NULL);
+
+	g_strfreev (prop_name_value);
+}
+
+static gboolean
+book_client_set_backend_property_finish (EClient *client, GAsyncResult *result, GError **error)
+{
+	return e_client_proxy_call_finish_void (client, result, error, book_client_set_backend_property);
+}
+
+static gboolean
+book_client_set_backend_property_sync (EClient *client, const gchar *prop_name, const gchar *prop_value, GCancellable *cancellable, GError **error)
+{
+	EBookClient *book_client;
+	gboolean res;
+	gchar **prop_name_value;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
+
+	book_client = E_BOOK_CLIENT (client);
+	g_return_val_if_fail (book_client != NULL, FALSE);
+	g_return_val_if_fail (book_client->priv != NULL, FALSE);
+
+	if (!book_client->priv->gdbus_book) {
+		set_proxy_gone_error (error);
+		return FALSE;
+	}
+
+	prop_name_value = e_gdbus_book_encode_set_backend_property (prop_name, prop_value);
+	res = e_client_proxy_call_sync_strv__void (client, (const gchar * const *) prop_name_value, cancellable, error, e_gdbus_book_call_set_backend_property_sync);
+	g_strfreev (prop_name_value);
+
+	return res;
+}
+
+static void
+book_client_open (EClient *client, gboolean only_if_exists, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_client_proxy_call_boolean (client, only_if_exists, cancellable, callback, user_data, book_client_open,
+			e_gdbus_book_call_open,
+			e_gdbus_book_call_open_finish, NULL, NULL, NULL, NULL);
+}
+
+static gboolean
+book_client_open_finish (EClient *client, GAsyncResult *result, GError **error)
+{
+	return e_client_proxy_call_finish_void (client, result, error, book_client_open);
+}
+
+static gboolean
+book_client_open_sync (EClient *client, gboolean only_if_exists, GCancellable *cancellable, GError **error)
+{
+	EBookClient *book_client;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
+
+	book_client = E_BOOK_CLIENT (client);
+	g_return_val_if_fail (book_client != NULL, FALSE);
+	g_return_val_if_fail (book_client->priv != NULL, FALSE);
+
+	if (!book_client->priv->gdbus_book) {
+		set_proxy_gone_error (error);
+		return FALSE;
+	}
+
+	return e_client_proxy_call_sync_boolean__void (client, only_if_exists, cancellable, error, e_gdbus_book_call_open_sync);
+}
+
+static void
+book_client_remove (EClient *client, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_client_proxy_call_void (client, cancellable, callback, user_data, book_client_remove,
+			e_gdbus_book_call_remove,
+			e_gdbus_book_call_remove_finish, NULL, NULL, NULL, NULL);
+}
+
+static gboolean
+book_client_remove_finish (EClient *client, GAsyncResult *result, GError **error)
+{
+	return e_client_proxy_call_finish_void (client, result, error, book_client_remove);
+}
+
+static gboolean
+book_client_remove_sync (EClient *client, GCancellable *cancellable, GError **error)
+{
+	EBookClient *book_client;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
+
+	book_client = E_BOOK_CLIENT (client);
+	g_return_val_if_fail (book_client != NULL, FALSE);
+	g_return_val_if_fail (book_client->priv != NULL, FALSE);
+
+	if (!book_client->priv->gdbus_book) {
+		set_proxy_gone_error (error);
+		return FALSE;
+	}
+
+	return e_client_proxy_call_sync_void__void (client, cancellable, error, e_gdbus_book_call_remove_sync);
+}
+
+static void
+book_client_refresh (EClient *client, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_client_proxy_call_void (client, cancellable, callback, user_data, book_client_refresh,
+			e_gdbus_book_call_refresh,
+			e_gdbus_book_call_refresh_finish, NULL, NULL, NULL, NULL);
+}
+
+static gboolean
+book_client_refresh_finish (EClient *client, GAsyncResult *result, GError **error)
+{
+	return e_client_proxy_call_finish_void (client, result, error, book_client_refresh);
+}
+
+static gboolean
+book_client_refresh_sync (EClient *client, GCancellable *cancellable, GError **error)
+{
+	EBookClient *book_client;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
+
+	book_client = E_BOOK_CLIENT (client);
+	g_return_val_if_fail (book_client != NULL, FALSE);
+	g_return_val_if_fail (book_client->priv != NULL, FALSE);
+
+	if (!book_client->priv->gdbus_book) {
+		set_proxy_gone_error (error);
+		return FALSE;
+	}
+
+	return e_client_proxy_call_sync_void__void (client, cancellable, error, e_gdbus_book_call_refresh_sync);
+}
+
+/**
+ * e_book_client_add_contact:
+ * @client: an #EBookClient
+ * @contact: an #EContact
+ * @cancellable: a #GCancellable; can be %NULL
+ * @callback: callback to call when a result is ready
+ * @user_data: user data for the @callback
+ *
+ * Adds @contact to @client.
+ * The call is finished by e_book_client_add_contact_finish()
+ * from the @callback.
+ *
+ * Since: 3.2
+ **/
+void
+e_book_client_add_contact (EBookClient *client, /* const */ EContact *contact, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	gchar *vcard, *gdbus_vcard = NULL;
+
+	g_return_if_fail (contact != NULL);
+	g_return_if_fail (E_IS_CONTACT (contact));
+
+	vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
+
+	e_client_proxy_call_string (E_CLIENT (client), e_util_ensure_gdbus_string (vcard, &gdbus_vcard), cancellable, callback, user_data, e_book_client_add_contact,
+			e_gdbus_book_call_add_contact,
+			NULL, NULL, e_gdbus_book_call_add_contact_finish, NULL, NULL);
+
+	g_free (vcard);
+	g_free (gdbus_vcard);
+}
+
+/**
+ * e_book_client_add_contact_finish:
+ * @client: an #EBookClient
+ * @result: a #GAsyncResult
+ * @added_uid: (out): UID of a newly added contact; can be %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Finishes previous call of e_book_client_add_contact() and
+ * sets @added_uid to a UID of a newly added contact.
+ * This string should be freed with g_free().
+ *
+ * Note: This is not modifying original #EContact.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_book_client_add_contact_finish (EBookClient *client, GAsyncResult *result, gchar **added_uid, GError **error)
+{
+	gboolean res;
+	gchar *out_uid = NULL;
+
+	res = e_client_proxy_call_finish_string (E_CLIENT (client), result, &out_uid, error, e_book_client_add_contact);
+
+	if (res && out_uid && added_uid) {
+		*added_uid = out_uid;
+	} else {
+		g_free (out_uid);
+		if (added_uid)
+			*added_uid = NULL;
+	}
+
+	return res;
+}
+
+/**
+ * e_book_client_add_contact_sync:
+ * @client: an #EBookClient
+ * @contact: an #EContact
+ * @added_uid: (out): UID of a newly added contact; can be %NULL
+ * @cancellable: a #GCancellable; can be %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Adds @contact to @client and
+ * sets @added_uid to a UID of a newly added contact.
+ * This string should be freed with g_free().
+ *
+ * Note: This is not modifying original @contact, thus if it's needed,
+ * then use e_contact_set (contact, E_CONTACT_UID, new_uid).
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_book_client_add_contact_sync (EBookClient *client, /* const */ EContact *contact, gchar **added_uid, GCancellable *cancellable, GError **error)
+{
+	gboolean res;
+	gchar *vcard, *gdbus_vcard = NULL, *out_uid = NULL;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+
+	if (!client->priv->gdbus_book) {
+		set_proxy_gone_error (error);
+		return FALSE;
+	}
+
+	vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
+
+	res = e_client_proxy_call_sync_string__string (E_CLIENT (client), e_util_ensure_gdbus_string (vcard, &gdbus_vcard), &out_uid, cancellable, error, e_gdbus_book_call_add_contact_sync);
+
+	if (res && out_uid && added_uid) {
+		*added_uid = out_uid;
+	} else {
+		g_free (out_uid);
+		if (added_uid)
+			*added_uid = NULL;
+	}
+
+	g_free (vcard);
+	g_free (gdbus_vcard);
+
+	return res;
+}
+
+/**
+ * e_book_client_modify_contact:
+ * @client: an #EBookClient
+ * @contact: an #EContact
+ * @cancellable: a #GCancellable; can be %NULL
+ * @callback: callback to call when a result is ready
+ * @user_data: user data for the @callback
+ *
+ * Applies the changes made to @contact to the stored version in @client.
+ * The call is finished by e_book_client_modify_contact_finish()
+ * from the @callback.
+ *
+ * Since: 3.2
+ **/
+void
+e_book_client_modify_contact (EBookClient *client, /* const */ EContact *contact, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	gchar *vcard, *gdbus_vcard = NULL;
+
+	g_return_if_fail (contact != NULL);
+	g_return_if_fail (E_IS_CONTACT (contact));
+
+	vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
+
+	e_client_proxy_call_string (E_CLIENT (client), e_util_ensure_gdbus_string (vcard, &gdbus_vcard), cancellable, callback, user_data, e_book_client_modify_contact,
+			e_gdbus_book_call_modify_contact,
+			e_gdbus_book_call_modify_contact_finish, NULL, NULL, NULL, NULL);
+
+	g_free (vcard);
+	g_free (gdbus_vcard);
+}
+
+/**
+ * e_book_client_modify_contact_finish:
+ * @client: an #EBookClient
+ * @result: a #GAsyncResult
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Finishes previous call of e_book_client_modify_contact().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_book_client_modify_contact_finish (EBookClient *client, GAsyncResult *result, GError **error)
+{
+	return e_client_proxy_call_finish_void (E_CLIENT (client), result, error, e_book_client_modify_contact);
+}
+
+/**
+ * e_book_client_modify_contact_sync:
+ * @client: an #EBookClient
+ * @contact: an #EContact
+ * @cancellable: a #GCancellable; can be %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Applies the changes made to @contact to the stored version in @client.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_book_client_modify_contact_sync (EBookClient *client, /* const */ EContact *contact, GCancellable *cancellable, GError **error)
+{
+	gboolean res;
+	gchar *vcard, *gdbus_vcard = NULL;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+
+	if (!client->priv->gdbus_book) {
+		set_proxy_gone_error (error);
+		return FALSE;
+	}
+
+	vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
+
+	res = e_client_proxy_call_sync_string__void (E_CLIENT (client), e_util_ensure_gdbus_string (vcard, &gdbus_vcard), cancellable, error, e_gdbus_book_call_modify_contact_sync);
+
+	g_free (vcard);
+	g_free (gdbus_vcard);
+
+	return res;
+}
+
+/**
+ * e_book_client_remove_contact:
+ * @client: an #EBookClient
+ * @contact: an #EContact
+ * @cancellable: a #GCancellable; can be %NULL
+ * @callback: callback to call when a result is ready
+ * @user_data: user data for the @callback
+ *
+ * Removes @contact from the @client.
+ * The call is finished by e_book_client_remove_contact_finish()
+ * from the @callback.
+ *
+ * Since: 3.2
+ **/
+void
+e_book_client_remove_contact (EBookClient *client, /* const */ EContact *contact, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	gchar *uid;
+	const gchar *lst[2];
+
+	g_return_if_fail (contact != NULL);
+	g_return_if_fail (E_IS_CONTACT (contact));
+
+	uid = e_util_utf8_make_valid (e_contact_get_const ((EContact *) contact, E_CONTACT_UID));
+	g_return_if_fail (uid != NULL);
+
+	lst[0] = uid;
+	lst[1] = NULL;
+
+	e_client_proxy_call_strv (E_CLIENT (client), lst, cancellable, callback, user_data, e_book_client_remove_contact,
+			e_gdbus_book_call_remove_contacts,
+			e_gdbus_book_call_remove_contacts_finish, NULL, NULL, NULL, NULL);
+
+	g_free (uid);
+}
+
+/**
+ * e_book_client_remove_contact_finish:
+ * @client: an #EBookClient
+ * @result: a #GAsyncResult
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Finishes previous call of e_book_client_remove_contact().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_book_client_remove_contact_finish (EBookClient *client, GAsyncResult *result, GError **error)
+{
+	return e_client_proxy_call_finish_void (E_CLIENT (client), result, error, e_book_client_remove_contact);
+}
+
+/**
+ * e_book_client_remove_contact_sync:
+ * @client: an #EBookClient
+ * @contact: an #EContact
+ * @cancellable: a #GCancellable; can be %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Removes @contact from the @client.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_book_client_remove_contact_sync (EBookClient *client, /* const */ EContact *contact, GCancellable *cancellable, GError **error)
+{
+	gboolean res;
+	gchar *uid;
+	const gchar *lst[2];
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+	g_return_val_if_fail (contact != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CONTACT (contact), FALSE);
+
+	if (!client->priv->gdbus_book) {
+		set_proxy_gone_error (error);
+		return FALSE;
+	}
+
+	uid = e_util_utf8_make_valid (e_contact_get_const ((EContact *) contact, E_CONTACT_UID));
+	g_return_val_if_fail (uid != NULL, 0);
+
+	lst[0] = uid;
+	lst[1] = NULL;
+
+	res = e_client_proxy_call_sync_strv__void (E_CLIENT (client), lst, cancellable, error, e_gdbus_book_call_remove_contacts_sync);
+
+	g_free (uid);
+
+	return res;
+}
+
+/**
+ * e_book_client_remove_contact_by_uid:
+ * @client: an #EBookClient
+ * @uid: a UID of a contact to remove
+ * @cancellable: a #GCancellable; can be %NULL
+ * @callback: callback to call when a result is ready
+ * @user_data: user data for the @callback
+ *
+ * Removes contact with @uid from the @client.
+ * The call is finished by e_book_client_remove_contact_by_uid_finish()
+ * from the @callback.
+ *
+ * Since: 3.2
+ **/
+void
+e_book_client_remove_contact_by_uid (EBookClient *client, const gchar *uid, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	gchar *safe_uid;
+	const gchar *lst[2];
+
+	g_return_if_fail (uid != NULL);
+
+	safe_uid = e_util_utf8_make_valid (uid);
+	g_return_if_fail (safe_uid != NULL);
+
+	lst[0] = safe_uid;
+	lst[1] = NULL;
+
+	e_client_proxy_call_strv (E_CLIENT (client), lst, cancellable, callback, user_data, e_book_client_remove_contact_by_uid,
+			e_gdbus_book_call_remove_contacts,
+			e_gdbus_book_call_remove_contacts_finish, NULL, NULL, NULL, NULL);
+
+	g_free (safe_uid);
+}
+
+/**
+ * e_book_client_remove_contact_by_uid_finish:
+ * @client: an #EBookClient
+ * @result: a #GAsyncResult
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Finishes previous call of e_book_client_remove_contact_by_uid().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_book_client_remove_contact_by_uid_finish (EBookClient *client, GAsyncResult *result, GError **error)
+{
+	return e_client_proxy_call_finish_void (E_CLIENT (client), result, error, e_book_client_remove_contact_by_uid);
+}
+
+/**
+ * e_book_client_remove_contact_by_uid_sync:
+ * @client: an #EBookClient
+ * @uid: a UID of a contact to remove
+ * @cancellable: a #GCancellable; can be %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Removes contact with @uid from the @client.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_book_client_remove_contact_by_uid_sync (EBookClient *client, const gchar *uid, GCancellable *cancellable, GError **error)
+{
+	gboolean res;
+	gchar *safe_uid;
+	const gchar *lst[2];
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+	g_return_val_if_fail (uid != NULL, FALSE);
+
+	if (!client->priv->gdbus_book) {
+		set_proxy_gone_error (error);
+		return FALSE;
+	}
+
+	safe_uid = e_util_utf8_make_valid (uid);
+	g_return_val_if_fail (safe_uid != NULL, FALSE);
+
+	lst[0] = safe_uid;
+	lst[1] = NULL;
+
+	res = e_client_proxy_call_sync_strv__void (E_CLIENT (client), lst, cancellable, error, e_gdbus_book_call_remove_contacts_sync);
+
+	g_free (safe_uid);
+
+	return res;
+}
+
+/**
+ * e_book_client_remove_contacts:
+ * @client: an #EBookClient
+ * @uids: a #GSList of UIDs to remove
+ * @cancellable: a #GCancellable; can be %NULL
+ * @callback: callback to call when a result is ready
+ * @user_data: user data for the @callback
+ *
+ * Removes the contacts with uids from the list @uids from @client.  This is
+ * always more efficient than calling e_book_client_remove_contact() if you
+ * have more than one uid to remove, as some backends can implement it
+ * as a batch request.
+ * The call is finished by e_book_client_remove_contacts_finish()
+ * from the @callback.
+ *
+ * Since: 3.2
+ **/
+void
+e_book_client_remove_contacts (EBookClient *client, const GSList *uids, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	gchar **lst;
+
+	g_return_if_fail (uids != NULL);
+
+	lst = e_client_util_slist_to_strv (uids);
+	g_return_if_fail (lst != NULL);
+
+	e_client_proxy_call_strv (E_CLIENT (client), (const gchar * const *) lst, cancellable, callback, user_data, e_book_client_remove_contacts,
+			e_gdbus_book_call_remove_contacts,
+			e_gdbus_book_call_remove_contacts_finish, NULL, NULL, NULL, NULL);
+
+	g_strfreev (lst);
+}
+
+/**
+ * e_book_client_remove_contacts_finish:
+ * @client: an #EBookClient
+ * @result: a #GAsyncResult
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Finishes previous call of e_book_client_remove_contacts().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_book_client_remove_contacts_finish (EBookClient *client, GAsyncResult *result, GError **error)
+{
+	return e_client_proxy_call_finish_void (E_CLIENT (client), result, error, e_book_client_remove_contacts);
+}
+
+/**
+ * e_book_client_remove_contacts_sync:
+ * @client: an #EBookClient
+ * @uids: a #GSList of UIDs to remove
+ * @cancellable: a #GCancellable; can be %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Removes the contacts with uids from the list @uids from @client.  This is
+ * always more efficient than calling e_book_client_remove_contact() if you
+ * have more than one uid to remove, as some backends can implement it
+ * as a batch request.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_book_client_remove_contacts_sync (EBookClient *client, const GSList *uids, GCancellable *cancellable, GError **error)
+{
+	gboolean res;
+	gchar **lst;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+	g_return_val_if_fail (uids != NULL, FALSE);
+
+	if (!client->priv->gdbus_book) {
+		set_proxy_gone_error (error);
+		return FALSE;
+	}
+
+	lst = e_client_util_slist_to_strv (uids);
+	g_return_val_if_fail (lst != NULL, FALSE);
+
+	res = e_client_proxy_call_sync_strv__void (E_CLIENT (client), (const gchar * const *) lst, cancellable, error, e_gdbus_book_call_remove_contacts_sync);
+
+	g_strfreev (lst);
+
+	return res;
+}
+
+/**
+ * e_book_client_get_contact:
+ * @client: an #EBookClient
+ * @uid: a unique string ID specifying the contact
+ * @cancellable: a #GCancellable; can be %NULL
+ * @callback: callback to call when a result is ready
+ * @user_data: user data for the @callback
+ *
+ * Receive #EContact from the @client for the gived @uid.
+ * The call is finished by e_book_client_get_contact_finish()
+ * from the @callback.
+ *
+ * Since: 3.2
+ **/
+void
+e_book_client_get_contact (EBookClient *client, const gchar *uid, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	gchar *safe_uid;
+
+	g_return_if_fail (uid != NULL);
+
+	safe_uid = e_util_utf8_make_valid (uid);
+	g_return_if_fail (safe_uid != NULL);
+	
+	e_client_proxy_call_string (E_CLIENT (client), safe_uid, cancellable, callback, user_data, e_book_client_get_contact,
+			e_gdbus_book_call_get_contact,
+			NULL, NULL, e_gdbus_book_call_get_contact_finish, NULL, NULL);
+
+	g_free (safe_uid);
+}
+
+/**
+ * e_book_client_get_contact_finish:
+ * @client: an #EBookClient
+ * @result: a #GAsyncResult
+ * @contact: (out) an #EContact for previously given uid
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Finishes previous call of e_book_client_get_contact().
+ * If successful, then the @contact is set to newly allocated
+ * #EContact, which should be freed with g_object_unref().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_book_client_get_contact_finish (EBookClient *client, GAsyncResult *result, EContact **contact, GError **error)
+{
+	gboolean res;
+	gchar *vcard = NULL;
+
+	g_return_val_if_fail (contact != NULL, FALSE);
+
+	res = e_client_proxy_call_finish_string (E_CLIENT (client), result, &vcard, error, e_book_client_get_contact);
+
+	if (vcard && res)
+		*contact = e_contact_new_from_vcard (vcard);
+	else
+		*contact = NULL;
+
+	g_free (vcard);
+
+	return res;
+}
+
+/**
+ * e_book_client_get_contact_sync:
+ * @client: an #EBookClient
+ * @uid: a unique string ID specifying the contact
+ * @contact: (out) an #EContact for given @uid
+ * @cancellable: a #GCancellable; can be %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Receive #EContact from the @client for the gived @uid.
+ * If successful, then the @contact is set to newly allocated
+ * #EContact, which should be freed with g_object_unref().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_book_client_get_contact_sync (EBookClient *client, const gchar *uid, EContact **contact, GCancellable *cancellable, GError **error)
+{
+	gboolean res;
+	gchar *vcard = NULL, *safe_uid;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+	g_return_val_if_fail (uid != NULL, FALSE);
+	g_return_val_if_fail (contact != NULL, FALSE);
+
+	if (!client->priv->gdbus_book) {
+		set_proxy_gone_error (error);
+		return FALSE;
+	}
+
+	safe_uid = e_util_utf8_make_valid (uid);
+	g_return_val_if_fail (safe_uid != NULL, FALSE);
+
+	res = e_client_proxy_call_sync_string__string (E_CLIENT (client), safe_uid, &vcard, cancellable, error, e_gdbus_book_call_get_contact_sync);
+
+	if (vcard && res)
+		*contact = e_contact_new_from_vcard (vcard);
+	else
+		*contact = NULL;
+
+	g_free (safe_uid);
+	g_free (vcard);
+
+	return res;
+}
+
+/**
+ * e_book_client_get_contacts:
+ * @client: an #EBookClient
+ * @sexp: an S-expression representing the query
+ * @cancellable: a #GCancellable; can be %NULL
+ * @callback: callback to call when a result is ready
+ * @user_data: user data for the @callback
+ *
+ * Query @client with @sexp, receiving a list of contacts which
+ * matched. The call is finished by e_book_client_get_contacts_finish()
+ * from the @callback.
+ *
+ * Note: @sexp can be obtained through #EBookQuery, by converting it
+ * to a string with e_book_query_to_string().
+ *
+ * Since: 3.2
+ **/
+void
+e_book_client_get_contacts (EBookClient *client, const gchar *sexp, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	gchar *gdbus_sexp = NULL;
+
+	g_return_if_fail (sexp != NULL);
+
+	e_client_proxy_call_string (E_CLIENT (client), e_util_ensure_gdbus_string (sexp, &gdbus_sexp), cancellable, callback, user_data, e_book_client_get_contacts,
+			e_gdbus_book_call_get_contact_list,
+			NULL, NULL, NULL, e_gdbus_book_call_get_contact_list_finish, NULL);
+
+	g_free (gdbus_sexp);
+}
+
+/**
+ * e_book_client_get_contacts_finish:
+ * @client: an #EBookClient
+ * @result: a #GAsyncResult
+ * @contacts: (out) a #GSList of matched #EContact-s
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Finishes previous call of e_book_client_get_contacts().
+ * If successful, then the @contacts is set to newly allocated list of #EContact-s,
+ * which should be freed with e_client_util_free_object_slist().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_book_client_get_contacts_finish (EBookClient *client, GAsyncResult *result, GSList **contacts, GError **error)
+{
+	gboolean res;
+	gchar **vcards = NULL;
+
+	g_return_val_if_fail (contacts != NULL, FALSE);
+
+	res = e_client_proxy_call_finish_strv (E_CLIENT (client), result, &vcards, error, e_book_client_get_contacts);
+
+	if (vcards && res) {
+		gint ii;
+		GSList *slist = NULL;
+
+		for (ii = 0; vcards[ii]; ii++) {
+			slist = g_slist_prepend (slist, e_contact_new_from_vcard (vcards[ii]));
+		}
+
+		*contacts = g_slist_reverse (slist);
+	} else {
+		*contacts = NULL;
+	}
+
+	g_strfreev (vcards);
+
+	return res;
+}
+
+/**
+ * e_book_client_get_contacts_sync:
+ * @client: an #EBookClient
+ * @sexp: an S-expression representing the query
+ * @contacts: (out) a #GSList of matched #EContact-s
+ * @cancellable: a #GCancellable; can be %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Query @client with @sexp, receiving a list of contacts which matched.
+ * If successful, then the @contacts is set to newly allocated #GSList of
+ * #EContact-s, which should be freed with e_client_util_free_object_slist().
+ *
+ * Note: @sexp can be obtained through #EBookQuery, by converting it
+ * to a string with e_book_query_to_string().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_book_client_get_contacts_sync (EBookClient *client, const gchar *sexp, GSList **contacts, GCancellable *cancellable, GError **error)
+{
+	gboolean res;
+	gchar *gdbus_sexp = NULL;
+	gchar **vcards = NULL;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+	g_return_val_if_fail (sexp != NULL, FALSE);
+	g_return_val_if_fail (contacts != NULL, FALSE);
+
+	if (!client->priv->gdbus_book) {
+		set_proxy_gone_error (error);
+		return FALSE;
+	}
+
+	res = e_client_proxy_call_sync_string__strv (E_CLIENT (client), e_util_ensure_gdbus_string (sexp, &gdbus_sexp), &vcards, cancellable, error, e_gdbus_book_call_get_contact_list_sync);
+
+	if (vcards && res) {
+		gint ii;
+		GSList *slist = NULL;
+
+		for (ii = 0; vcards[ii]; ii++) {
+			slist = g_slist_prepend (slist, e_contact_new_from_vcard (vcards[ii]));
+		}
+
+		*contacts = g_slist_reverse (slist);
+	} else {
+		*contacts = NULL;
+	}
+
+	g_free (gdbus_sexp);
+	g_strfreev (vcards);
+
+	return res;
+}
+
+/**
+ * e_book_client_get_view:
+ * @client: an #EBookClient
+ * @sexp: an S-expression representing the query
+ * @cancellable: a #GCancellable; can be %NULL
+ * @callback: callback to call when a result is ready
+ * @user_data: user data for the @callback
+ *
+ * Query @client with @sexp, creating an #EBookClientView.
+ * The call is finished by e_book_client_get_view_finish()
+ * from the @callback.
+ *
+ * Note: @sexp can be obtained through #EBookQuery, by converting it
+ * to a string with e_book_query_to_string().
+ *
+ * Since: 3.2
+ **/
+void
+e_book_client_get_view (EBookClient *client, const gchar *sexp, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	gchar *gdbus_sexp = NULL;
+
+	g_return_if_fail (sexp != NULL);
+
+	e_client_proxy_call_string (E_CLIENT (client), e_util_ensure_gdbus_string (sexp, &gdbus_sexp), cancellable, callback, user_data, e_book_client_get_view,
+			e_gdbus_book_call_get_view,
+			NULL, NULL, e_gdbus_book_call_get_view_finish, NULL, NULL);
+
+	g_free (gdbus_sexp);
+}
+
+static gboolean
+complete_get_view (EBookClient *client, gboolean res, gchar *view_path, EBookClientView **view, GError **error)
+{
+	g_return_val_if_fail (view != NULL, FALSE);
+
+	if (view_path && res && book_factory_proxy) {
+		GError *local_error = NULL;
+		EGdbusBookView *gdbus_bookview;
+
+		gdbus_bookview = e_gdbus_book_view_proxy_new_sync (g_dbus_proxy_get_connection (G_DBUS_PROXY (book_factory_proxy)),
+								G_DBUS_PROXY_FLAGS_NONE,
+								ADDRESS_BOOK_DBUS_SERVICE_NAME,
+								view_path,
+								NULL,
+								&local_error);
+
+		if (gdbus_bookview) {
+			*view = _e_book_client_view_new (client, gdbus_bookview);
+			g_object_unref (gdbus_bookview);
+		} else {
+			*view = NULL;
+			res = FALSE;
+		}
+
+		if (local_error)
+			unwrap_dbus_error (local_error, error);
+	} else {
+		*view = NULL;
+		res = FALSE;
+	}
+
+	if (!*view && error && !*error)
+		g_set_error_literal (error, E_CLIENT_ERROR, E_CLIENT_ERROR_DBUS_ERROR, _("Cannot get connection to view"));
+
+	g_free (view_path);
+
+	return res;
+}
+
+/**
+ * e_book_client_get_view_finish:
+ * @client: an #EBookClient
+ * @result: a #GAsyncResult
+ * @view: (out) an #EBookClientView
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Finishes previous call of e_book_client_get_view().
+ * If successful, then the @view is set to newly allocated #EBookClientView,
+ * which should be freed with g_object_unref().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_book_client_get_view_finish (EBookClient *client, GAsyncResult *result, EBookClientView **view, GError **error)
+{
+	gboolean res;
+	gchar *view_path = NULL;
+
+	g_return_val_if_fail (view != NULL, FALSE);
+
+	res = e_client_proxy_call_finish_string (E_CLIENT (client), result, &view_path, error, e_book_client_get_view);
+
+	return complete_get_view (client, res, view_path, view, error);
+}
+
+/**
+ * e_book_client_get_view_sync:
+ * @client: an #EBookClient
+ * @sexp: an S-expression representing the query
+ * @view: (out) an #EBookClientView
+ * @cancellable: a #GCancellable; can be %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Query @client with @sexp, creating an #EBookClientView.
+ * If successful, then the @view is set to newly allocated #EBookClientView,
+ * which should be freed with g_object_unref().
+ *
+ * Note: @sexp can be obtained through #EBookQuery, by converting it
+ * to a string with e_book_query_to_string().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_book_client_get_view_sync (EBookClient *client, const gchar *sexp, EBookClientView **view, GCancellable *cancellable, GError **error)
+{
+	gboolean res;
+	gchar *gdbus_sexp = NULL;
+	gchar *view_path = NULL;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+	g_return_val_if_fail (sexp != NULL, FALSE);
+	g_return_val_if_fail (view != NULL, FALSE);
+
+	if (!client->priv->gdbus_book) {
+		set_proxy_gone_error (error);
+		return FALSE;
+	}
+
+	res = e_client_proxy_call_sync_string__string (E_CLIENT (client), e_util_ensure_gdbus_string (sexp, &gdbus_sexp), &view_path, cancellable, error, e_gdbus_book_call_get_view_sync);
+
+	g_free (gdbus_sexp);
+
+	return complete_get_view (client, res, view_path, view, error);
+}
+
+static GDBusProxy *
+book_client_get_dbus_proxy (EClient *client)
+{
+	EBookClient *book_client;
+
+	g_return_val_if_fail (client != NULL, NULL);
+
+	book_client = E_BOOK_CLIENT (client);
+	g_return_val_if_fail (book_client != NULL, NULL);
+	g_return_val_if_fail (book_client->priv != NULL, NULL);
+
+	return book_client->priv->gdbus_book;
+}
+
+static void
+book_client_unwrap_dbus_error (EClient *client, GError *dbus_error, GError **out_error)
+{
+	unwrap_dbus_error (dbus_error, out_error);
+}
+
+static void
+book_client_handle_authentication (EClient *client, const ECredentials *credentials)
+{
+	EBookClient *book_client;
+	GError *error = NULL;
+	gchar **strv;
+
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (credentials != NULL);
+
+	book_client = E_BOOK_CLIENT (client);
+	g_return_if_fail (book_client != NULL);
+	g_return_if_fail (book_client->priv != NULL);
+
+	if (!book_client->priv->gdbus_book)
+		return;
+
+	strv = e_credentials_to_strv (credentials);
+	g_return_if_fail (strv != NULL);
+
+	e_gdbus_book_call_authenticate_user_sync (book_client->priv->gdbus_book, (const gchar * const *) strv, NULL, &error);
+
+	g_strfreev (strv);
+
+	if (error) {
+		g_debug ("%s: Failed to authenticate user: %s", G_STRFUNC, error->message);
+		g_error_free (error);
+	}
+}
+
+static gchar *
+book_client_retrieve_capabilities (EClient *client)
+{
+	EBookClient *book_client;
+	GError *error = NULL;
+	gchar *capabilities = NULL;
+
+	g_return_val_if_fail (client != NULL, NULL);
+
+	book_client = E_BOOK_CLIENT (client);
+	g_return_val_if_fail (book_client != NULL, NULL);
+	g_return_val_if_fail (book_client->priv != NULL, NULL);
+
+	if (!book_client->priv->gdbus_book)
+		return NULL;
+
+	e_gdbus_book_call_get_backend_property_sync (book_client->priv->gdbus_book, CLIENT_BACKEND_PROPERTY_CAPABILITIES, &capabilities, NULL, &error);
+
+	if (error) {
+		g_debug ("%s: Failed to retrieve capabilitites: %s", G_STRFUNC, error->message);
+		g_error_free (error);
+	}
+
+	return capabilities;
+}
+
+static void
+e_book_client_init (EBookClient *client)
+{
+	LOCK_FACTORY ();
+	active_book_clients++;
+	UNLOCK_FACTORY ();
+
+	client->priv = G_TYPE_INSTANCE_GET_PRIVATE (client, E_TYPE_BOOK_CLIENT, EBookClientPrivate);
+}
+
+static void
+book_client_dispose (GObject *object)
+{
+	EClient *client;
+
+	client = E_CLIENT (object);
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (client->priv != NULL);
+
+	e_client_cancel_all (client);
+
+	gdbus_book_client_disconnect (E_BOOK_CLIENT (client));
+
+	/* Chain up to parent's dispose() method. */
+	G_OBJECT_CLASS (e_book_client_parent_class)->dispose (object);
+}
+
+static void
+book_client_finalize (GObject *object)
+{
+	EBookClient *client;
+
+	client = E_BOOK_CLIENT (object);
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (client->priv != NULL);
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (e_book_client_parent_class)->finalize (object);
+
+	LOCK_FACTORY ();
+	active_book_clients--;
+	if (!active_book_clients)
+		gdbus_book_factory_proxy_disconnect (NULL);
+	UNLOCK_FACTORY ();
+}
+
+static void
+e_book_client_class_init (EBookClientClass *klass)
+{
+	GObjectClass *object_class;
+	EClientClass *client_class;
+
+	g_type_class_add_private (klass, sizeof (EBookClientPrivate));
+
+	object_class = G_OBJECT_CLASS (klass);
+	object_class->dispose = book_client_dispose;
+	object_class->finalize = book_client_finalize;
+
+	client_class = E_CLIENT_CLASS (klass);
+	client_class->get_dbus_proxy			= book_client_get_dbus_proxy;
+	client_class->unwrap_dbus_error			= book_client_unwrap_dbus_error;
+	client_class->handle_authentication		= book_client_handle_authentication;
+	client_class->retrieve_capabilities		= book_client_retrieve_capabilities;
+	client_class->get_backend_property		= book_client_get_backend_property;
+	client_class->get_backend_property_finish	= book_client_get_backend_property_finish;
+	client_class->get_backend_property_sync		= book_client_get_backend_property_sync;
+	client_class->set_backend_property		= book_client_set_backend_property;
+	client_class->set_backend_property_finish	= book_client_set_backend_property_finish;
+	client_class->set_backend_property_sync		= book_client_set_backend_property_sync;
+	client_class->open				= book_client_open;
+	client_class->open_finish			= book_client_open_finish;
+	client_class->open_sync				= book_client_open_sync;
+	client_class->remove				= book_client_remove;
+	client_class->remove_finish			= book_client_remove_finish;
+	client_class->remove_sync			= book_client_remove_sync;
+	client_class->refresh				= book_client_refresh;
+	client_class->refresh_finish			= book_client_refresh_finish;
+	client_class->refresh_sync			= book_client_refresh_sync;
+}
diff --git a/addressbook/libebook/e-book-client.h b/addressbook/libebook/e-book-client.h
new file mode 100644
index 0000000..2bd74f5
--- /dev/null
+++ b/addressbook/libebook/e-book-client.h
@@ -0,0 +1,131 @@
+/*
+ * e-book-client.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 2011 Red Hat, Inc. (www.redhat.com)
+ *
+ */
+
+#ifndef E_BOOK_CLIENT_H
+#define E_BOOK_CLIENT_H
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#include <libedataserver/e-client.h>
+#include <libedataserver/e-source-list.h>
+#include <libebook/e-book-client-view.h>
+#include <libebook/e-contact.h>
+
+G_BEGIN_DECLS
+
+#define E_TYPE_BOOK_CLIENT		(e_book_client_get_type ())
+#define E_BOOK_CLIENT(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_BOOK_CLIENT, EBookClient))
+#define E_BOOK_CLIENT_CLASS(k)		(G_TYPE_CHECK_CLASS_CAST ((k), E_TYPE_BOOK_CLIENT, EBookClientClass))
+#define E_IS_BOOK_CLIENT(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_BOOK_CLIENT))
+#define E_IS_BOOK_CLIENT_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_BOOK_CLIENT))
+#define E_BOOK_CLIENT_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_BOOK_CLIENT, EBookClientClass))
+
+#define BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS		"required-fields"
+#define BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS		"supported-fields"
+#define BOOK_BACKEND_PROPERTY_SUPPORTED_AUTH_METHODS	"supported-auth-methods"
+
+#define E_BOOK_CLIENT_ERROR e_book_client_error_quark ()
+
+GQuark e_book_client_error_quark (void) G_GNUC_CONST;
+
+typedef enum {
+	E_BOOK_CLIENT_ERROR_NO_SUCH_BOOK,
+	E_BOOK_CLIENT_ERROR_CONTACT_NOT_FOUND,
+	E_BOOK_CLIENT_ERROR_CONTACT_ID_ALREADY_EXISTS,
+	E_BOOK_CLIENT_ERROR_TLS_NOT_AVAILABLE,
+	E_BOOK_CLIENT_ERROR_NO_SUCH_SOURCE,
+	E_BOOK_CLIENT_ERROR_OFFLINE_UNAVAILABLE,
+	E_BOOK_CLIENT_ERROR_UNSUPPORTED_AUTHENTICATION_METHOD,
+	E_BOOK_CLIENT_ERROR_NO_SPACE
+} EBookClientError;
+
+const gchar *e_book_client_error_to_string (EBookClientError code);
+
+typedef struct _EBookClient        EBookClient;
+typedef struct _EBookClientClass   EBookClientClass;
+typedef struct _EBookClientPrivate EBookClientPrivate;
+
+struct _EBookClient {
+	EClient parent;
+
+	/*< private >*/
+	EBookClientPrivate *priv;
+};
+
+struct _EBookClientClass {
+	EClientClass parent;
+};
+
+GType		e_book_client_get_type				(void);
+
+/* Creating a new addressbook */
+EBookClient *	e_book_client_new				(ESource *source, GError **error);
+EBookClient *	e_book_client_new_from_uri			(const gchar *uri, GError **error);
+EBookClient *	e_book_client_new_system			(GError **error);
+EBookClient *	e_book_client_new_default			(GError **error);
+
+/* Addressbook discovery */
+gboolean	e_book_client_set_default			(EBookClient *client, GError **error);
+gboolean	e_book_client_set_default_source		(ESource *source, GError **error);
+gboolean	e_book_client_get_sources			(ESourceList **sources, GError **error);
+
+/* Identity */
+gboolean	e_book_client_get_self				(EContact **contact, EBookClient **client, GError **error);
+gboolean	e_book_client_set_self				(EBookClient *client, EContact *contact, GError **error);
+gboolean	e_book_client_is_self				(EContact *contact);
+
+/* Addressbook methods */
+void		e_book_client_add_contact			(EBookClient *client, /* const */ EContact *contact, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_book_client_add_contact_finish		(EBookClient *client, GAsyncResult *result, gchar **added_uid, GError **error);
+gboolean	e_book_client_add_contact_sync			(EBookClient *client, /* const */ EContact *contact, gchar **added_uid, GCancellable *cancellable, GError **error);
+
+void		e_book_client_modify_contact			(EBookClient *client, /* const */ EContact *contact, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_book_client_modify_contact_finish		(EBookClient *client, GAsyncResult *result, GError **error);
+gboolean	e_book_client_modify_contact_sync		(EBookClient *client, /* const */ EContact *contact, GCancellable *cancellable, GError **error);
+
+void		e_book_client_remove_contact			(EBookClient *client, /* const */ EContact *contact, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_book_client_remove_contact_finish		(EBookClient *client, GAsyncResult *result, GError **error);
+gboolean	e_book_client_remove_contact_sync		(EBookClient *client, /* const */ EContact *contact, GCancellable *cancellable, GError **error);
+
+void		e_book_client_remove_contact_by_uid		(EBookClient *client, const gchar *uid, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_book_client_remove_contact_by_uid_finish	(EBookClient *client, GAsyncResult *result, GError **error);
+gboolean	e_book_client_remove_contact_by_uid_sync	(EBookClient *client, const gchar *uid, GCancellable *cancellable, GError **error);
+
+void		e_book_client_remove_contacts			(EBookClient *client, const GSList *uids, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_book_client_remove_contacts_finish		(EBookClient *client, GAsyncResult *result, GError **error);
+gboolean	e_book_client_remove_contacts_sync		(EBookClient *client, const GSList *uids, GCancellable *cancellable, GError **error);
+
+void		e_book_client_get_contact			(EBookClient *client, const gchar *uid, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_book_client_get_contact_finish		(EBookClient *client, GAsyncResult *result, EContact **contact, GError **error);
+gboolean	e_book_client_get_contact_sync			(EBookClient *client, const gchar *uid, EContact **contact, GCancellable *cancellable, GError **error);
+
+void		e_book_client_get_contacts			(EBookClient *client, const gchar *sexp, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_book_client_get_contacts_finish		(EBookClient *client, GAsyncResult *result, GSList **contacts, GError **error);
+gboolean	e_book_client_get_contacts_sync			(EBookClient *client, const gchar *sexp, GSList **contacts, GCancellable *cancellable, GError **error);
+
+void		e_book_client_get_view				(EBookClient *client, const gchar *sexp, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_book_client_get_view_finish			(EBookClient *client, GAsyncResult *result, EBookClientView **view, GError **error);
+gboolean	e_book_client_get_view_sync			(EBookClient *client, const gchar *sexp, EBookClientView **view, GCancellable *cancellable, GError **error);
+
+G_END_DECLS
+
+#endif /* E_BOOK_CLIENT_H */
diff --git a/addressbook/libebook/e-book-view-private.h b/addressbook/libebook/e-book-view-private.h
index 16a6461..1b49f60 100644
--- a/addressbook/libebook/e-book-view-private.h
+++ b/addressbook/libebook/e-book-view-private.h
@@ -23,6 +23,7 @@
 #define __E_BOOK_VIEW_PRIVATE_H__
 
 #include "e-book.h"
+#include "e-book-client.h"
 #include "e-book-view.h"
 
 struct _EGdbusBookView;
diff --git a/addressbook/libebook/e-book-view.c b/addressbook/libebook/e-book-view.c
index ff48ea8..47288f1 100644
--- a/addressbook/libebook/e-book-view.c
+++ b/addressbook/libebook/e-book-view.c
@@ -21,12 +21,13 @@
  */
 
 #include <glib-object.h>
+
 #include "e-book.h"
 #include "e-book-view.h"
 #include "e-book-view-private.h"
 #include "e-book-marshal.h"
 #include "libedata-book/e-data-book-types.h"
-#include "e-gdbus-egdbusbookview.h"
+#include "e-gdbus-book-view.h"
 
 G_DEFINE_TYPE (EBookView, e_book_view, G_TYPE_OBJECT);
 
@@ -51,7 +52,7 @@ enum {
 static guint signals[LAST_SIGNAL];
 
 static void
-contacts_added_cb (EGdbusBookView *object, const gchar * const *vcards, EBookView *book_view)
+objects_added_cb (EGdbusBookView *object, const gchar * const *vcards, EBookView *book_view)
 {
 	const gchar * const *p;
 	GList *contacts = NULL;
@@ -72,7 +73,7 @@ contacts_added_cb (EGdbusBookView *object, const gchar * const *vcards, EBookVie
 }
 
 static void
-contacts_changed_cb (EGdbusBookView *object, const gchar * const *vcards, EBookView *book_view)
+objects_modified_cb (EGdbusBookView *object, const gchar * const *vcards, EBookView *book_view)
 {
 	const gchar * const *p;
 	GList *contacts = NULL;
@@ -92,7 +93,7 @@ contacts_changed_cb (EGdbusBookView *object, const gchar * const *vcards, EBookV
 }
 
 static void
-contacts_removed_cb (EGdbusBookView *object, const gchar * const *ids, EBookView *book_view)
+objects_removed_cb (EGdbusBookView *object, const gchar * const *ids, EBookView *book_view)
 {
 	const gchar * const *p;
 	GList *list = NULL;
@@ -112,7 +113,7 @@ contacts_removed_cb (EGdbusBookView *object, const gchar * const *ids, EBookView
 }
 
 static void
-status_message_cb (EGdbusBookView *object, const gchar *message, EBookView *book_view)
+progress_cb (EGdbusBookView *object, guint percent, const gchar *message, EBookView *book_view)
 {
 	if (!book_view->priv->running)
 		return;
@@ -121,14 +122,17 @@ status_message_cb (EGdbusBookView *object, const gchar *message, EBookView *book
 }
 
 static void
-complete_cb (EGdbusBookView *object, /* EDataBookStatus */ guint status, const gchar *message, EBookView *book_view)
+complete_cb (EGdbusBookView *object, const gchar * const *in_error_strv, EBookView *book_view)
 {
+	GError *error = NULL;
 	EBookViewStatus bv_status = E_BOOK_VIEW_ERROR_OTHER_ERROR;
 
 	if (!book_view->priv->running)
 		return;
 
-	switch (status) {
+	g_return_if_fail (e_gdbus_templates_decode_error (in_error_strv, &error));
+
+	switch (error ? error->code : E_DATA_BOOK_STATUS_SUCCESS) {
 	case E_DATA_BOOK_STATUS_SUCCESS:
 		bv_status = E_BOOK_VIEW_STATUS_OK;
 		break;
@@ -151,20 +155,12 @@ complete_cb (EGdbusBookView *object, /* EDataBookStatus */ guint status, const g
 	#ifndef E_BOOK_DISABLE_DEPRECATED
 	g_signal_emit (book_view, signals[SEQUENCE_COMPLETE], 0, bv_status);
 	#endif
-	g_signal_emit (book_view, signals[VIEW_COMPLETE], 0, bv_status, message);
+	g_signal_emit (book_view, signals[VIEW_COMPLETE], 0, bv_status, error ? error->message : "");
+
+	if (error)
+		g_error_free (error);
 }
 
-/*
- * e_book_view_new:
- * @book: an #EBook
- * @gdbus_bookview: The #EGdbusBookView to get signals from
- *
- * Creates a new #EBookView based on #EBook and listening to @gdbus_bookview.  This
- * is a private function, applications should call #e_book_get_book_view or
- * #e_book_async_get_book_view.
- *
- * Returns: A new #EBookView.
- **/
 EBookView *
 _e_book_view_new (EBook *book, EGdbusBookView *gdbus_bookview)
 {
@@ -180,10 +176,10 @@ _e_book_view_new (EBook *book, EGdbusBookView *gdbus_bookview)
 	priv->gdbus_bookview = gdbus_bookview;
 
 	g_object_add_weak_pointer (G_OBJECT (gdbus_bookview), (gpointer) &priv->gdbus_bookview);
-	g_signal_connect (priv->gdbus_bookview, "contacts-added", G_CALLBACK (contacts_added_cb), view);
-	g_signal_connect (priv->gdbus_bookview, "contacts-changed", G_CALLBACK (contacts_changed_cb), view);
-	g_signal_connect (priv->gdbus_bookview, "contacts-removed", G_CALLBACK (contacts_removed_cb), view);
-	g_signal_connect (priv->gdbus_bookview, "status-message", G_CALLBACK (status_message_cb), view);
+	g_signal_connect (priv->gdbus_bookview, "objects-added", G_CALLBACK (objects_added_cb), view);
+	g_signal_connect (priv->gdbus_bookview, "objects-modified", G_CALLBACK (objects_modified_cb), view);
+	g_signal_connect (priv->gdbus_bookview, "objects-removed", G_CALLBACK (objects_removed_cb), view);
+	g_signal_connect (priv->gdbus_bookview, "progress", G_CALLBACK (progress_cb), view);
 	g_signal_connect (priv->gdbus_bookview, "complete", G_CALLBACK (complete_cb), view);
 
 	return view;
@@ -223,7 +219,7 @@ e_book_view_start (EBookView *book_view)
 	book_view->priv->running = TRUE;
 
 	if (book_view->priv->gdbus_bookview) {
-		e_gdbus_book_view_call_start_sync (book_view->priv->gdbus_bookview, NULL, &error);
+		e_gdbus_book_view_call_start_sync (G_DBUS_PROXY (book_view->priv->gdbus_bookview), NULL, &error);
 		if (error) {
 			g_warning ("Cannot start book view: %s\n", error->message);
 
@@ -255,7 +251,7 @@ e_book_view_stop (EBookView *book_view)
 	book_view->priv->running = FALSE;
 
 	if (book_view->priv->gdbus_bookview) {
-		e_gdbus_book_view_call_stop_sync (book_view->priv->gdbus_bookview, NULL, &error);
+		e_gdbus_book_view_call_stop_sync (G_DBUS_PROXY (book_view->priv->gdbus_bookview), NULL, &error);
 		if (error) {
 			g_warning ("Cannot stop book view: %s\n", error->message);
 			g_error_free (error);
@@ -269,6 +265,7 @@ e_book_view_init (EBookView *book_view)
 	book_view->priv = G_TYPE_INSTANCE_GET_PRIVATE (
 		book_view, E_TYPE_BOOK_VIEW, EBookViewPrivate);
 	book_view->priv->gdbus_bookview = NULL;
+
 	book_view->priv->book = NULL;
 	book_view->priv->running = FALSE;
 }
@@ -282,7 +279,7 @@ e_book_view_dispose (GObject *object)
 		GError *error = NULL;
 
 		g_signal_handlers_disconnect_matched (book_view->priv->gdbus_bookview, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, book_view);
-		e_gdbus_book_view_call_dispose_sync (book_view->priv->gdbus_bookview, NULL, &error);
+		e_gdbus_book_view_call_dispose_sync (G_DBUS_PROXY (book_view->priv->gdbus_bookview), NULL, &error);
 		g_object_unref (book_view->priv->gdbus_bookview);
 		book_view->priv->gdbus_bookview = NULL;
 
diff --git a/addressbook/libebook/e-book-view.h b/addressbook/libebook/e-book-view.h
index 2148f74..36d6620 100644
--- a/addressbook/libebook/e-book-view.h
+++ b/addressbook/libebook/e-book-view.h
@@ -11,6 +11,8 @@
 #ifndef __E_BOOK_VIEW_H__
 #define __E_BOOK_VIEW_H__
 
+#ifndef E_BOOK_DISABLE_DEPRECATED
+
 #include <glib.h>
 #include <glib-object.h>
 #include "e-book-types.h"
@@ -59,13 +61,15 @@ struct _EBookViewClass {
 	void (*_ebook_reserved4) (void);
 };
 
-GType              e_book_view_get_type               (void);
+GType			e_book_view_get_type		(void);
 
-void               e_book_view_start                  (EBookView *book_view);
-void               e_book_view_stop                   (EBookView *book_view);
+void			e_book_view_start		(EBookView *book_view);
+void			e_book_view_stop		(EBookView *book_view);
 
-struct _EBook     *e_book_view_get_book               (EBookView *book_view);
+struct _EBook *		e_book_view_get_book		(EBookView *book_view);
 
 G_END_DECLS
 
+#endif /* E_BOOK_DISABLE_DEPRECATED */
+
 #endif /* __E_BOOK_VIEW_H__ */
diff --git a/addressbook/libebook/e-book.c b/addressbook/libebook/e-book.c
index 0b82efa..009e406 100644
--- a/addressbook/libebook/e-book.c
+++ b/addressbook/libebook/e-book.c
@@ -20,6 +20,9 @@
  * Author: Ross Burton <ross linux intel com>
  */
 
+/* e-book deprecated since 3.2, use e-book-client instead */
+#ifndef E_BOOK_DISABLE_DEPRECATED
+
 /**
  * SECTION:e-book
  *
@@ -28,6 +31,8 @@
  * structure in the asynchronous callback, instead of a status code only.
  *
  * As an example, e_book_async_open() is replaced by e_book_open_async().
+ *
+ * Deprecated: 3.2: Use #EBookClient instead.
  */
 
 #include <config.h>
@@ -43,9 +48,14 @@
 #include "e-book-view-private.h"
 #include "e-book-marshal.h"
 
-#include "e-gdbus-egdbusbookfactory.h"
-#include "e-gdbus-egdbusbook.h"
-#include "e-gdbus-egdbusbookview.h"
+#include "e-gdbus-book.h"
+#include "e-gdbus-book-factory.h"
+#include "e-gdbus-book-view.h"
+
+#define CLIENT_BACKEND_PROPERTY_CAPABILITIES		"capabilities"
+#define BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS		"required-fields"
+#define BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS		"supported-fields"
+#define BOOK_BACKEND_PROPERTY_SUPPORTED_AUTH_METHODS	"supported-auth-methods"
 
 static gchar ** flatten_stringlist (GList *list);
 static GList *array_to_stringlist (gchar **list);
@@ -65,7 +75,7 @@ enum {
 static guint e_book_signals[LAST_SIGNAL];
 
 struct _EBookPrivate {
-	EGdbusBook *gdbus_book;
+	GDBusProxy *gdbus_book;
 	guint gone_signal_id;
 
 	ESource *source;
@@ -347,27 +357,27 @@ e_book_activate (GError **error)
 }
 
 static void
-writable_cb (EGdbusBook *object, gboolean writable, EBook *book)
+readonly_cb (EGdbusBook *object, gboolean readonly, EBook *book)
 {
 	g_return_if_fail (E_IS_BOOK (book));
 
-	book->priv->writable = writable;
+	book->priv->writable = !readonly;
 
-	g_signal_emit (G_OBJECT (book), e_book_signals[WRITABLE_STATUS], 0, writable);
+	g_signal_emit (G_OBJECT (book), e_book_signals[WRITABLE_STATUS], 0, book->priv->writable);
 }
 
 static void
-connection_cb (EGdbusBook *object, gboolean connected, EBook *book)
+online_cb (EGdbusBook *object, gboolean is_online, EBook *book)
 {
 	g_return_if_fail (E_IS_BOOK (book));
 
-	book->priv->connected = connected;
+	book->priv->connected = is_online;
 
-	g_signal_emit (G_OBJECT (book), e_book_signals[CONNECTION_STATUS], 0, connected);
+	g_signal_emit (G_OBJECT (book), e_book_signals[CONNECTION_STATUS], 0, is_online);
 }
 
 static void
-auth_required_cb (EGdbusBook *object, EBook *book)
+auth_required_cb (EGdbusBook *object, const ECredentials *credentials, EBook *book)
 {
 	g_return_if_fail (E_IS_BOOK (book));
 
@@ -383,6 +393,8 @@ auth_required_cb (EGdbusBook *object, EBook *book)
  * Adds @contact to @book.
  *
  * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Deprecated: 3.2: Use e_book_client_add_contact_sync() instead.
  **/
 gboolean
 e_book_add_contact (EBook *book,
@@ -422,7 +434,7 @@ add_contact_reply (GObject *gdbus_book, GAsyncResult *res, gpointer user_data)
 	EBookIdCallback cb = data->callback;
 	#endif
 
-	e_gdbus_book_call_add_contact_finish (E_GDBUS_BOOK (gdbus_book), &uid, res, &error);
+	e_gdbus_book_call_add_contact_finish (G_DBUS_PROXY (gdbus_book), res, &uid, &error);
 
 	unwrap_gerror (error, &err);
 
@@ -505,6 +517,8 @@ e_book_async_add_contact (EBook *book,
  * Returns: %TRUE if the operation was started, %FALSE otherwise.
  *
  * Since: 2.32
+ *
+ * Deprecated: 3.2: Use e_book_client_add_contact() and e_book_client_add_contact_finish() instead.
  **/
 gboolean
 e_book_add_contact_async (EBook *book,
@@ -546,6 +560,8 @@ e_book_add_contact_async (EBook *book,
  * @book.
  *
  * Returns: %TRUE if successful, %FALSE otherwise
+ *
+ * Deprecated: 3.2: Use e_book_client_modify_contact_sync() instead.
  **/
 gboolean
 e_book_commit_contact (EBook *book,
@@ -579,7 +595,7 @@ modify_contact_reply (GObject *gdbus_book, GAsyncResult *res, gpointer user_data
 	EBookCallback cb = data->callback;
 	#endif
 
-	e_gdbus_book_call_modify_contact_finish (E_GDBUS_BOOK (gdbus_book), res, &error);
+	e_gdbus_book_call_modify_contact_finish (G_DBUS_PROXY (gdbus_book), res, &error);
 
 	unwrap_gerror (error, &err);
 
@@ -657,6 +673,8 @@ e_book_async_commit_contact (EBook *book,
  * Returns: %TRUE if the operation was started, %FALSE otherwise.
  *
  * Since: 2.32
+ *
+ * Deprecated: 3.2: Use e_book_client_modify_contact() and e_book_client_modify_contact_finish() instead.
  **/
 gboolean
 e_book_commit_contact_async (EBook *book,
@@ -700,6 +718,9 @@ e_book_commit_contact_async (EBook *book,
  * must be freed by the caller.
  *
  * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Deprecated: 3.2: Use e_client_get_backend_property_sync() on
+ * an #EBookClient object with #BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS instead.
  **/
 gboolean
 e_book_get_required_fields (EBook *book,
@@ -707,14 +728,17 @@ e_book_get_required_fields (EBook *book,
                             GError **error)
 {
 	GError *err = NULL;
-	gchar **list = NULL;
+	gchar **list = NULL, *list_str = NULL;
 
 	g_return_val_if_fail (E_IS_BOOK (book), FALSE);
 
 	e_return_error_if_fail (
 		book->priv->gdbus_book, E_BOOK_ERROR_REPOSITORY_OFFLINE);
 
-	e_gdbus_book_call_get_required_fields_sync (book->priv->gdbus_book, &list, NULL, &err);
+	e_gdbus_book_call_get_backend_property_sync (book->priv->gdbus_book, BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS, &list_str, NULL, &err);
+
+	list = g_strsplit (list_str, ",", -1);
+	g_free (list_str);
 
 	if (list) {
 		*fields = array_to_stringlist (list);
@@ -728,7 +752,7 @@ e_book_get_required_fields (EBook *book,
 static void
 get_required_fields_reply (GObject *gdbus_book, GAsyncResult *res, gpointer user_data)
 {
-	gchar **fields = NULL;
+	gchar **fields = NULL, *fields_str = NULL;
 	GError *err = NULL, *error = NULL;
 	AsyncData *data = user_data;
 	EBookEListAsyncCallback excb = data->excallback;
@@ -737,7 +761,10 @@ get_required_fields_reply (GObject *gdbus_book, GAsyncResult *res, gpointer user
 	#endif
 	EList *efields = NULL;
 
-	e_gdbus_book_call_get_required_fields_finish (E_GDBUS_BOOK (gdbus_book), &fields, res, &error);
+	e_gdbus_book_call_get_backend_property_finish (G_DBUS_PROXY (gdbus_book), res, &fields_str, &error);
+
+	fields = g_strsplit (fields_str, ",", -1);
+	g_free (fields_str);
 
 	efields = array_to_elist (fields);
 
@@ -790,7 +817,7 @@ e_book_async_get_required_fields (EBook *book,
 	data->callback = cb;
 	data->closure = closure;
 
-	e_gdbus_book_call_get_required_fields (book->priv->gdbus_book, NULL, get_required_fields_reply, data);
+	e_gdbus_book_call_get_backend_property (book->priv->gdbus_book, BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS, NULL, get_required_fields_reply, data);
 
 	return TRUE;
 }
@@ -808,6 +835,9 @@ e_book_async_get_required_fields (EBook *book,
  * Returns: %TRUE if the operation was started, %FALSE otherwise.
  *
  * Since: 2.32
+ *
+ * Deprecated: 3.2: Use e_client_get_backend_property() and e_client_get_backend_property_finish()
+ * on an #EBookClient object with #BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS instead.
  **/
 gboolean
 e_book_get_required_fields_async (EBook *book,
@@ -826,7 +856,7 @@ e_book_get_required_fields_async (EBook *book,
 	data->excallback = cb;
 	data->closure = closure;
 
-	e_gdbus_book_call_get_required_fields (book->priv->gdbus_book, NULL, get_required_fields_reply, data);
+	e_gdbus_book_call_get_backend_property (book->priv->gdbus_book, BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS, NULL, get_required_fields_reply, data);
 
 	return TRUE;
 }
@@ -843,6 +873,9 @@ e_book_get_required_fields_async (EBook *book,
  * #GList and the strings must be freed by the caller.
  *
  * Returns: %TRUE if successful, %FALSE otherwise
+ *
+ * Deprecated: 3.2: Use e_client_get_backend_property_sync() on
+ * an #EBookClient object with #BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS instead.
  **/
 gboolean
 e_book_get_supported_fields  (EBook *book,
@@ -850,15 +883,17 @@ e_book_get_supported_fields  (EBook *book,
                               GError **error)
 {
 	GError *err = NULL;
-	gchar **list = NULL;
+	gchar **list = NULL, *list_str = NULL;
 
 	g_return_val_if_fail (E_IS_BOOK (book), FALSE);
 
 	e_return_error_if_fail (
 		book->priv->gdbus_book, E_BOOK_ERROR_REPOSITORY_OFFLINE);
 
-	e_gdbus_book_call_get_supported_fields_sync (book->priv->gdbus_book, &list, NULL, &err);
+	e_gdbus_book_call_get_backend_property_sync (book->priv->gdbus_book, BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS, &list_str, NULL, &err);
 
+	list = g_strsplit (list_str, ",", -1);
+	g_free (list_str);
 	if (list) {
 		*fields = array_to_stringlist (list);
 		g_strfreev (list);
@@ -871,7 +906,7 @@ e_book_get_supported_fields  (EBook *book,
 static void
 get_supported_fields_reply (GObject *gdbus_book, GAsyncResult *res, gpointer user_data)
 {
-	gchar **fields = NULL;
+	gchar **fields = NULL, *fields_str = NULL;
 	GError *err = NULL, *error = NULL;
 	AsyncData *data = user_data;
 	EBookEListAsyncCallback excb = data->excallback;
@@ -880,7 +915,10 @@ get_supported_fields_reply (GObject *gdbus_book, GAsyncResult *res, gpointer use
 	#endif
 	EList *efields;
 
-	e_gdbus_book_call_get_supported_fields_finish (E_GDBUS_BOOK (gdbus_book), &fields, res, &error);
+	e_gdbus_book_call_get_backend_property_finish (G_DBUS_PROXY (gdbus_book), res, &fields_str, &error);
+
+	fields = g_strsplit (fields_str, ",", -1);
+	g_free (fields_str);
 
 	efields = array_to_elist (fields);
 
@@ -934,7 +972,7 @@ e_book_async_get_supported_fields (EBook *book,
 	data->callback = cb;
 	data->closure = closure;
 
-	e_gdbus_book_call_get_supported_fields (book->priv->gdbus_book, NULL, get_supported_fields_reply, data);
+	e_gdbus_book_call_get_backend_property (book->priv->gdbus_book, BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS, NULL, get_supported_fields_reply, data);
 
 	return TRUE;
 }
@@ -953,6 +991,9 @@ e_book_async_get_supported_fields (EBook *book,
  * Returns: %TRUE if successful, %FALSE otherwise.
  *
  * Since: 2.32
+ *
+ * Deprecated: 3.2: Use e_client_get_backend_property() and e_client_get_backend_property_finish()
+ * on an #EBookClient object with #BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS instead.
  **/
 gboolean
 e_book_get_supported_fields_async (EBook *book,
@@ -971,7 +1012,7 @@ e_book_get_supported_fields_async (EBook *book,
 	data->excallback = cb;
 	data->closure = closure;
 
-	e_gdbus_book_call_get_supported_fields (book->priv->gdbus_book, NULL, get_supported_fields_reply, data);
+	e_gdbus_book_call_get_backend_property (book->priv->gdbus_book, BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS, NULL, get_supported_fields_reply, data);
 
 	return TRUE;
 }
@@ -987,6 +1028,9 @@ e_book_get_supported_fields_async (EBook *book,
  * #GList and the strings must be freed by the caller.
  *
  * Returns: %TRUE if successful, %FALSE otherwise
+ *
+ * Deprecated: 3.2: Use e_client_get_backend_property_sync() on
+ * an #EBookClient object with #BOOK_BACKEND_PROPERTY_SUPPORTED_AUTH_METHODS instead.
  **/
 gboolean
 e_book_get_supported_auth_methods (EBook *book,
@@ -994,6 +1038,7 @@ e_book_get_supported_auth_methods (EBook *book,
                                    GError **error)
 {
 	GError *err = NULL;
+	gchar *list_str = NULL;
 	gchar **list = NULL;
 
 	g_return_val_if_fail (E_IS_BOOK (book), FALSE);
@@ -1001,7 +1046,10 @@ e_book_get_supported_auth_methods (EBook *book,
 	e_return_error_if_fail (
 		book->priv->gdbus_book, E_BOOK_ERROR_REPOSITORY_OFFLINE);
 
-	e_gdbus_book_call_get_supported_auth_methods_sync (book->priv->gdbus_book, &list, NULL, &err);
+	e_gdbus_book_call_get_backend_property_sync (book->priv->gdbus_book, BOOK_BACKEND_PROPERTY_SUPPORTED_AUTH_METHODS, &list_str, NULL, &err);
+
+	list = g_strsplit (list_str, ",", -1);
+	g_free (list_str);
 
 	if (list) {
 		*auth_methods = array_to_stringlist (list);
@@ -1015,7 +1063,7 @@ e_book_get_supported_auth_methods (EBook *book,
 static void
 get_supported_auth_methods_reply (GObject *gdbus_book, GAsyncResult *res, gpointer user_data)
 {
-	gchar **methods = NULL;
+	gchar **methods = NULL, *methods_str = NULL;
 	GError *err = NULL, *error = NULL;
 	AsyncData *data = user_data;
 	EBookEListAsyncCallback excb = data->excallback;
@@ -1024,7 +1072,10 @@ get_supported_auth_methods_reply (GObject *gdbus_book, GAsyncResult *res, gpoint
 	#endif
 	EList *emethods;
 
-	e_gdbus_book_call_get_supported_auth_methods_finish (E_GDBUS_BOOK (gdbus_book), &methods, res, &error);
+	e_gdbus_book_call_get_backend_property_finish (G_DBUS_PROXY (gdbus_book), res, &methods_str, &error);
+
+	methods = g_strsplit (methods_str, ",", -1);
+	g_free (methods_str);
 
 	emethods = array_to_elist (methods);
 
@@ -1077,7 +1128,7 @@ e_book_async_get_supported_auth_methods (EBook *book,
 	data->callback = cb;
 	data->closure = closure;
 
-	e_gdbus_book_call_get_supported_auth_methods (book->priv->gdbus_book, NULL, get_supported_auth_methods_reply, data);
+	e_gdbus_book_call_get_backend_property (book->priv->gdbus_book, BOOK_BACKEND_PROPERTY_SUPPORTED_AUTH_METHODS, NULL, get_supported_auth_methods_reply, data);
 
 	return TRUE;
 }
@@ -1095,6 +1146,9 @@ e_book_async_get_supported_auth_methods (EBook *book,
  * Returns: %TRUE if successful, %FALSE otherwise.
  *
  * Since: 2.32
+ *
+ * Deprecated: 3.2: Use e_client_get_backend_property() and e_client_get_backend_property_finish()
+ * on an #EBookClient object with #BOOK_BACKEND_PROPERTY_SUPPORTED_AUTH_METHODS instead.
  **/
 gboolean
 e_book_get_supported_auth_methods_async (EBook *book,
@@ -1113,7 +1167,7 @@ e_book_get_supported_auth_methods_async (EBook *book,
 	data->excallback = cb;
 	data->closure = closure;
 
-	e_gdbus_book_call_get_supported_auth_methods (book->priv->gdbus_book, NULL, get_supported_auth_methods_reply, data);
+	e_gdbus_book_call_get_backend_property (book->priv->gdbus_book, BOOK_BACKEND_PROPERTY_SUPPORTED_AUTH_METHODS, NULL, get_supported_auth_methods_reply, data);
 
 	return TRUE;
 }
@@ -1131,6 +1185,8 @@ e_book_get_supported_auth_methods_async (EBook *book,
  * methods returned using e_book_get_supported_auth_methods.
  *
  * Returns: %TRUE if successful, %FALSE otherwise
+ *
+ * Deprecated: 3.2: Connect to EClient::authenticate signal instead.
  **/
 gboolean
 e_book_authenticate_user (EBook *book,
@@ -1140,21 +1196,26 @@ e_book_authenticate_user (EBook *book,
                           GError **error)
 {
 	GError *err = NULL;
-	gchar *gdbus_user = NULL, *gdbus_passwd = NULL, *gdbus_auth_method = NULL;
+	ECredentials *credentials;
+	gchar **credentials_strv;
 
 	g_return_val_if_fail (E_IS_BOOK (book), FALSE);
 
 	e_return_error_if_fail (
 		book->priv->gdbus_book, E_BOOK_ERROR_REPOSITORY_OFFLINE);
 
-	e_gdbus_book_call_authenticate_user_sync (book->priv->gdbus_book,
-		e_util_ensure_gdbus_string (user, &gdbus_user),
-		e_util_ensure_gdbus_string (passwd, &gdbus_passwd),
-		e_util_ensure_gdbus_string (auth_method, &gdbus_auth_method), NULL, &err);
+	credentials = e_credentials_new_args (
+		E_CREDENTIALS_KEY_USERNAME, user,
+		E_CREDENTIALS_KEY_PASSWORD, passwd,
+		E_CREDENTIALS_KEY_AUTH_METHOD, auth_method,
+		NULL);
+
+	credentials_strv = e_credentials_to_strv (credentials);
 
-	g_free (gdbus_user);
-	g_free (gdbus_passwd);
-	g_free (gdbus_auth_method);
+	e_gdbus_book_call_authenticate_user_sync (book->priv->gdbus_book, (const gchar * const *) credentials_strv, NULL, &err);
+
+	g_strfreev (credentials_strv);
+	e_credentials_free (credentials);
 
 	return unwrap_gerror (err, error);
 }
@@ -1169,7 +1230,7 @@ authenticate_user_reply (GObject *gdbus_book, GAsyncResult *res, gpointer user_d
 	EBookCallback cb = data->callback;
 	#endif
 
-	e_gdbus_book_call_authenticate_user_finish (E_GDBUS_BOOK (gdbus_book), res, &error);
+	e_gdbus_book_call_authenticate_user_finish (G_DBUS_PROXY (gdbus_book), res, &error);
 
 	unwrap_gerror (error, &err);
 
@@ -1215,7 +1276,8 @@ e_book_async_authenticate_user (EBook *book,
                                 gpointer closure)
 {
 	AsyncData *data;
-	gchar *gdbus_user = NULL, *gdbus_passwd = NULL, *gdbus_auth_method = NULL;
+	ECredentials *credentials;
+	gchar **credentials_strv;
 
 	g_return_val_if_fail (E_IS_BOOK (book), FALSE);
 	g_return_val_if_fail (user != NULL, FALSE);
@@ -1230,14 +1292,18 @@ e_book_async_authenticate_user (EBook *book,
 	data->callback = cb;
 	data->closure = closure;
 
-	e_gdbus_book_call_authenticate_user (book->priv->gdbus_book,
-		e_util_ensure_gdbus_string (user, &gdbus_user),
-		e_util_ensure_gdbus_string (passwd, &gdbus_passwd),
-		e_util_ensure_gdbus_string (auth_method, &gdbus_auth_method), NULL, authenticate_user_reply, data);
+	credentials = e_credentials_new_args (
+		E_CREDENTIALS_KEY_USERNAME, user,
+		E_CREDENTIALS_KEY_PASSWORD, passwd,
+		E_CREDENTIALS_KEY_AUTH_METHOD, auth_method,
+		NULL);
+
+	credentials_strv = e_credentials_to_strv (credentials);
 
-	g_free (gdbus_user);
-	g_free (gdbus_passwd);
-	g_free (gdbus_auth_method);
+	e_gdbus_book_call_authenticate_user (book->priv->gdbus_book, (const gchar * const *) credentials_strv, NULL, authenticate_user_reply, data);
+
+	g_strfreev (credentials_strv);
+	e_credentials_free (credentials);
 
 	return TRUE;
 }
@@ -1260,6 +1326,8 @@ e_book_async_authenticate_user (EBook *book,
  * Returns: %FALSE if successful, %TRUE otherwise.
  *
  * Since: 2.32
+ *
+ * Deprecated: 3.2: Connect to EClient::authenticate signal instead.
  **/
 gboolean
 e_book_authenticate_user_async (EBook *book,
@@ -1270,7 +1338,8 @@ e_book_authenticate_user_async (EBook *book,
                                 gpointer closure)
 {
 	AsyncData *data;
-	gchar *gdbus_user = NULL, *gdbus_passwd = NULL, *gdbus_auth_method = NULL;
+	ECredentials *credentials;
+	gchar **credentials_strv;
 
 	g_return_val_if_fail (E_IS_BOOK (book), FALSE);
 	g_return_val_if_fail (user != NULL, FALSE);
@@ -1285,14 +1354,18 @@ e_book_authenticate_user_async (EBook *book,
 	data->excallback = cb;
 	data->closure = closure;
 
-	e_gdbus_book_call_authenticate_user (book->priv->gdbus_book,
-		e_util_ensure_gdbus_string (user, &gdbus_user),
-		e_util_ensure_gdbus_string (passwd, &gdbus_passwd),
-		e_util_ensure_gdbus_string (auth_method, &gdbus_auth_method), NULL, authenticate_user_reply, data);
+	credentials = e_credentials_new_args (
+		E_CREDENTIALS_KEY_USERNAME, user,
+		E_CREDENTIALS_KEY_PASSWORD, passwd,
+		E_CREDENTIALS_KEY_AUTH_METHOD, auth_method,
+		NULL);
 
-	g_free (gdbus_user);
-	g_free (gdbus_passwd);
-	g_free (gdbus_auth_method);
+	credentials_strv = e_credentials_to_strv (credentials);
+
+	e_gdbus_book_call_authenticate_user (book->priv->gdbus_book, (const gchar * const *) credentials_strv, NULL, authenticate_user_reply, data);
+
+	g_strfreev (credentials_strv);
+	e_credentials_free (credentials);
 
 	return TRUE;
 }
@@ -1308,6 +1381,8 @@ e_book_authenticate_user_async (EBook *book,
  * corresponding to @id.
  *
  * Returns: %TRUE if successful, %FALSE otherwise
+ *
+ * Deprecated: 3.2: Use e_book_client_get_contact_sync() instead.
  **/
 gboolean
 e_book_get_contact (EBook *book,
@@ -1346,7 +1421,7 @@ get_contact_reply (GObject *gdbus_book, GAsyncResult *res, gpointer user_data)
 	EBookContactCallback cb = data->callback;
 	#endif
 
-	e_gdbus_book_call_get_contact_finish (E_GDBUS_BOOK (gdbus_book), &vcard, res, &error);
+	e_gdbus_book_call_get_contact_finish (G_DBUS_PROXY (gdbus_book), res, &vcard, &error);
 
 	unwrap_gerror (error, &err);
 
@@ -1423,6 +1498,8 @@ e_book_async_get_contact (EBook *book,
  * Returns: %FALSE if successful, %TRUE otherwise
  *
  * Since: 2.32
+ *
+ * Deprecated: 3.2: Use e_book_client_get_contact() and e_book_client_get_contact_finish() instead.
  **/
 gboolean
 e_book_get_contact_async (EBook *book,
@@ -1460,6 +1537,8 @@ e_book_get_contact_async (EBook *book,
  * Removes the contact with id @id from @book.
  *
  * Returns: %TRUE if successful, %FALSE otherwise
+ *
+ * Deprecated: 3.2: Use e_book_client_remove_contact_by_uid_sync() or e_book_client_remove_contact_sync() instead.
  **/
 gboolean
 e_book_remove_contact (EBook *book,
@@ -1495,7 +1574,7 @@ remove_contact_reply (GObject *gdbus_book, GAsyncResult *res, gpointer user_data
 	EBookCallback cb = data->callback;
 	#endif
 
-	e_gdbus_book_call_remove_contacts_finish (E_GDBUS_BOOK (gdbus_book), res, &error);
+	e_gdbus_book_call_remove_contacts_finish (G_DBUS_PROXY (gdbus_book), res, &error);
 
 	unwrap_gerror (error, &err);
 
@@ -1525,6 +1604,8 @@ remove_contact_reply (GObject *gdbus_book, GAsyncResult *res, gpointer user_data
  * as a batch request.
  *
  * Returns: %TRUE if successful, %FALSE otherwise
+ *
+ * Deprecated: 3.2: Use e_book_client_remove_contacts_sync() instead.
  **/
 gboolean
 e_book_remove_contacts (EBook *book,
@@ -1606,6 +1687,8 @@ e_book_async_remove_contact (EBook *book,
  * Returns: %TRUE if successful, %FALSE otherwise
  *
  * Since: 2.32
+ *
+ * Deprecated: 3.2: Use e_book_client_remove_contact() and e_book_client_remove_contact_finish() instead.
  **/
 gboolean
 e_book_remove_contact_async (EBook *book,
@@ -1647,7 +1730,7 @@ remove_contact_by_id_reply (GObject *gdbus_book, GAsyncResult *res, gpointer use
 	EBookCallback cb = data->callback;
 	#endif
 
-	e_gdbus_book_call_remove_contacts_finish (E_GDBUS_BOOK (gdbus_book), res, &error);
+	e_gdbus_book_call_remove_contacts_finish (G_DBUS_PROXY (gdbus_book), res, &error);
 
 	unwrap_gerror (error, &err);
 
@@ -1722,6 +1805,8 @@ e_book_async_remove_contact_by_id (EBook *book,
  * Returns: %TRUE if successful, %FALSE otherwise
  *
  * Since: 2.32
+ *
+ * Deprecated: 3.2: Use e_book_client_remove_contact_by_uid() and e_book_client_remove_contact_by_uid_finish() instead.
  **/
 gboolean
 e_book_remove_contact_by_id_async (EBook *book,
@@ -1763,7 +1848,7 @@ remove_contacts_reply (GObject *gdbus_book, GAsyncResult *res, gpointer user_dat
 	EBookCallback cb = data->callback;
 	#endif
 
-	e_gdbus_book_call_remove_contacts_finish (E_GDBUS_BOOK (gdbus_book), res, &error);
+	e_gdbus_book_call_remove_contacts_finish (G_DBUS_PROXY (gdbus_book), res, &error);
 
 	unwrap_gerror (error, &err);
 
@@ -1848,6 +1933,8 @@ e_book_async_remove_contacts (EBook *book,
  * Returns: %TRUE if successful, %FALSE otherwise
  *
  * Since: 2.32
+ *
+ * Deprecated: 3.2: Use e_book_client_remove_contacts() and e_book_client_remove_contacts_finish() instead.
  **/
 gboolean
 e_book_remove_contacts_async (EBook *book,
@@ -1898,6 +1985,8 @@ e_book_remove_contacts_async (EBook *book,
  * error, @error is set and %FALSE returned.
  *
  * Returns: %TRUE if successful, %FALSE otherwise
+ *
+ * Deprecated: 3.2: Use e_book_client_get_view_sync() instead.
  **/
 gboolean
 e_book_get_book_view (EBook       *book,
@@ -1919,7 +2008,7 @@ e_book_get_book_view (EBook       *book,
 
 	sexp = e_book_query_to_string (query);
 
-	if (!e_gdbus_book_call_get_book_view_sync (book->priv->gdbus_book, e_util_ensure_gdbus_string (sexp, &gdbus_sexp), max_results, &view_path, NULL, &err)) {
+	if (!e_gdbus_book_call_get_view_sync (book->priv->gdbus_book, e_util_ensure_gdbus_string (sexp, &gdbus_sexp), &view_path, NULL, &err)) {
 		*book_view = NULL;
 		g_free (sexp);
 		g_free (gdbus_sexp);
@@ -1963,7 +2052,7 @@ get_book_view_reply (GObject *gdbus_book, GAsyncResult *res, gpointer user_data)
 	#endif
 	EGdbusBookView *gdbus_bookview;
 
-	e_gdbus_book_call_get_book_view_finish (E_GDBUS_BOOK (gdbus_book), &view_path, res, &error);
+	e_gdbus_book_call_get_view_finish (G_DBUS_PROXY (gdbus_book), res, &view_path, &error);
 
 	if (view_path) {
 		gdbus_bookview = e_gdbus_book_view_proxy_new_sync (g_dbus_proxy_get_connection (G_DBUS_PROXY (book_factory_proxy)),
@@ -2034,7 +2123,7 @@ e_book_async_get_book_view (EBook *book,
 
 	sexp = e_book_query_to_string (query);
 
-	e_gdbus_book_call_get_book_view (book->priv->gdbus_book, e_util_ensure_gdbus_string (sexp, &gdbus_sexp), max_results, NULL, get_book_view_reply, data);
+	e_gdbus_book_call_get_view (book->priv->gdbus_book, e_util_ensure_gdbus_string (sexp, &gdbus_sexp), NULL, get_book_view_reply, data);
 
 	g_free (sexp);
 	g_free (gdbus_sexp);
@@ -2059,6 +2148,8 @@ e_book_async_get_book_view (EBook *book,
  * Returns: %FALSE if successful, %TRUE otherwise
  *
  * Since: 2.32
+ *
+ * Deprecated: 3.2: Use e_book_client_get_view() and e_book_client_get_view_finish() instead.
  **/
 gboolean
 e_book_get_book_view_async (EBook *book,
@@ -2084,7 +2175,7 @@ e_book_get_book_view_async (EBook *book,
 
 	sexp = e_book_query_to_string (query);
 
-	e_gdbus_book_call_get_book_view (book->priv->gdbus_book, e_util_ensure_gdbus_string (sexp, &gdbus_sexp), max_results, NULL, get_book_view_reply, data);
+	e_gdbus_book_call_get_view (book->priv->gdbus_book, e_util_ensure_gdbus_string (sexp, &gdbus_sexp), NULL, get_book_view_reply, data);
 
 	g_free (sexp);
 	g_free (gdbus_sexp);
@@ -2103,6 +2194,8 @@ e_book_get_book_view_async (EBook *book,
  * matched. On failed, @error will be set and %FALSE returned.
  *
  * Returns: %TRUE on success, %FALSE otherwise
+ *
+ * Deprecated: 3.2: Use e_book_client_get_contacts_sync() instead.
  **/
 gboolean
 e_book_get_contacts (EBook       *book,
@@ -2152,7 +2245,7 @@ get_contacts_reply (GObject *gdbus_book, GAsyncResult *res, gpointer user_data)
 	EBookListCallback cb = data->callback;
 	#endif
 
-	e_gdbus_book_call_get_contact_list_finish (E_GDBUS_BOOK (gdbus_book), &vcards, res, &error);
+	e_gdbus_book_call_get_contact_list_finish (G_DBUS_PROXY (gdbus_book), res, &vcards, &error);
 
 	unwrap_gerror (error, &err);
 
@@ -2240,6 +2333,8 @@ e_book_async_get_contacts (EBook *book,
  * Returns: %FALSE on success, %TRUE otherwise
  *
  * Since: 2.32
+ *
+ * Deprecated: 3.2: Use e_book_client_get_contacts() and e_book_client_get_contacts_finish() instead.
  **/
 gboolean
 e_book_get_contacts_async (EBook *book,
@@ -2313,6 +2408,8 @@ parse_changes_array (GVariant *var_changes)
  * for a given change ID.
  *
  * Returns: %TRUE on success, %FALSE otherwise
+ *
+ * Deprecated: 3.2: This function has been dropped completely.
  */
 gboolean
 e_book_get_changes (EBook       *book,
@@ -2329,7 +2426,7 @@ e_book_get_changes (EBook       *book,
 	e_return_error_if_fail (
 		book->priv->gdbus_book, E_BOOK_ERROR_REPOSITORY_OFFLINE);
 
-	e_gdbus_book_call_get_changes_sync (book->priv->gdbus_book, e_util_ensure_gdbus_string (changeid, &gdbus_changeid), &var_changes, NULL, &err);
+	/*e_gdbus_book_call_get_changes_sync (book->priv->gdbus_book, e_util_ensure_gdbus_string (changeid, &gdbus_changeid), &var_changes, NULL, &err);*/
 
 	g_free (gdbus_changeid);
 
@@ -2344,42 +2441,6 @@ e_book_get_changes (EBook       *book,
 	}
 }
 
-static void
-get_changes_reply (GObject *gdbus_book, GAsyncResult *res, gpointer user_data)
-{
-	GVariant *var_changes = NULL;
-	GError *err = NULL, *error = NULL;
-	AsyncData *data = user_data;
-	EBookListAsyncCallback excb = data->excallback;
-	#ifndef E_BOOK_DISABLE_DEPRECATED
-	EBookListCallback cb = data->callback;
-	#endif
-	GList *list = NULL;
-
-	e_gdbus_book_call_get_changes_finish (E_GDBUS_BOOK (gdbus_book), &var_changes, res, &error);
-
-	unwrap_gerror (error, &err);
-
-	if (var_changes) {
-		list = parse_changes_array (var_changes);
-		g_variant_unref (var_changes);
-	}
-
-	#ifndef E_BOOK_DISABLE_DEPRECATED
-	if (cb)
-		cb (data->book, err ? err->code : E_BOOK_ERROR_OK, list, data->closure);
-	#endif
-
-	if (excb)
-		excb (data->book, err, list, data->closure);
-
-	if (err)
-		g_error_free (err);
-
-	g_object_unref (data->book);
-	g_slice_free (AsyncData, data);
-}
-
 #ifndef E_BOOK_DISABLE_DEPRECATED
 /**
  * e_book_async_get_changes:
@@ -2401,22 +2462,12 @@ e_book_async_get_changes (EBook *book,
                           EBookListCallback cb,
                           gpointer closure)
 {
-	AsyncData *data;
-	gchar *gdbus_changeid = NULL;
-
 	g_return_val_if_fail (E_IS_BOOK (book), FALSE);
 
 	e_return_async_error_val_if_fail (
 		book->priv->gdbus_book, E_BOOK_ERROR_REPOSITORY_OFFLINE);
 
-	data = g_slice_new0 (AsyncData);
-	data->book = g_object_ref (book);
-	data->callback = cb;
-	data->closure = closure;
-
-	e_gdbus_book_call_get_changes (book->priv->gdbus_book, e_util_ensure_gdbus_string (changeid, &gdbus_changeid), NULL, get_changes_reply, data);
-
-	g_free (gdbus_changeid);
+	cb (book, E_BOOK_ERROR_NOT_SUPPORTED, NULL, closure);
 
 	return TRUE;
 }
@@ -2435,6 +2486,8 @@ e_book_async_get_changes (EBook *book,
  * Returns: %TRUE on success, %FALSE otherwise
  *
  * Since: 2.32
+ *
+ * Deprecated: 3.2: This function has been dropped completely.
  */
 gboolean
 e_book_get_changes_async (EBook *book,
@@ -2442,22 +2495,16 @@ e_book_get_changes_async (EBook *book,
                           EBookListAsyncCallback cb,
                           gpointer closure)
 {
-	AsyncData *data;
-	gchar *gdbus_changeid = NULL;
+	GError *error;
 
 	g_return_val_if_fail (E_IS_BOOK (book), FALSE);
 
 	e_return_ex_async_error_val_if_fail (
 		book->priv->gdbus_book, E_BOOK_ERROR_REPOSITORY_OFFLINE);
 
-	data = g_slice_new0 (AsyncData);
-	data->book = g_object_ref (book);
-	data->excallback = cb;
-	data->closure = closure;
-
-	e_gdbus_book_call_get_changes (book->priv->gdbus_book, e_util_ensure_gdbus_string (changeid, &gdbus_changeid), NULL, get_changes_reply, data);
-
-	g_free (gdbus_changeid);
+	error = g_error_new (E_BOOK_ERROR, E_BOOK_ERROR_NOT_SUPPORTED, "Not supported");
+	cb (book, error, NULL, closure);
+	g_error_free (error);
 
 	return TRUE;
 }
@@ -2467,6 +2514,8 @@ e_book_get_changes_async (EBook *book,
  * @change_list: a #GList of #EBookChange items
  *
  * Free the contents of #change_list, and the list itself.
+ *
+ * Deprecated: 3.2: Related function has been dropped completely.
  */
 void
 e_book_free_change_list (GList *change_list)
@@ -2498,6 +2547,8 @@ e_book_free_change_list (GList *change_list)
  * return with a status of E_BOOK_STATUS_CANCELLED.
  *
  * Returns: %TRUE on success, %FALSE otherwise
+ *
+ * Deprecated: 3.2: Use e_client_cancel_all() or e_client_cancel_op() on an #EBookClient object instead.
  **/
 gboolean
 e_book_cancel (EBook   *book,
@@ -2508,7 +2559,7 @@ e_book_cancel (EBook   *book,
 	e_return_error_if_fail (
 		book->priv->gdbus_book, E_BOOK_ERROR_REPOSITORY_OFFLINE);
 
-	return e_gdbus_book_call_cancel_operation_sync (book->priv->gdbus_book, NULL, error);
+	return e_gdbus_book_call_cancel_all_sync (book->priv->gdbus_book, NULL, error);
 }
 
 /**
@@ -2518,6 +2569,8 @@ e_book_cancel (EBook   *book,
  * asynchronous operation.
  *
  * Since: 2.24
+ *
+ * Deprecated: 3.2: Use e_client_cancel_all() or e_client_cancel_op() on an #EBookClient object instead.
  **/
 gboolean
 e_book_cancel_async_op (EBook *book, GError **error)
@@ -2527,7 +2580,7 @@ e_book_cancel_async_op (EBook *book, GError **error)
 	e_return_error_if_fail (
 		book->priv->gdbus_book, E_BOOK_ERROR_REPOSITORY_OFFLINE);
 
-	return e_gdbus_book_call_cancel_operation_sync (book->priv->gdbus_book, NULL, error);
+	return e_gdbus_book_call_cancel_all_sync (book->priv->gdbus_book, NULL, error);
 }
 
 /**
@@ -2539,6 +2592,8 @@ e_book_cancel_async_op (EBook *book, GError **error)
  * Opens the addressbook, making it ready for queries and other operations.
  *
  * Returns: %TRUE if the book was successfully opened, %FALSE otherwise.
+ *
+ * Deprecated: 3.2: Use e_client_open_sync() on an #EBookClient object instead.
  */
 gboolean
 e_book_open (EBook     *book,
@@ -2575,7 +2630,7 @@ open_reply (GObject *gdbus_book, GAsyncResult *res, gpointer user_data)
 	EBookCallback cb = data->callback;
 	#endif
 
-	e_gdbus_book_call_open_finish (E_GDBUS_BOOK (gdbus_book), res, &error);
+	e_gdbus_book_call_open_finish (G_DBUS_PROXY (gdbus_book), res, &error);
 
 	unwrap_gerror (error, &err);
 
@@ -2647,6 +2702,8 @@ e_book_async_open (EBook *book,
  * Returns: %FALSE if successful, %TRUE otherwise.
  *
  * Since: 2.32
+ *
+ * Deprecated: 3.2: Use e_client_open() and e_client_open_finish() on an #EBookClient object instead.
  **/
 gboolean
 e_book_open_async (EBook *book,
@@ -2680,6 +2737,8 @@ e_book_open_async (EBook *book,
  * deletes the database file. You cannot get it back!
  *
  * Returns: %TRUE on success, %FALSE on failure.
+ *
+ * Deprecated: 3.2: Use e_client_remove_sync() on an #EBookClient object instead.
  */
 gboolean
 e_book_remove (EBook   *book,
@@ -2707,7 +2766,7 @@ remove_reply (GObject *gdbus_book, GAsyncResult *res, gpointer user_data)
 	EBookCallback cb = data->callback;
 	#endif
 
-	e_gdbus_book_call_remove_finish (E_GDBUS_BOOK (gdbus_book), res, &error);
+	e_gdbus_book_call_remove_finish (G_DBUS_PROXY (gdbus_book), res, &error);
 
 	unwrap_gerror (error, &err);
 
@@ -2774,6 +2833,8 @@ e_book_async_remove (EBook *book,
  * Returns: %FALSE if successful, %TRUE otherwise.
  *
  * Since: 2.32
+ *
+ * Deprecated: 3.2: Use e_client_remove() and e_client_remove_finish() on an #EBookClient object instead.
  **/
 gboolean
 e_book_remove_async (EBook *book,
@@ -2804,6 +2865,8 @@ e_book_remove_async (EBook *book,
  * Get the URI that this book has loaded. This string should not be freed.
  *
  * Returns: The URI.
+ *
+ * Deprecated: 3.2: Use e_client_get_uri() on an #EBookClient object instead.
  */
 const gchar *
 e_book_get_uri (EBook *book)
@@ -2820,6 +2883,8 @@ e_book_get_uri (EBook *book)
  * Get the #ESource that this book has loaded.
  *
  * Returns: (transfer none): The source.
+ *
+ * Deprecated: 3.2: Use e_client_get_source() on an #EBookClient object instead.
  */
 ESource *
 e_book_get_source (EBook *book)
@@ -2838,6 +2903,8 @@ e_book_get_source (EBook *book)
  * supports. This string should not be freed.
  *
  * Returns: The capabilities list
+ *
+ * Deprecated: 3.2: Use e_client_get_capabilities() on an #EBookClient object.
  */
 const gchar *
 e_book_get_static_capabilities (EBook *book,
@@ -2851,7 +2918,7 @@ e_book_get_static_capabilities (EBook *book,
 	if (!book->priv->cap_queried) {
 		gchar *cap = NULL;
 
-		if (!e_gdbus_book_call_get_static_capabilities_sync (book->priv->gdbus_book, &cap, NULL, error)) {
+		if (!e_gdbus_book_call_get_backend_property_sync (book->priv->gdbus_book, CLIENT_BACKEND_PROPERTY_CAPABILITIES, &cap, NULL, error)) {
 			return NULL;
 		}
 
@@ -2871,6 +2938,8 @@ e_book_get_static_capabilities (EBook *book,
  * @cap.
  *
  * Returns: %TRUE if the backend supports @cap, %FALSE otherwise.
+ *
+ * Deprecated: 3.2: Use e_client_check_capability() on an #EBookClient object instead.
  */
 gboolean
 e_book_check_static_capability (EBook *book,
@@ -2896,6 +2965,8 @@ e_book_check_static_capability (EBook *book,
  * Check if this book has been opened.
  *
  * Returns: %TRUE if this book has been opened, otherwise %FALSE.
+ *
+ * Deprecated: 3.2: Use e_client_is_opened() on an #EBookClient object instead.
  */
 gboolean
 e_book_is_opened (EBook *book)
@@ -2912,6 +2983,8 @@ e_book_is_opened (EBook *book)
  * Check if this book is writable.
  *
  * Returns: %TRUE if this book is writable, otherwise %FALSE.
+ *
+ * Deprecated: 3.2: Use e_client_is_readonly() on an #EBookClient object instead.
  */
 gboolean
 e_book_is_writable (EBook *book)
@@ -2928,6 +3001,8 @@ e_book_is_writable (EBook *book)
  * Check if this book is connected.
  *
  * Returns: %TRUE if this book is connected, otherwise %FALSE.
+ *
+ * Deprecated: 3.2: Use e_client_is_online() on an #EBookClient object instead.
  **/
 gboolean
 e_book_is_online (EBook *book)
@@ -2986,6 +3061,8 @@ make_me_card (void)
  * and set it in @contact and @book.
  *
  * Returns: %TRUE if successful, otherwise %FALSE.
+ *
+ * Deprecated: 3.2: Use e_book_client_get_self() instead.
  **/
 gboolean
 e_book_get_self (EContact **contact, EBook **book, GError **error)
@@ -3053,6 +3130,8 @@ e_book_get_self (EContact **contact, EBook **book, GError **error)
  * refers to the user of the address book.
  *
  * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Deprecated: 3.2: Use e_book_client_set_self() instead.
  **/
 gboolean
 e_book_set_self (EBook *book, EContact *contact, GError **error)
@@ -3076,6 +3155,8 @@ e_book_set_self (EBook *book, EContact *contact, GError **error)
  * Check if @contact is the user of the address book.
  *
  * Returns: %TRUE if @contact is the user, %FALSE otherwise.
+ *
+ * Deprecated: 3.2: Use e_book_client_is_self() instead.
  **/
 gboolean
 e_book_is_self (EContact *contact)
@@ -3108,6 +3189,8 @@ e_book_is_self (EContact *contact)
  * that will be loaded in the e_book_get_default_addressbook call.
  *
  * Returns: %TRUE if the setting was stored in libebook's ESourceList, otherwise %FALSE.
+ *
+ * Deprecated: 3.2: Use e_book_client_set_default_addressbook() instead.
  */
 gboolean
 e_book_set_default_addressbook (EBook *book, GError **error)
@@ -3134,6 +3217,8 @@ e_book_set_default_addressbook (EBook *book, GError **error)
  * will be loaded in the e_book_get_default_addressbook call.
  *
  * Returns: %TRUE if the setting was stored in libebook's ESourceList, otherwise %FALSE.
+ *
+ * Deprecated: 3.2: Use e_book_client_set_default_source() instead.
  */
 gboolean
 e_book_set_default_source (ESource *source, GError **error)
@@ -3199,6 +3284,8 @@ e_book_set_default_source (ESource *source, GError **error)
  * added to Evolution.
  *
  * Returns: %TRUE if @addressbook_sources was set, otherwise %FALSE.
+ *
+ * Deprecated: 3.2: Use e_book_client_get_sources() instead.
  */
 gboolean
 e_book_get_addressbooks (ESourceList **addressbook_sources, GError **error)
@@ -3224,6 +3311,8 @@ e_book_get_addressbooks (ESourceList **addressbook_sources, GError **error)
  * e_book_open(), and e_book_remove().
  *
  * Returns: a new but unopened #EBook.
+ *
+ * Deprecated: 3.2: Use e_book_client_new() instead.
  */
 EBook *
 e_book_new (ESource *source, GError **error)
@@ -3250,7 +3339,7 @@ e_book_new (ESource *source, GError **error)
 
 	xml = e_source_to_standalone_xml (source);
 
-	if (!e_gdbus_book_factory_call_get_book_sync (book_factory_proxy, e_util_ensure_gdbus_string (xml, &gdbus_xml), &path, NULL, &err)) {
+	if (!e_gdbus_book_factory_call_get_book_sync (G_DBUS_PROXY (book_factory_proxy), e_util_ensure_gdbus_string (xml, &gdbus_xml), &path, NULL, &err)) {
 		unwrap_gerror (err, &err);
 		g_free (xml);
 		g_free (gdbus_xml);
@@ -3264,12 +3353,12 @@ e_book_new (ESource *source, GError **error)
 	g_free (xml);
 	g_free (gdbus_xml);
 
-	book->priv->gdbus_book = e_gdbus_book_proxy_new_sync (g_dbus_proxy_get_connection (G_DBUS_PROXY (book_factory_proxy)),
+	book->priv->gdbus_book = G_DBUS_PROXY (e_gdbus_book_proxy_new_sync (g_dbus_proxy_get_connection (G_DBUS_PROXY (book_factory_proxy)),
 						      G_DBUS_PROXY_FLAGS_NONE,
 						      ADDRESS_BOOK_DBUS_SERVICE_NAME,
 						      path,
 						      NULL,
-						      &err);
+						      &err));
 
 	if (!book->priv->gdbus_book) {
 		g_free (path);
@@ -3294,8 +3383,8 @@ e_book_new (ESource *source, GError **error)
 		gdbus_book_connection_gone_cb, book, NULL);
 	g_signal_connect (connection, "closed", G_CALLBACK (gdbus_book_closed_cb), book);
 
-	g_signal_connect (book->priv->gdbus_book, "writable", G_CALLBACK (writable_cb), book);
-	g_signal_connect (book->priv->gdbus_book, "connection", G_CALLBACK (connection_cb), book);
+	g_signal_connect (book->priv->gdbus_book, "readonly", G_CALLBACK (readonly_cb), book);
+	g_signal_connect (book->priv->gdbus_book, "online", G_CALLBACK (online_cb), book);
 	g_signal_connect (book->priv->gdbus_book, "auth-required", G_CALLBACK (auth_required_cb), book);
 
 	return book;
@@ -3378,6 +3467,8 @@ check_uri (ESource *source, gpointer uri)
  * documentation for e_book_new for further information.
  *
  * Returns: a new but unopened #EBook.
+ *
+ * Deprecated: 3.2: Use e_book_client_new_from_uri() instead.
  */
 EBook *
 e_book_new_from_uri (const gchar *uri, GError **error)
@@ -3447,6 +3538,8 @@ check_system (ESource *source, gpointer data)
  * information.
  *
  * Returns: a new but unopened #EBook.
+ *
+ * Deprecated: 3.2: Use e_book_client_new_system() instead.
  */
 EBook *
 e_book_new_system_addressbook (GError **error)
@@ -3500,6 +3593,8 @@ e_book_new_system_addressbook (GError **error)
  * further information.
  *
  * Returns: a new but unopened #EBook
+ *
+ * Deprecated: 3.2: Use e_book_client_new_default() instead.
  */
 EBook *
 e_book_new_default_addressbook (GError **error)
@@ -3539,6 +3634,7 @@ get_status_from_error (GError *error)
 		EBookStatus err_code;
 	} errors[] = {
 		{ err ("Success",				E_BOOK_ERROR_OK) },
+		{ err ("Busy",					E_BOOK_ERROR_BUSY) },
 		{ err ("RepositoryOffline",			E_BOOK_ERROR_REPOSITORY_OFFLINE) },
 		{ err ("PermissionDenied",			E_BOOK_ERROR_PERMISSION_DENIED) },
 		{ err ("ContactNotFound",			E_BOOK_ERROR_CONTACT_NOT_FOUND) },
@@ -3670,3 +3766,5 @@ array_to_elist (gchar **list)
 
 	return elst;
 }
+
+#endif /* E_BOOK_DISABLE_DEPRECATED */
diff --git a/addressbook/libebook/e-book.h b/addressbook/libebook/e-book.h
index 17a10a2..4bdfc0e 100644
--- a/addressbook/libebook/e-book.h
+++ b/addressbook/libebook/e-book.h
@@ -11,6 +11,9 @@
 #ifndef __E_BOOK_H__
 #define __E_BOOK_H__
 
+/* e-book deprecated since 3.2, use e-book-client instead */
+#ifndef E_BOOK_DISABLE_DEPRECATED
+
 #include <glib.h>
 #include <glib-object.h>
 
@@ -411,4 +414,6 @@ GType        e_book_get_type                  (void);
 
 G_END_DECLS
 
+#endif /* E_BOOK_DISABLE_DEPRECATED */
+
 #endif /* __E_BOOK_H__ */
diff --git a/addressbook/libedata-book/Makefile.am b/addressbook/libedata-book/Makefile.am
index 5975f8d..584151c 100644
--- a/addressbook/libedata-book/Makefile.am
+++ b/addressbook/libedata-book/Makefile.am
@@ -31,7 +31,6 @@ libedata_book_1_2_la_SOURCES =				\
 	e-data-book-view.c				\
 	e-data-book.c					\
 	ximian-vcard.h					\
-	opid.c opid.h					\
 	$(ENUM_GENERATED)
 
 libedata_book_1_2_la_LIBADD =					\
diff --git a/addressbook/libedata-book/e-book-backend-sync.c b/addressbook/libedata-book/e-book-backend-sync.c
index 1f0a134..a944554 100644
--- a/addressbook/libedata-book/e-book-backend-sync.c
+++ b/addressbook/libedata-book/e-book-backend-sync.c
@@ -15,7 +15,7 @@
 G_DEFINE_TYPE (EBookBackendSync, e_book_backend_sync, E_TYPE_BOOK_BACKEND)
 
 struct _EBookBackendSyncPrivate {
-  gint mumble;
+	gint mumble;
 };
 
 static GObjectClass *parent_class;
@@ -35,10 +35,34 @@ e_book_backend_sync_construct (EBookBackendSync *backend)
 }
 
 /**
+ * e_book_backend_sync_open:
+ * @backend: an #EBookBackendSync
+ * @book: an #EDataBook
+ * @cancellable: a #GCancellable for the operation
+ * @only_if_exists: whether open only if exists
+ * @error: #GError to set, when something fails
+ *
+ * Opens @backend, which can involve connecting it to a remote server.
+ **/
+void
+e_book_backend_sync_open (EBookBackendSync *backend,
+			  EDataBook *book,
+			  GCancellable *cancellable,
+			  gboolean only_if_exists,
+			  GError **error)
+{
+	e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_SYNC (backend), E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (E_IS_DATA_BOOK (book), E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->open_sync, E_DATA_BOOK_STATUS_NOT_SUPPORTED);
+
+	(* E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->open_sync) (backend, book, cancellable, only_if_exists, error);
+}
+
+/**
  * e_book_backend_sync_create_contact:
  * @backend: an #EBookBackendSync
  * @book: an #EDataBook
- * @opid: the unique ID of the operation
+ * @cancellable: a #GCancellable for the operation
  * @vcard: a VCard representation of a contact
  * @contact: a pointer to a location to store the resulting #EContact
  * @error: #GError to set, when something fails
@@ -48,7 +72,7 @@ e_book_backend_sync_construct (EBookBackendSync *backend)
 void
 e_book_backend_sync_create_contact (EBookBackendSync *backend,
 				    EDataBook *book,
-				    guint32 opid,
+				    GCancellable *cancellable,
 				    const gchar *vcard,
 				    EContact **contact,
 				    GError **error)
@@ -57,17 +81,16 @@ e_book_backend_sync_create_contact (EBookBackendSync *backend,
 	e_return_data_book_error_if_fail (E_IS_DATA_BOOK (book), E_DATA_BOOK_STATUS_INVALID_ARG);
 	e_return_data_book_error_if_fail (vcard, E_DATA_BOOK_STATUS_INVALID_ARG);
 	e_return_data_book_error_if_fail (contact, E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->create_contact_sync, E_DATA_BOOK_STATUS_NOT_SUPPORTED);
 
-	g_assert (E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->create_contact_sync);
-
-	(* E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->create_contact_sync) (backend, book, opid, vcard, contact, error);
+	(* E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->create_contact_sync) (backend, book, cancellable, vcard, contact, error);
 }
 
 /**
  * e_book_backend_sync_remove:
  * @backend: an #EBookBackendSync
  * @book: an #EDataBook
- * @opid: the unique ID of the operation
+ * @cancellable: a #GCancellable for the operation
  * @error: #GError to set, when something fails
  *
  * Remove @book's database and storage overhead from the storage
@@ -76,23 +99,101 @@ e_book_backend_sync_create_contact (EBookBackendSync *backend,
 void
 e_book_backend_sync_remove (EBookBackendSync *backend,
 			    EDataBook *book,
-			    guint32 opid,
+			    GCancellable *cancellable,
 			    GError **error)
 {
 	e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_SYNC (backend), E_DATA_BOOK_STATUS_INVALID_ARG);
 	e_return_data_book_error_if_fail (E_IS_DATA_BOOK (book), E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->remove_sync, E_DATA_BOOK_STATUS_NOT_SUPPORTED);
 
-	g_assert (E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->remove_sync);
+	(* E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->remove_sync) (backend, book, cancellable, error);
+}
 
-	(* E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->remove_sync) (backend, book, opid, error);
+/**
+ * e_book_backend_sync_refresh:
+ * @backend: An EBookBackendSync object.
+ * @book: An EDataBook object.
+ * @cancellable: a #GCancellable for the operation
+ * @error: Out parameter for a #GError.
+ *
+ * Calls the refresh_sync method on the given backend.
+ *
+ * Since: 3.2
+ */
+void
+e_book_backend_sync_refresh  (EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, GError **error)
+{
+	e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_SYNC (backend), E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (E_IS_DATA_BOOK (book), E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->refresh_sync, E_DATA_BOOK_STATUS_NOT_SUPPORTED);
+
+	(* E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->refresh_sync) (backend, book, cancellable, error);
+}
+
+/**
+ * e_book_backend_sync_get_backend_property:
+ * @backend: an #EBookBackendSync
+ * @book: an #EDataBook
+ * @cancellable: a #GCancellable for the operation
+ * @prop_name: Property name whose value to retrieve.
+ * @prop_value: Return value of the @prop_name.
+ * @error: #GError to set, when something fails
+ *
+ * Calls the get_backend_property_sync method on the given backend.
+ *
+ * Returns whether processed this property. Returning FALSE means to pass
+ * the call to the EBookBackend parent class, thus neither @error should be
+ * set in this case.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_book_backend_sync_get_backend_property (EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, const gchar *prop_name, gchar **prop_value, GError **error)
+{
+	e_return_data_book_error_val_if_fail (E_IS_BOOK_BACKEND_SYNC (backend), E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_val_if_fail (E_IS_DATA_BOOK (book), E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_val_if_fail (prop_name, E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_val_if_fail (prop_value, E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_val_if_fail (E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->get_backend_property_sync, E_DATA_BOOK_STATUS_NOT_SUPPORTED);
+
+	return (* E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->get_backend_property_sync) (backend, book, cancellable, prop_name, prop_value, error);
+}
+
+/**
+ * e_book_backend_sync_set_backend_property:
+ * @backend: an #EBookBackendSync
+ * @book: an #EDataBook
+ * @cancellable: a #GCancellable for the operation
+ * @prop_name: Property name to set.
+ * @prop_value: New value of the @prop_name.
+ * @error: #GError to set, when something fails
+ *
+ * Calls the set_backend_property_sync method on the given backend.
+ *
+ * Returns whether processed this property. Returning FALSE means to pass
+ * the call to the EBookBackend parent class, thus neither @error should be
+ * set in this case.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_book_backend_sync_set_backend_property (EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, const gchar *prop_name, const gchar *prop_value, GError **error)
+{
+	e_return_data_book_error_val_if_fail (E_IS_BOOK_BACKEND_SYNC (backend), E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_val_if_fail (E_IS_DATA_BOOK (book), E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_val_if_fail (prop_name, E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_val_if_fail (prop_value, E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_val_if_fail (E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->set_backend_property_sync, E_DATA_BOOK_STATUS_NOT_SUPPORTED);
+
+	return (* E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->set_backend_property_sync) (backend, book, cancellable, prop_name, prop_value, error);
 }
 
 /**
  * e_book_backend_sync_remove_contacts:
  * @backend: an #EBookBackendSync
  * @book: an #EDataBook
- * @opid: the unique ID of the operation
- * @id_list: a #GList of pointers to unique contact ID strings
+ * @cancellable: a #GCancellable for the operation
+ * @id_list: a #GSList of pointers to unique contact ID strings
  * @removed_ids: a pointer to a location to store a list of the contacts actually removed
  * @error: #GError to set, when something fails
  *
@@ -103,26 +204,25 @@ e_book_backend_sync_remove (EBookBackendSync *backend,
 void
 e_book_backend_sync_remove_contacts (EBookBackendSync *backend,
 				     EDataBook *book,
-				     guint32 opid,
-				     GList *id_list,
-				     GList **removed_ids,
+				     GCancellable *cancellable,
+				     const GSList *id_list,
+				     GSList **removed_ids,
 				     GError **error)
 {
 	e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_SYNC (backend), E_DATA_BOOK_STATUS_INVALID_ARG);
 	e_return_data_book_error_if_fail (E_IS_DATA_BOOK (book), E_DATA_BOOK_STATUS_INVALID_ARG);
 	e_return_data_book_error_if_fail (id_list, E_DATA_BOOK_STATUS_INVALID_ARG);
 	e_return_data_book_error_if_fail (removed_ids, E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->remove_contacts_sync, E_DATA_BOOK_STATUS_NOT_SUPPORTED);
 
-	g_assert (E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->remove_contacts_sync);
-
-	(* E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->remove_contacts_sync) (backend, book, opid, id_list, removed_ids, error);
+	(* E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->remove_contacts_sync) (backend, book, cancellable, id_list, removed_ids, error);
 }
 
 /**
  * e_book_backend_sync_modify_contact:
  * @backend: an #EBookBackendSync
  * @book: an #EDataBook
- * @opid: the unique ID of the operation
+ * @cancellable: a #GCancellable for the operation
  * @vcard: the string representation of a contact
  * @contact: a pointer to a location to store the resulting #EContact
  * @error: #GError to set, when something fails
@@ -133,7 +233,7 @@ e_book_backend_sync_remove_contacts (EBookBackendSync *backend,
 void
 e_book_backend_sync_modify_contact (EBookBackendSync *backend,
 				    EDataBook *book,
-				    guint32 opid,
+				    GCancellable *cancellable,
 				    const gchar *vcard,
 				    EContact **contact,
 				    GError **error)
@@ -142,17 +242,16 @@ e_book_backend_sync_modify_contact (EBookBackendSync *backend,
 	e_return_data_book_error_if_fail (E_IS_DATA_BOOK (book), E_DATA_BOOK_STATUS_INVALID_ARG);
 	e_return_data_book_error_if_fail (vcard, E_DATA_BOOK_STATUS_INVALID_ARG);
 	e_return_data_book_error_if_fail (contact, E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->modify_contact_sync, E_DATA_BOOK_STATUS_NOT_SUPPORTED);
 
-	g_assert (E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->modify_contact_sync);
-
-	(* E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->modify_contact_sync) (backend, book, opid, vcard, contact, error);
+	(* E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->modify_contact_sync) (backend, book, cancellable, vcard, contact, error);
 }
 
 /**
  * e_book_backend_sync_get_contact:
  * @backend: an #EBookBackendSync
  * @book: an #EDataBook
- * @opid: the unique ID of the operation
+ * @cancellable: a #GCancellable for the operation
  * @id: a unique contact ID
  * @vcard: a pointer to a location to store the resulting VCard string
  *
@@ -161,7 +260,7 @@ e_book_backend_sync_modify_contact (EBookBackendSync *backend,
 void
 e_book_backend_sync_get_contact (EBookBackendSync *backend,
 				 EDataBook *book,
-				 guint32 opid,
+				 GCancellable *cancellable,
 				 const gchar *id,
 				 gchar **vcard,
 				 GError **error)
@@ -170,17 +269,16 @@ e_book_backend_sync_get_contact (EBookBackendSync *backend,
 	e_return_data_book_error_if_fail (E_IS_DATA_BOOK (book), E_DATA_BOOK_STATUS_INVALID_ARG);
 	e_return_data_book_error_if_fail (id, E_DATA_BOOK_STATUS_INVALID_ARG);
 	e_return_data_book_error_if_fail (vcard, E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->get_contact_sync, E_DATA_BOOK_STATUS_NOT_SUPPORTED);
 
-	g_assert (E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->get_contact_sync);
-
-	(* E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->get_contact_sync) (backend, book, opid, id, vcard, error);
+	(* E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->get_contact_sync) (backend, book, cancellable, id, vcard, error);
 }
 
 /**
  * e_book_backend_sync_get_contact_list:
  * @backend: an #EBookBackendSync
  * @book: an #EDataBook
- * @opid: the unique ID of the operation
+ * @cancellable: a #GCancellable for the operation
  * @query: an s-expression of the query to perform
  * @contacts: a pointer to a location to store the resulting list of VCard strings
  * @error: #GError to set, when something fails
@@ -191,188 +289,115 @@ e_book_backend_sync_get_contact (EBookBackendSync *backend,
 void
 e_book_backend_sync_get_contact_list (EBookBackendSync *backend,
 				      EDataBook *book,
-				      guint32 opid,
+				      GCancellable *cancellable,
 				      const gchar *query,
-				      GList **contacts,
+				      GSList **contacts,
 				      GError **error)
 {
 	e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_SYNC (backend), E_DATA_BOOK_STATUS_INVALID_ARG);
 	e_return_data_book_error_if_fail (E_IS_DATA_BOOK (book), E_DATA_BOOK_STATUS_INVALID_ARG);
 	e_return_data_book_error_if_fail (query, E_DATA_BOOK_STATUS_INVALID_ARG);
 	e_return_data_book_error_if_fail (contacts, E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->get_contact_list_sync, E_DATA_BOOK_STATUS_NOT_SUPPORTED);
 
-	g_assert (E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->get_contact_list_sync);
-
-	(* E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->get_contact_list_sync) (backend, book, opid, query, contacts, error);
+	(* E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->get_contact_list_sync) (backend, book, cancellable, query, contacts, error);
 }
 
 /**
- * e_book_backend_sync_get_changes:
+ * e_book_backend_sync_authenticate_user:
  * @backend: an #EBookBackendSync
- * @book: an #EDataBook
- * @opid: the unique ID of the operation
- * @change_id: a unique changes ID
- * @changes: a pointer to a location to store the resulting list of changes
+ * @cancellable: a #GCancellable for the operation
+ * @credentials: an #ECredentials to authenticate with
  * @error: #GError to set, when something fails
  *
- * Gets the changes made to @book since the last call to this function.
- * The returned list will contain items of CORBA type
- * #EDataBookChange.
+ * Authenticates @backend with given @credentials.
  **/
 void
-e_book_backend_sync_get_changes (EBookBackendSync *backend,
-				 EDataBook *book,
-				 guint32 opid,
-				 const gchar *change_id,
-				 GList **changes,
-				 GError **error)
+e_book_backend_sync_authenticate_user (EBookBackendSync *backend,
+				       GCancellable *cancellable,
+				       ECredentials *credentials,
+				       GError **error)
 {
 	e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_SYNC (backend), E_DATA_BOOK_STATUS_INVALID_ARG);
-	e_return_data_book_error_if_fail (E_IS_DATA_BOOK (book), E_DATA_BOOK_STATUS_INVALID_ARG);
-	e_return_data_book_error_if_fail (change_id, E_DATA_BOOK_STATUS_INVALID_ARG);
-	e_return_data_book_error_if_fail (changes, E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (credentials, E_DATA_BOOK_STATUS_INVALID_ARG);
+	e_return_data_book_error_if_fail (E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->authenticate_user_sync, E_DATA_BOOK_STATUS_NOT_SUPPORTED);
 
-	g_assert (E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->get_changes_sync);
-
-	(* E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->get_changes_sync) (backend, book, opid, change_id, changes, error);
+	(* E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->authenticate_user_sync) (backend, cancellable, credentials, error);
 }
 
-/**
- * e_book_backend_sync_authenticate_user:
- * @backend: an #EBookBackendSync
- * @book: an #EDataBook
- * @opid: the unique ID of the operation
- * @user: the user's name
- * @passwd: the user's password
- * @auth_method: the authentication method desired
- * @error: #GError to set, when something fails
- *
- * Authenticates @user against @book.
- **/
-void
-e_book_backend_sync_authenticate_user (EBookBackendSync *backend,
-				       EDataBook *book,
-				       guint32 opid,
-				       const gchar *user,
-				       const gchar *passwd,
-				       const gchar *auth_method,
-				       GError **error)
+static void
+book_backend_open (EBookBackend *backend,
+		      EDataBook    *book,
+		      guint32       opid,
+		      GCancellable *cancellable,
+		      gboolean only_if_exists)
 {
-	e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_SYNC (backend), E_DATA_BOOK_STATUS_INVALID_ARG);
-	e_return_data_book_error_if_fail (E_IS_DATA_BOOK (book), E_DATA_BOOK_STATUS_INVALID_ARG);
-	e_return_data_book_error_if_fail (user && passwd && auth_method, E_DATA_BOOK_STATUS_INVALID_ARG);
+	GError *error = NULL;
 
-	g_assert (E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->authenticate_user_sync);
+	e_book_backend_sync_open (E_BOOK_BACKEND_SYNC (backend), book, cancellable, only_if_exists, &error);
 
-	(* E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->authenticate_user_sync) (backend, book, opid, user, passwd, auth_method, error);
+	e_data_book_respond_open (book, opid, error);
 }
 
-/**
- * e_book_backend_sync_get_required_fields:
- * @backend: an #EBookBackendSync
- * @book: an #EDataBook
- * @opid: the unique ID of the operation
- * @fields: a pointer to a location to store the fields
- * @error: #GError to set, when something fails
- *
- * Gets a list of the fields required for all contacts in @book. The
- * fields are represented by strings from #e_contact_field_name. The list
- * and its contents must be freed by the caller.
- **/
-void
-e_book_backend_sync_get_required_fields (EBookBackendSync *backend,
-					  EDataBook *book,
-					  guint32 opid,
-					  GList **fields,
-					  GError **error)
+static void
+book_backend_remove (EBookBackend *backend,
+			EDataBook    *book,
+			guint32       opid,
+			GCancellable *cancellable)
 {
-	e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_SYNC (backend), E_DATA_BOOK_STATUS_INVALID_ARG);
-	e_return_data_book_error_if_fail (E_IS_DATA_BOOK (book), E_DATA_BOOK_STATUS_INVALID_ARG);
-	e_return_data_book_error_if_fail (fields, E_DATA_BOOK_STATUS_INVALID_ARG);
+	GError *error = NULL;
 
-	g_assert (E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->get_required_fields_sync);
+	e_book_backend_sync_remove (E_BOOK_BACKEND_SYNC (backend), book, cancellable, &error);
 
-	(* E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->get_required_fields_sync) (backend, book, opid, fields, error);
+	e_data_book_respond_remove (book, opid, error);
 }
 
-/**
- * e_book_backend_sync_get_supported_fields:
- * @backend: an #EBookBackendSync
- * @book: an #EDataBook
- * @opid: the unique ID of the operation
- * @fields: a pointer to a location to store the fields
- * @error: #GError to set, when something fails
- *
- * Gets a list of the fields supported for contacts in @book. Other fields
- * may not be stored. The fields are represented by strings from #e_contact_field_name.
- * The list and its contents must be freed by the caller.
- **/
-void
-e_book_backend_sync_get_supported_fields (EBookBackendSync *backend,
-					  EDataBook *book,
-					  guint32 opid,
-					  GList **fields,
-					  GError **error)
+static void
+book_backend_refresh (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable)
 {
-	e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_SYNC (backend), E_DATA_BOOK_STATUS_INVALID_ARG);
-	e_return_data_book_error_if_fail (E_IS_DATA_BOOK (book), E_DATA_BOOK_STATUS_INVALID_ARG);
-	e_return_data_book_error_if_fail (fields, E_DATA_BOOK_STATUS_INVALID_ARG);
+	GError *error = NULL;
 
-	g_assert (E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->get_supported_fields_sync);
+	e_book_backend_sync_refresh (E_BOOK_BACKEND_SYNC (backend), book, cancellable, &error);
 
-	(* E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->get_supported_fields_sync) (backend, book, opid, fields, error);
+	e_data_book_respond_refresh (book, opid, error);
 }
 
-/**
- * e_book_backend_sync_get_supported_auth_methods:
- * @backend: an #EBookBackendSync
- * @book: an #EDataBook
- * @opid: the unique ID of the operation
- * @methods: a pointer to a location to store the methods
- * @error: #GError to set, when something fails
- *
- * Gets a list of the authentication methods supported by @book. The
- * methods are represented by strings. The list and its contents must
- * be freed by the caller.
- **/
-void
-e_book_backend_sync_get_supported_auth_methods (EBookBackendSync *backend,
-						EDataBook *book,
-						guint32 opid,
-						GList **methods,
-						GError **error)
+static void
+book_backend_get_backend_property (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *prop_name)
 {
-	e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND_SYNC (backend), E_DATA_BOOK_STATUS_INVALID_ARG);
-	e_return_data_book_error_if_fail (E_IS_DATA_BOOK (book), E_DATA_BOOK_STATUS_INVALID_ARG);
-	e_return_data_book_error_if_fail (methods, E_DATA_BOOK_STATUS_INVALID_ARG);
+	GError *error = NULL;
+	gchar *prop_value = NULL;
 
-	g_assert (E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->get_supported_auth_methods_sync);
+	if (e_book_backend_sync_get_backend_property (E_BOOK_BACKEND_SYNC (backend), book, cancellable, prop_name, &prop_value, &error))
+		e_data_book_respond_get_backend_property (book, opid, error, prop_value);
+	else
+		(* E_BOOK_BACKEND_CLASS (e_book_backend_sync_parent_class)->get_backend_property) (backend, book, opid, cancellable, prop_name);
 
-	(* E_BOOK_BACKEND_SYNC_GET_CLASS (backend)->get_supported_auth_methods_sync) (backend, book, opid, methods, error);
+	g_free (prop_value);
 }
 
 static void
-_e_book_backend_remove (EBookBackend *backend,
-			EDataBook    *book,
-			guint32       opid)
+book_backend_set_backend_property (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *prop_name, const gchar *prop_value)
 {
-	GError *error = NULL;;
-
-	e_book_backend_sync_remove (E_BOOK_BACKEND_SYNC (backend), book, opid, &error);
+	GError *error = NULL;
 
-	e_data_book_respond_remove (book, opid, error);
+	if (e_book_backend_sync_set_backend_property (E_BOOK_BACKEND_SYNC (backend), book, cancellable, prop_name, prop_value, &error))
+		e_data_book_respond_set_backend_property (book, opid, error);
+	else
+		(* E_BOOK_BACKEND_CLASS (e_book_backend_sync_parent_class)->set_backend_property) (backend, book, opid, cancellable, prop_name, prop_value);
 }
 
 static void
-_e_book_backend_create_contact (EBookBackend *backend,
-				EDataBook    *book,
-				guint32       opid,
-				const gchar   *vcard)
+book_backend_create_contact (EBookBackend *backend,
+			     EDataBook    *book,
+			     guint32       opid,
+			     GCancellable *cancellable,
+			     const gchar   *vcard)
 {
 	GError *error = NULL;
 	EContact *contact = NULL;
 
-	e_book_backend_sync_create_contact (E_BOOK_BACKEND_SYNC (backend), book, opid, vcard, &contact, &error);
+	e_book_backend_sync_create_contact (E_BOOK_BACKEND_SYNC (backend), book, cancellable, vcard, &contact, &error);
 
 	e_data_book_respond_create (book, opid, error, contact);
 
@@ -381,32 +406,36 @@ _e_book_backend_create_contact (EBookBackend *backend,
 }
 
 static void
-_e_book_backend_remove_contacts (EBookBackend *backend,
-				 EDataBook    *book,
-				 guint32       opid,
-				 GList        *id_list)
+book_backend_remove_contacts (EBookBackend *backend,
+			      EDataBook    *book,
+			      guint32       opid,
+			      GCancellable *cancellable,
+			      const GSList *id_list)
 {
 	GError *error = NULL;
-	GList *ids = NULL;
+	GSList *ids = NULL;
 
-	e_book_backend_sync_remove_contacts (E_BOOK_BACKEND_SYNC (backend), book, opid, id_list, &ids, &error);
+	e_book_backend_sync_remove_contacts (E_BOOK_BACKEND_SYNC (backend), book, cancellable, id_list, &ids, &error);
 
 	e_data_book_respond_remove_contacts (book, opid, error, ids);
 
-	if (ids)
-		g_list_free (ids);
+	if (ids) {
+		g_slist_foreach (ids, (GFunc) g_free, NULL);
+		g_slist_free (ids);
+	}
 }
 
 static void
-_e_book_backend_modify_contact (EBookBackend *backend,
-				EDataBook    *book,
-				guint32       opid,
-				const gchar   *vcard)
+book_backend_modify_contact (EBookBackend *backend,
+			     EDataBook    *book,
+			     guint32       opid,
+			     GCancellable *cancellable,
+			     const gchar   *vcard)
 {
 	GError *error = NULL;
 	EContact *contact = NULL;
 
-	e_book_backend_sync_modify_contact (E_BOOK_BACKEND_SYNC (backend), book, opid, vcard, &contact, &error);
+	e_book_backend_sync_modify_contact (E_BOOK_BACKEND_SYNC (backend), book, cancellable, vcard, &contact, &error);
 
 	e_data_book_respond_modify (book, opid, error, contact);
 
@@ -415,15 +444,16 @@ _e_book_backend_modify_contact (EBookBackend *backend,
 }
 
 static void
-_e_book_backend_get_contact (EBookBackend *backend,
-			     EDataBook    *book,
-			     guint32       opid,
-			     const gchar   *id)
+book_backend_get_contact (EBookBackend *backend,
+			  EDataBook    *book,
+			  guint32       opid,
+			  GCancellable *cancellable,
+			  const gchar   *id)
 {
 	GError *error = NULL;
 	gchar *vcard = NULL;
 
-	e_book_backend_sync_get_contact (E_BOOK_BACKEND_SYNC (backend), book, opid, id, &vcard, &error);
+	e_book_backend_sync_get_contact (E_BOOK_BACKEND_SYNC (backend), book, cancellable, id, &vcard, &error);
 
 	e_data_book_respond_get_contact (book, opid, error, vcard);
 
@@ -432,100 +462,47 @@ _e_book_backend_get_contact (EBookBackend *backend,
 }
 
 static void
-_e_book_backend_get_contact_list (EBookBackend *backend,
-				  EDataBook    *book,
-				  guint32       opid,
-				  const gchar   *query)
+book_backend_get_contact_list (EBookBackend *backend,
+			       EDataBook    *book,
+			       guint32       opid,
+			       GCancellable *cancellable,
+			       const gchar   *query)
 {
 	GError *error = NULL;
-	GList *cards = NULL;
+	GSList *cards = NULL;
 
-	e_book_backend_sync_get_contact_list (E_BOOK_BACKEND_SYNC (backend), book, opid, query, &cards, &error);
+	e_book_backend_sync_get_contact_list (E_BOOK_BACKEND_SYNC (backend), book, cancellable, query, &cards, &error);
 
 	e_data_book_respond_get_contact_list (book, opid, error, cards);
-}
-
-static void
-_e_book_backend_get_changes (EBookBackend *backend,
-			     EDataBook    *book,
-			     guint32       opid,
-			     const gchar   *change_id)
-{
-	GError *error = NULL;
-	GList *changes = NULL;
-
-	e_book_backend_sync_get_changes (E_BOOK_BACKEND_SYNC (backend), book, opid, change_id, &changes, &error);
-
-	e_data_book_respond_get_changes (book, opid, error, changes);
-}
-
-static void
-_e_book_backend_authenticate_user (EBookBackend *backend,
-				   EDataBook    *book,
-				   guint32       opid,
-				   const gchar   *user,
-				   const gchar   *passwd,
-				   const gchar   *auth_method)
-{
-	GError *error = NULL;
-
-	e_book_backend_sync_authenticate_user (E_BOOK_BACKEND_SYNC (backend), book, opid, user, passwd, auth_method, &error);
 
-	e_data_book_respond_authenticate_user (book, opid, error);
+	g_slist_foreach (cards, (GFunc) g_free, NULL);
+	g_slist_free (cards);
 }
 
 static void
-_e_book_backend_get_required_fields (EBookBackend *backend,
-				      EDataBook    *book,
-				      guint32       opid)
+book_backend_authenticate_user (EBookBackend *backend,
+				GCancellable *cancellable,
+				ECredentials *credentials)
 {
 	GError *error = NULL;
-	GList *fields = NULL;
-
-	e_book_backend_sync_get_required_fields (E_BOOK_BACKEND_SYNC (backend), book, opid, &fields, &error);
 
-	e_data_book_respond_get_required_fields (book, opid, error, fields);
+	e_book_backend_sync_authenticate_user (E_BOOK_BACKEND_SYNC (backend), cancellable, credentials, &error);
 
-	if (fields) {
-		g_list_foreach (fields, (GFunc) g_free, NULL);
-		g_list_free (fields);
-	}
+	e_book_backend_notify_opened (backend, error);
 }
 
-static void
-_e_book_backend_get_supported_fields (EBookBackend *backend,
-				      EDataBook    *book,
-				      guint32       opid)
+static gboolean
+book_backend_sync_get_backend_property (EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, const gchar *prop_name, gchar **prop_value, GError **error)
 {
-	GError *error = NULL;
-	GList *fields = NULL;
-
-	e_book_backend_sync_get_supported_fields (E_BOOK_BACKEND_SYNC (backend), book, opid, &fields, &error);
-
-	e_data_book_respond_get_supported_fields (book, opid, error, fields);
-
-	if (fields) {
-		g_list_foreach (fields, (GFunc) g_free, NULL);
-		g_list_free (fields);
-	}
+	/* to indicate to pass to the EBookBackend parent class */
+	return FALSE;
 }
 
-static void
-_e_book_backend_get_supported_auth_methods (EBookBackend *backend,
-					    EDataBook    *book,
-					    guint32       opid)
+static gboolean
+book_backend_sync_set_backend_property (EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, const gchar *prop_name, const gchar *prop_value, GError **error)
 {
-	GError *error = NULL;
-	GList *methods = NULL;
-
-	e_book_backend_sync_get_supported_auth_methods (E_BOOK_BACKEND_SYNC (backend), book, opid, &methods, &error);
-
-	e_data_book_respond_get_supported_auth_methods (book, opid, error, methods);
-
-	if (methods) {
-		g_list_foreach (methods, (GFunc) g_free, NULL);
-		g_list_free (methods);
-	}
+	/* to indicate to pass to the EBookBackend parent class */
+	return FALSE;
 }
 
 static void
@@ -563,18 +540,20 @@ e_book_backend_sync_class_init (EBookBackendSyncClass *klass)
 	parent_class = g_type_class_peek_parent (klass);
 
 	object_class = (GObjectClass *) klass;
-
-	backend_class->remove = _e_book_backend_remove;
-	backend_class->create_contact = _e_book_backend_create_contact;
-	backend_class->remove_contacts = _e_book_backend_remove_contacts;
-	backend_class->modify_contact = _e_book_backend_modify_contact;
-	backend_class->get_contact = _e_book_backend_get_contact;
-	backend_class->get_contact_list = _e_book_backend_get_contact_list;
-	backend_class->get_changes = _e_book_backend_get_changes;
-	backend_class->authenticate_user = _e_book_backend_authenticate_user;
-	backend_class->get_required_fields = _e_book_backend_get_required_fields;
-	backend_class->get_supported_fields = _e_book_backend_get_supported_fields;
-	backend_class->get_supported_auth_methods = _e_book_backend_get_supported_auth_methods;
-
 	object_class->dispose = e_book_backend_sync_dispose;
+
+	backend_class->open			= book_backend_open;
+	backend_class->authenticate_user	= book_backend_authenticate_user;
+	backend_class->remove			= book_backend_remove;
+	backend_class->refresh			= book_backend_refresh;
+	backend_class->get_backend_property	= book_backend_get_backend_property;
+	backend_class->set_backend_property	= book_backend_set_backend_property;
+	backend_class->create_contact		= book_backend_create_contact;
+	backend_class->remove_contacts		= book_backend_remove_contacts;
+	backend_class->modify_contact		= book_backend_modify_contact;
+	backend_class->get_contact		= book_backend_get_contact;
+	backend_class->get_contact_list		= book_backend_get_contact_list;
+
+	klass->get_backend_property_sync	= book_backend_sync_get_backend_property;
+	klass->set_backend_property_sync	= book_backend_sync_set_backend_property;
 }
diff --git a/addressbook/libedata-book/e-book-backend-sync.h b/addressbook/libedata-book/e-book-backend-sync.h
index 16fb4fb..7f37d04 100644
--- a/addressbook/libedata-book/e-book-backend-sync.h
+++ b/addressbook/libedata-book/e-book-backend-sync.h
@@ -29,67 +29,36 @@ struct _EBookBackendSyncClass {
 	EBookBackendClass parent_class;
 
 	/* Virtual methods */
-	void (*remove_sync) (EBookBackendSync *backend, EDataBook *book, guint32 opid, GError **perror);
-	void (*create_contact_sync)  (EBookBackendSync *backend, EDataBook *book,
-							guint32 opid,
-							const gchar *vcard, EContact **contact, GError **perror);
-	void (*remove_contacts_sync) (EBookBackendSync *backend, EDataBook *book,
-							guint32 opid,
-							GList *id_list, GList **removed_ids, GError **perror);
-	void (*modify_contact_sync)  (EBookBackendSync *backend, EDataBook *book,
-							guint32 opid,
-							const gchar *vcard, EContact **contact, GError **perror);
-	void (*get_contact_sync) (EBookBackendSync *backend, EDataBook *book,
-						    guint32 opid,
-						    const gchar *id, gchar **vcard, GError **perror);
-	void (*get_contact_list_sync) (EBookBackendSync *backend, EDataBook *book,
-							 guint32 opid,
-							 const gchar *query, GList **contacts, GError **perror);
-	void (*get_changes_sync) (EBookBackendSync *backend, EDataBook *book,
-						    guint32 opid,
-						    const gchar *change_id, GList **changes, GError **perror);
-	void (*authenticate_user_sync) (EBookBackendSync *backend, EDataBook *book,
-							  guint32 opid,
-							  const gchar *user,
-							  const gchar *passwd,
-							  const gchar *auth_method, GError **perror);
-
-	void (*get_required_fields_sync) (EBookBackendSync *backend, EDataBook *book,
-							     guint32 opid,
-							     GList **fields, GError **perror);
-
-	void (*get_supported_fields_sync) (EBookBackendSync *backend, EDataBook *book,
-							     guint32 opid,
-							     GList **fields, GError **perror);
-	void (*get_supported_auth_methods_sync) (EBookBackendSync *backend, EDataBook *book,
-								   guint32 opid,
-								   GList **methods, GError **perror);
-
-	/* Padding for future expansion */
-	void (*_pas_reserved0) (void);
-	void (*_pas_reserved1) (void);
-	void (*_pas_reserved2) (void);
-	void (*_pas_reserved3) (void);
-	void (*_pas_reserved4) (void);
-
+	void (*open_sync)			(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, gboolean only_if_exists, GError **error);
+	void (*remove_sync)			(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, GError **error);
+	void (* refresh_sync)			(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, GError **error);
+	gboolean (*get_backend_property_sync)	(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, const gchar *prop_name, gchar **prop_value, GError **error);
+	gboolean (*set_backend_property_sync)	(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, const gchar *prop_name, const gchar *prop_value, GError **error);
+	void (*create_contact_sync)		(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, const gchar *vcard, EContact **contact, GError **error);
+	void (*remove_contacts_sync)		(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, const GSList *id_list, GSList **removed_ids, GError **error);
+	void (*modify_contact_sync)		(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, const gchar *vcard, EContact **contact, GError **error);
+	void (*get_contact_sync)		(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, const gchar *id, gchar **vcard, GError **error);
+	void (*get_contact_list_sync)		(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, const gchar *query, GSList **contacts, GError **error);
+
+	void (*authenticate_user_sync)		(EBookBackendSync *backend, GCancellable *cancellable, ECredentials *credentials, GError **error);
 };
 
-gboolean    e_book_backend_sync_construct                (EBookBackendSync             *backend);
+GType		e_book_backend_sync_get_type		(void);
 
-GType       e_book_backend_sync_get_type                 (void);
+gboolean	e_book_backend_sync_construct		(EBookBackendSync *backend);
 
-void e_book_backend_sync_remove  (EBookBackendSync *backend, EDataBook *book, guint32 opid, GError **perror);
-void e_book_backend_sync_create_contact  (EBookBackendSync *backend, EDataBook *book, guint32 opid, const gchar *vcard, EContact **contact, GError **perror);
-void e_book_backend_sync_remove_contacts (EBookBackendSync *backend, EDataBook *book, guint32 opid, GList *id_list, GList **removed_ids, GError **perror);
-void e_book_backend_sync_modify_contact  (EBookBackendSync *backend, EDataBook *book, guint32 opid, const gchar *vcard, EContact **contact, GError **perror);
-void e_book_backend_sync_get_contact (EBookBackendSync *backend, EDataBook *book, guint32 opid, const gchar *id, gchar **vcard, GError **perror);
-void e_book_backend_sync_get_contact_list (EBookBackendSync *backend, EDataBook *book, guint32 opid, const gchar *query, GList **contacts, GError **perror);
-void e_book_backend_sync_get_changes (EBookBackendSync *backend, EDataBook *book, guint32 opid, const gchar *change_id, GList **changes, GError **perror);
-void e_book_backend_sync_authenticate_user (EBookBackendSync *backend, EDataBook *book, guint32 opid, const gchar *user, const gchar *passwd, const gchar *auth_method, GError **perror);
+void		e_book_backend_sync_open		(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, gboolean only_if_exists, GError **error);
+void		e_book_backend_sync_remove		(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, GError **error);
+void		e_book_backend_sync_refresh		(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, GError **error);
+gboolean	e_book_backend_sync_get_backend_property(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, const gchar *prop_name, gchar **prop_value, GError **error);
+gboolean	e_book_backend_sync_set_backend_property(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, const gchar *prop_name, const gchar *prop_value, GError **error);
+void		e_book_backend_sync_create_contact	(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, const gchar *vcard, EContact **contact, GError **error);
+void		e_book_backend_sync_remove_contacts	(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, const GSList *id_list, GSList **removed_ids, GError **error);
+void		e_book_backend_sync_modify_contact	(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, const gchar *vcard, EContact **contact, GError **error);
+void		e_book_backend_sync_get_contact		(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, const gchar *id, gchar **vcard, GError **error);
+void		e_book_backend_sync_get_contact_list	(EBookBackendSync *backend, EDataBook *book, GCancellable *cancellable, const gchar *query, GSList **contacts, GError **error);
 
-void e_book_backend_sync_get_required_fields (EBookBackendSync *backend, EDataBook *book, guint32 opid, GList **fields, GError **perror);
-void e_book_backend_sync_get_supported_fields (EBookBackendSync *backend, EDataBook *book, guint32 opid, GList **fields, GError **perror);
-void e_book_backend_sync_get_supported_auth_methods (EBookBackendSync *backend, EDataBook *book, guint32 opid, GList **methods, GError **perror);
+void		e_book_backend_sync_authenticate_user	(EBookBackendSync *backend, GCancellable *cancellable, ECredentials *credentials, GError **error);
 
 G_END_DECLS
 
diff --git a/addressbook/libedata-book/e-book-backend.c b/addressbook/libedata-book/e-book-backend.c
index ad0492b..204e53a 100644
--- a/addressbook/libedata-book/e-book-backend.c
+++ b/addressbook/libedata-book/e-book-backend.c
@@ -8,23 +8,25 @@
 
 #include <config.h>
 
+#include <glib/gi18n-lib.h>
+
 #include <libedataserver/e-data-server-util.h>
 
 #include "e-data-book-view.h"
 #include "e-data-book.h"
 #include "e-book-backend.h"
 
-struct _EBookBackendPrivate {
-	GMutex *open_mutex;
+#define EDB_OPENING_ERROR e_data_book_create_error (E_DATA_BOOK_STATUS_BUSY, _("Cannot process, book backend is opening"))
 
+struct _EBookBackendPrivate {
 	GMutex *clients_mutex;
-	GList *clients;
+	GSList *clients;
 
 	ESource *source;
-	gboolean loaded, writable, removed, online;
+	gboolean opening, opened, readonly, removed, online;
 
 	GMutex *views_mutex;
-	EList *views;
+	GSList *views;
 
 	gchar *cache_dir;
 };
@@ -70,6 +72,40 @@ book_backend_set_default_cache_dir (EBookBackend *backend)
 }
 
 static void
+book_backend_get_backend_property (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *prop_name)
+{
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
+	g_return_if_fail (book != NULL);
+	g_return_if_fail (prop_name != NULL);
+
+	if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_OPENED)) {
+		e_data_book_respond_get_backend_property (book, opid, NULL, e_book_backend_is_opened (backend) ? "TRUE" : "FALSE");
+	} else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_OPENING)) {
+		e_data_book_respond_get_backend_property (book, opid, NULL, e_book_backend_is_opening (backend) ? "TRUE" : "FALSE");
+	} else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_ONLINE)) {
+		e_data_book_respond_get_backend_property (book, opid, NULL, e_book_backend_is_online (backend) ? "TRUE" : "FALSE");
+	} else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_READONLY)) {
+		e_data_book_respond_get_backend_property (book, opid, NULL, e_book_backend_is_readonly (backend) ? "TRUE" : "FALSE");
+	} else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CACHE_DIR)) {
+		e_data_book_respond_get_backend_property (book, opid, NULL, e_book_backend_get_cache_dir (backend));
+	} else {
+		e_data_book_respond_get_backend_property (book, opid, e_data_book_create_error_fmt (E_DATA_BOOK_STATUS_NOT_SUPPORTED, _("Unknown book property '%s'"), prop_name), NULL);
+	}
+}
+
+static void
+book_backend_set_backend_property (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *prop_name, const gchar *prop_value)
+{
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
+	g_return_if_fail (book != NULL);
+	g_return_if_fail (prop_name != NULL);
+
+	e_data_book_respond_set_backend_property (book, opid, e_data_book_create_error_fmt (E_DATA_BOOK_STATUS_NOT_SUPPORTED, _("Cannot change value of book property '%s'"), prop_name));
+}
+
+static void
 book_backend_set_property (GObject *object,
                            guint property_id,
                            const GValue *value,
@@ -111,7 +147,7 @@ book_backend_dispose (GObject *object)
 	priv = E_BOOK_BACKEND (object)->priv;
 
 	if (priv->views != NULL) {
-		g_object_unref (priv->views);
+		g_slist_free (priv->views);
 		priv->views = NULL;
 	}
 
@@ -131,9 +167,8 @@ book_backend_finalize (GObject *object)
 
 	priv = E_BOOK_BACKEND (object)->priv;
 
-	g_list_free (priv->clients);
+	g_slist_free (priv->clients);
 
-	g_mutex_free (priv->open_mutex);
 	g_mutex_free (priv->clients_mutex);
 	g_mutex_free (priv->views_mutex);
 
@@ -144,18 +179,21 @@ book_backend_finalize (GObject *object)
 }
 
 static void
-e_book_backend_class_init (EBookBackendClass *class)
+e_book_backend_class_init (EBookBackendClass *klass)
 {
 	GObjectClass *object_class;
 
-	g_type_class_add_private (class, sizeof (EBookBackendPrivate));
+	g_type_class_add_private (klass, sizeof (EBookBackendPrivate));
 
-	object_class = G_OBJECT_CLASS (class);
+	object_class = G_OBJECT_CLASS (klass);
 	object_class->set_property = book_backend_set_property;
 	object_class->get_property = book_backend_get_property;
 	object_class->dispose = book_backend_dispose;
 	object_class->finalize = book_backend_finalize;
 
+	klass->get_backend_property = book_backend_get_backend_property;
+	klass->set_backend_property = book_backend_set_backend_property;
+
 	g_object_class_install_property (
 		object_class,
 		PROP_CACHE_DIR,
@@ -182,11 +220,10 @@ e_book_backend_init (EBookBackend *backend)
 	backend->priv = G_TYPE_INSTANCE_GET_PRIVATE (
 		backend, E_TYPE_BOOK_BACKEND, EBookBackendPrivate);
 
-	backend->priv->views = e_list_new (
-		(EListCopyFunc) NULL, (EListFreeFunc) NULL, NULL);
-
-	backend->priv->open_mutex = g_mutex_new ();
+	backend->priv->clients = NULL;
 	backend->priv->clients_mutex = g_mutex_new ();
+
+	backend->priv->views = NULL;
 	backend->priv->views_mutex = g_mutex_new ();
 }
 
@@ -216,7 +253,7 @@ e_book_backend_get_cache_dir (EBookBackend *backend)
  * Sets the cache directory for the given backend.
  *
  * Note that #EBookBackend is initialized with a usable default based on
- * the #ESource given to e_book_backend_load_source().  Backends should
+ * the #ESource given to e_book_backend_open().  Backends should
  * not override the default without good reason.
  *
  * Since: 2.32
@@ -235,48 +272,6 @@ e_book_backend_set_cache_dir (EBookBackend *backend,
 }
 
 /**
- * e_book_backend_load_source:
- * @backend: an #EBookBackend
- * @source: an #ESource to load
- * @only_if_exists: %TRUE to prevent the creation of a new book
- * @error: #GError to set, when something fails
- *
- * Loads @source into @backend.
- **/
-void
-e_book_backend_load_source (EBookBackend           *backend,
-			    ESource                *source,
-			    gboolean                only_if_exists,
-			    GError		  **error)
-{
-	GError *local_error = NULL;
-
-	e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND (backend), E_DATA_BOOK_STATUS_INVALID_ARG);
-	e_return_data_book_error_if_fail (source, E_DATA_BOOK_STATUS_INVALID_ARG);
-	e_return_data_book_error_if_fail (backend->priv->loaded == FALSE, E_DATA_BOOK_STATUS_INVALID_ARG);
-
-	/* Subclasses may need to call e_book_backend_get_cache_dir() in
-	 * their load_source() methods, so get the "cache-dir" property
-	 * initialized before we call the method. */
-	backend->priv->source = g_object_ref (source);
-	book_backend_set_default_cache_dir (backend);
-
-	g_assert (E_BOOK_BACKEND_GET_CLASS (backend)->load_source);
-
-	g_object_ref (backend);
-
-	(* E_BOOK_BACKEND_GET_CLASS (backend)->load_source) (backend, source, only_if_exists, &local_error);
-
-	g_object_unref (backend);
-
-	if (g_error_matches (local_error, E_DATA_BOOK_ERROR,
-		E_DATA_BOOK_STATUS_INVALID_SERVER_VERSION))
-		g_error_free (local_error);
-	else if (local_error != NULL)
-		g_propagate_error (error, local_error);
-}
-
-/**
  * e_book_backend_get_source:
  * @backend: An addressbook backend.
  *
@@ -297,67 +292,154 @@ e_book_backend_get_source (EBookBackend *backend)
  * @backend: an #EBookBackend
  * @book: an #EDataBook
  * @opid: the ID to use for this operation
+ * @cancellable: a #GCancellable for the operation
  * @only_if_exists: %TRUE to prevent the creation of a new book
  *
  * Executes an 'open' request specified by @opid on @book
- * using @backend.
+ * using @backend. This call might be finished
+ * with e_data_book_respond_open() or e_book_backend_respond_opened(),
+ * though the overall opening phase finishes only after call
+ * of e_book_backend_notify_opened() after which call the backend
+ * is either fully opened (including authentication against (remote)
+ * server/storage) or an error was encountered during this opening phase.
+ * 'opened' and 'opening' properties are updated automatically.
+ * The backend refuses all other operations until the opening phase is finished.
+ *
+ * The e_book_backend_notify_opened() is called either from this function
+ * or from e_book_backend_authenticate_user(), or after necessary steps
+ * initiated by these two functions.
+ *
+ * The opening phase usually works like this:
+ * 1) client requests open for the backend
+ * 2) server receives this request and calls e_book_backend_open() - the opening phase begun
+ * 3) either the backend is opened during this call, and notifies client
+ *    with e_book_backend_notify_opened() about that. This is usually
+ *    for local backends; their opening phase is finished
+ * 4) or the backend requires authentication, thus it notifies client
+ *    about that with e_book_backend_notify_auth_required() and is
+ *    waiting for credentials, which will be received from client
+ *    by e_book_backend_authenticate_user() call. Backend's opening
+ *    phase is still running in this case, thus it doesn't call
+ *    e_book_backend_notify_opened() within e_book_backend_open() call.
+ * 5) when backend receives credentials in e_book_backend_authenticate_user()
+ *    then it tries to authenticate against a server/storage with them
+ *    and only after it knows result of the authentication, whether user
+ *    was or wasn't authenticated, it notifies client with the result
+ *    by e_book_backend_notify_opened() and it's opening phase is
+ *    finished now. If there was no error returned then the backend is
+ *    considered opened, otherwise it's considered closed. Use AuthenticationFailed
+ *    error when the given credentials were rejected by the server/store, which
+ *    will result in a re-prompt on the client side, otherwise use AuthenticationRequired
+ *    if there was anything wrong with the given credentials. Set error's
+ *    message to a reason for a re-prompt, it'll be shown to a user.
+ * 6) client checks error returned from e_book_backend_notify_opened() and
+ *    reprompts for a password if it was AuthenticationFailed. Otherwise
+ *    considers backend opened based on the error presence (no error means success).
+ *
+ * In any case, the call of e_book_backend_open() should be always finished
+ * with e_data_book_respond_open(), which has no influence on the opening phase,
+ * or alternatively with e_book_backend_respond_opened(). Never use authentication
+ * errors in e_data_book_respond_open() to notify the client the authentication is
+ * required, there is e_book_backend_notify_auth_required() for this.
  **/
 void
 e_book_backend_open (EBookBackend *backend,
 		     EDataBook    *book,
 		     guint32       opid,
+		     GCancellable *cancellable,
 		     gboolean      only_if_exists)
 {
 	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
 	g_return_if_fail (E_IS_DATA_BOOK (book));
 
-	g_mutex_lock (backend->priv->open_mutex);
+	g_mutex_lock (backend->priv->clients_mutex);
 
-	if (backend->priv->loaded) {
-		e_data_book_report_writable (book, backend->priv->writable);
-		e_data_book_report_connection_status (book, backend->priv->online);
+	if (e_book_backend_is_opened (backend)) {
+		g_mutex_unlock (backend->priv->clients_mutex);
 
-		e_data_book_respond_open (book, opid, NULL);
+		e_data_book_report_readonly (book, backend->priv->readonly);
+		e_data_book_report_online (book, backend->priv->online);
+
+		e_book_backend_respond_opened (backend, book, opid, NULL);
+	} else if (e_book_backend_is_opening (backend)) {
+		g_mutex_unlock (backend->priv->clients_mutex);
+
+		e_data_book_respond_open (book, opid, EDB_OPENING_ERROR);
 	} else {
-		GError *error = NULL;
+		ESource *source = e_data_book_get_source (book);
 
-		e_book_backend_load_source (backend, e_data_book_get_source (book), only_if_exists, &error);
+		backend->priv->opening = TRUE;
+		g_mutex_unlock (backend->priv->clients_mutex);
 
-		if (!error || g_error_matches (error, E_DATA_BOOK_ERROR, E_DATA_BOOK_STATUS_INVALID_SERVER_VERSION)) {
-			e_data_book_report_writable (book, backend->priv->writable);
-			e_data_book_report_connection_status (book, backend->priv->online);
-		}
+		g_return_if_fail (source != NULL);
 
-		e_data_book_respond_open (book, opid, error);
-	}
+		/* Subclasses may need to call e_book_backend_get_cache_dir() in
+		 * their open() methods, so get the "cache-dir" property
+		 * initialized before we call the method. */
+		backend->priv->source = g_object_ref (source);
+		book_backend_set_default_cache_dir (backend);
 
-	g_mutex_unlock (backend->priv->open_mutex);
+		g_return_if_fail (E_BOOK_BACKEND_GET_CLASS (backend)->open != NULL);
+
+		(* E_BOOK_BACKEND_GET_CLASS (backend)->open) (backend, book, opid, cancellable, only_if_exists);
+	}
 }
 
 /**
  * e_book_backend_remove:
  * @backend: an #EBookBackend
  * @book: an #EDataBook
+ * @cancellable: a #GCancellable for the operation
  * @opid: the ID to use for this operation
  *
  * Executes a 'remove' request to remove all of @backend's data,
  * specified by @opid on @book.
+ * This might be finished with e_data_book_respond_remove().
  **/
 void
 e_book_backend_remove (EBookBackend *backend,
 		       EDataBook    *book,
-		       guint32       opid)
+		       guint32       opid,
+		       GCancellable *cancellable)
 {
 	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
 	g_return_if_fail (E_IS_DATA_BOOK (book));
+	g_return_if_fail (E_BOOK_BACKEND_GET_CLASS (backend)->remove);
 
-	g_assert (E_BOOK_BACKEND_GET_CLASS (backend)->remove);
-
-	g_object_ref (backend);
+	if (e_book_backend_is_opening (backend))
+		e_data_book_respond_remove (book, opid, EDB_OPENING_ERROR);
+	else
+		(* E_BOOK_BACKEND_GET_CLASS (backend)->remove) (backend, book, opid, cancellable);
+}
 
-	(* E_BOOK_BACKEND_GET_CLASS (backend)->remove) (backend, book, opid);
+/**
+ * e_book_backend_refresh:
+ * @backend: an #EBookBackend
+ * @book: an #EDataBook
+ * @opid: the ID to use for this operation
+ * @cancellable: a #GCancellable for the operation
+ *
+ * Refreshes the address book being accessed by the given backend.
+ * This might be finished with e_data_book_respond_refresh(),
+ * and it might be called as soon as possible; it doesn't mean
+ * that the refreshing is done after calling that, the backend
+ * is only notifying client whether it started the refresh process
+ * or not.
+ *
+ * Since: 3.2
+ **/
+void
+e_book_backend_refresh (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable)
+{
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
 
-	g_object_unref (backend);
+	if (e_book_backend_is_opening (backend))
+		e_data_book_respond_refresh (book, opid, EDB_OPENING_ERROR);
+	else if (!E_BOOK_BACKEND_GET_CLASS (backend)->refresh)
+		e_data_book_respond_refresh (book, opid, e_data_book_create_error (E_DATA_BOOK_STATUS_NOT_SUPPORTED, NULL));
+	else
+		(* E_BOOK_BACKEND_GET_CLASS (backend)->refresh) (backend, book, opid, cancellable);
 }
 
 /**
@@ -365,28 +447,29 @@ e_book_backend_remove (EBookBackend *backend,
  * @backend: an #EBookBackend
  * @book: an #EDataBook
  * @opid: the ID to use for this operation
+ * @cancellable: a #GCancellable for the operation
  * @vcard: the VCard to add
  *
  * Executes a 'create contact' request specified by @opid on @book
  * using @backend.
+ * This might be finished with e_data_book_respond_create().
  **/
 void
 e_book_backend_create_contact (EBookBackend *backend,
 			       EDataBook    *book,
 			       guint32       opid,
+			       GCancellable *cancellable,
 			       const gchar   *vcard)
 {
 	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
 	g_return_if_fail (E_IS_DATA_BOOK (book));
 	g_return_if_fail (vcard);
+	g_return_if_fail (E_BOOK_BACKEND_GET_CLASS (backend)->create_contact);
 
-	g_assert (E_BOOK_BACKEND_GET_CLASS (backend)->create_contact);
-
-	g_object_ref (backend);
-
-	(* E_BOOK_BACKEND_GET_CLASS (backend)->create_contact) (backend, book, opid, vcard);
-
-	g_object_unref (backend);
+	if (e_book_backend_is_opening (backend))
+		e_data_book_respond_create (book, opid, EDB_OPENING_ERROR, NULL);
+	else
+		(* E_BOOK_BACKEND_GET_CLASS (backend)->create_contact) (backend, book, opid, cancellable, vcard);
 }
 
 /**
@@ -394,28 +477,29 @@ e_book_backend_create_contact (EBookBackend *backend,
  * @backend: an #EBookBackend
  * @book: an #EDataBook
  * @opid: the ID to use for this operation
+ * @cancellable: a #GCancellable for the operation
  * @id_list: list of string IDs to remove
  *
  * Executes a 'remove contacts' request specified by @opid on @book
  * using @backend.
+ * This might be finished with e_data_book_respond_remove_contacts().
  **/
 void
 e_book_backend_remove_contacts (EBookBackend *backend,
 				EDataBook    *book,
 				guint32       opid,
-				GList        *id_list)
+			        GCancellable *cancellable,
+				const GSList *id_list)
 {
 	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
 	g_return_if_fail (E_IS_DATA_BOOK (book));
 	g_return_if_fail (id_list);
+	g_return_if_fail (E_BOOK_BACKEND_GET_CLASS (backend)->remove_contacts);
 
-	g_assert (E_BOOK_BACKEND_GET_CLASS (backend)->remove_contacts);
-
-	g_object_ref (backend);
-
-	(* E_BOOK_BACKEND_GET_CLASS (backend)->remove_contacts) (backend, book, opid, id_list);
-
-	g_object_unref (backend);
+	if (e_book_backend_is_opening (backend))
+		e_data_book_respond_remove_contacts (book, opid, EDB_OPENING_ERROR, NULL);
+	else
+		(* E_BOOK_BACKEND_GET_CLASS (backend)->remove_contacts) (backend, book, opid, cancellable, id_list);
 }
 
 /**
@@ -423,28 +507,29 @@ e_book_backend_remove_contacts (EBookBackend *backend,
  * @backend: an #EBookBackend
  * @book: an #EDataBook
  * @opid: the ID to use for this operation
+ * @cancellable: a #GCancellable for the operation
  * @vcard: the VCard to update
  *
  * Executes a 'modify contact' request specified by @opid on @book
  * using @backend.
+ * This might be finished with e_data_book_respond_modify().
  **/
 void
 e_book_backend_modify_contact (EBookBackend *backend,
 			       EDataBook    *book,
 			       guint32       opid,
+			       GCancellable *cancellable,
 			       const gchar   *vcard)
 {
 	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
 	g_return_if_fail (E_IS_DATA_BOOK (book));
 	g_return_if_fail (vcard);
+	g_return_if_fail (E_BOOK_BACKEND_GET_CLASS (backend)->modify_contact);
 
-	g_assert (E_BOOK_BACKEND_GET_CLASS (backend)->modify_contact);
-
-	g_object_ref (backend);
-
-	(* E_BOOK_BACKEND_GET_CLASS (backend)->modify_contact) (backend, book, opid, vcard);
-
-	g_object_unref (backend);
+	if (e_book_backend_is_opening (backend))
+		e_data_book_respond_modify (book, opid, EDB_OPENING_ERROR, NULL);
+	else
+		(* E_BOOK_BACKEND_GET_CLASS (backend)->modify_contact) (backend, book, opid, cancellable, vcard);
 }
 
 /**
@@ -452,28 +537,29 @@ e_book_backend_modify_contact (EBookBackend *backend,
  * @backend: an #EBookBackend
  * @book: an #EDataBook
  * @opid: the ID to use for this operation
+ * @cancellable: a #GCancellable for the operation
  * @id: the ID of the contact to get
  *
  * Executes a 'get contact' request specified by @opid on @book
  * using @backend.
+ * This might be finished with e_data_book_respond_get_contact().
  **/
 void
 e_book_backend_get_contact (EBookBackend *backend,
 			    EDataBook    *book,
 			    guint32       opid,
+			    GCancellable *cancellable,
 			    const gchar   *id)
 {
 	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
 	g_return_if_fail (E_IS_DATA_BOOK (book));
 	g_return_if_fail (id);
+	g_return_if_fail (E_BOOK_BACKEND_GET_CLASS (backend)->get_contact);
 
-	g_assert (E_BOOK_BACKEND_GET_CLASS (backend)->get_contact);
-
-	g_object_ref (backend);
-
-	(* E_BOOK_BACKEND_GET_CLASS (backend)->get_contact) (backend, book, opid, id);
-
-	g_object_unref (backend);
+	if (e_book_backend_is_opening (backend))
+		e_data_book_respond_get_contact (book, opid, EDB_OPENING_ERROR, NULL);
+	else
+		(* E_BOOK_BACKEND_GET_CLASS (backend)->get_contact) (backend, book, opid, cancellable, id);
 }
 
 /**
@@ -481,28 +567,29 @@ e_book_backend_get_contact (EBookBackend *backend,
  * @backend: an #EBookBackend
  * @book: an #EDataBook
  * @opid: the ID to use for this operation
+ * @cancellable: a #GCancellable for the operation
  * @query: the s-expression to match
  *
  * Executes a 'get contact list' request specified by @opid on @book
  * using @backend.
+ * This might be finished with e_data_book_respond_get_contact_list().
  **/
 void
 e_book_backend_get_contact_list (EBookBackend *backend,
 				 EDataBook    *book,
 				 guint32       opid,
+				 GCancellable *cancellable,
 				 const gchar   *query)
 {
 	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
 	g_return_if_fail (E_IS_DATA_BOOK (book));
 	g_return_if_fail (query);
+	g_return_if_fail (E_BOOK_BACKEND_GET_CLASS (backend)->get_contact_list);
 
-	g_assert (E_BOOK_BACKEND_GET_CLASS (backend)->get_contact_list);
-
-	g_object_ref (backend);
-
-	(* E_BOOK_BACKEND_GET_CLASS (backend)->get_contact_list) (backend, book, opid, query);
-
-	g_object_unref (backend);
+	if (e_book_backend_is_opening (backend))
+		e_data_book_respond_get_contact_list (book, opid, EDB_OPENING_ERROR, NULL);
+	else
+		(* E_BOOK_BACKEND_GET_CLASS (backend)->get_contact_list) (backend, book, opid, cancellable, query);
 }
 
 /**
@@ -519,14 +606,9 @@ e_book_backend_start_book_view (EBookBackend  *backend,
 {
 	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
 	g_return_if_fail (E_IS_DATA_BOOK_VIEW (book_view));
-
-	g_assert (E_BOOK_BACKEND_GET_CLASS (backend)->start_book_view);
-
-	g_object_ref (backend);
+	g_return_if_fail (E_BOOK_BACKEND_GET_CLASS (backend)->start_book_view);
 
 	(* E_BOOK_BACKEND_GET_CLASS (backend)->start_book_view) (backend, book_view);
-
-	g_object_unref (backend);
 }
 
 /**
@@ -543,181 +625,40 @@ e_book_backend_stop_book_view (EBookBackend  *backend,
 {
 	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
 	g_return_if_fail (E_IS_DATA_BOOK_VIEW (book_view));
-
-	g_assert (E_BOOK_BACKEND_GET_CLASS (backend)->stop_book_view);
-
-	g_object_ref (backend);
+	g_return_if_fail (E_BOOK_BACKEND_GET_CLASS (backend)->stop_book_view);
 
 	(* E_BOOK_BACKEND_GET_CLASS (backend)->stop_book_view) (backend, book_view);
-
-	g_object_unref (backend);
-}
-
-/**
- * e_book_backend_get_changes:
- * @backend: an #EBookBackend
- * @book: an #EDataBook
- * @opid: the ID to use for this operation
- * @change_id: the ID of the changeset
- *
- * Executes a 'get changes' request specified by @opid on @book
- * using @backend.
- **/
-void
-e_book_backend_get_changes (EBookBackend *backend,
-			    EDataBook    *book,
-			    guint32       opid,
-			    const gchar   *change_id)
-{
-	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
-	g_return_if_fail (E_IS_DATA_BOOK (book));
-	g_return_if_fail (change_id);
-
-	g_assert (E_BOOK_BACKEND_GET_CLASS (backend)->get_changes);
-
-	g_object_ref (backend);
-
-	(* E_BOOK_BACKEND_GET_CLASS (backend)->get_changes) (backend, book, opid, change_id);
-
-	g_object_unref (backend);
 }
 
 /**
  * e_book_backend_authenticate_user:
  * @backend: an #EBookBackend
- * @book: an #EDataBook
- * @opid: the ID to use for this operation
- * @user: the name of the user account
- * @passwd: the user's password
- * @auth_method: the authentication method to use
+ * @cancellable: a #GCancellable for the operation
+ * @credentials: #ECredentials to use for authentication
  *
- * Executes an 'authenticate' request specified by @opid on @book
- * using @backend.
- **/
-void
-e_book_backend_authenticate_user (EBookBackend *backend,
-				  EDataBook    *book,
-				  guint32       opid,
-				  const gchar   *user,
-				  const gchar   *passwd,
-				  const gchar   *auth_method)
-{
-	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
-	g_return_if_fail (E_IS_DATA_BOOK (book));
-	g_return_if_fail (user && passwd && auth_method);
-
-	g_assert (E_BOOK_BACKEND_GET_CLASS (backend)->authenticate_user);
-
-	g_object_ref (backend);
-
-	(* E_BOOK_BACKEND_GET_CLASS (backend)->authenticate_user) (backend, book, opid, user, passwd, auth_method);
-
-	g_object_unref (backend);
-}
-
-/**
- * e_book_backend_get_required_fields:
- * @backend: an #EBookBackend
- * @book: an #EDataBook
- * @opid: the ID to use for this operation
+ * Notifies @backend about @credentials provided by user to use
+ * for authentication. This notification is usually called during
+ * opening phase as a response to e_book_backend_notify_auth_required()
+ * on the client side and it results in setting property 'opening' to %TRUE
+ * unless the backend is already opened. This function finishes opening
+ * phase, thus it should be finished with e_book_backend_notify_opened().
  *
- * Executes a 'get required fields' request specified by @opid on @book
- * using @backend.
+ * See information at e_book_backend_open() for more details
+ * how the opening phase works.
  **/
 void
-e_book_backend_get_required_fields (EBookBackend *backend,
-				     EDataBook    *book,
-				     guint32       opid)
-
-{
-	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
-	g_return_if_fail (E_IS_DATA_BOOK (book));
-
-	g_assert (E_BOOK_BACKEND_GET_CLASS (backend)->get_required_fields);
-
-	g_object_ref (backend);
-
-	(* E_BOOK_BACKEND_GET_CLASS (backend)->get_required_fields) (backend, book, opid);
-
-	g_object_unref (backend);
-}
-
-/**
- * e_book_backend_get_supported_fields:
- * @backend: an #EBookBackend
- * @book: an #EDataBook
- * @opid: the ID to use for this operation
- *
- * Executes a 'get supported fields' request specified by @opid on @book
- * using @backend.
- **/
-void
-e_book_backend_get_supported_fields (EBookBackend *backend,
-				     EDataBook    *book,
-				     guint32       opid)
-
-{
-	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
-	g_return_if_fail (E_IS_DATA_BOOK (book));
-
-	g_assert (E_BOOK_BACKEND_GET_CLASS (backend)->get_supported_fields);
-
-	g_object_ref (backend);
-
-	(* E_BOOK_BACKEND_GET_CLASS (backend)->get_supported_fields) (backend, book, opid);
-
-	g_object_unref (backend);
-}
-
-/**
- * e_book_backend_get_supported_auth_methods:
- * @backend: an #EBookBackend
- * @book: an #EDataBook
- * @opid: the ID to use for this operation
- *
- * Executes a 'get supported auth methods' request specified by @opid on @book
- * using @backend.
- **/
-void
-e_book_backend_get_supported_auth_methods (EBookBackend *backend,
-					   EDataBook    *book,
-					   guint32       opid)
+e_book_backend_authenticate_user (EBookBackend *backend,
+				  GCancellable *cancellable,
+				  ECredentials *credentials)
 {
 	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
-	g_return_if_fail (E_IS_DATA_BOOK (book));
-
-	g_assert (E_BOOK_BACKEND_GET_CLASS (backend)->get_supported_auth_methods);
-
-	g_object_ref (backend);
-
-	(* E_BOOK_BACKEND_GET_CLASS (backend)->get_supported_auth_methods) (backend, book, opid);
-
-	g_object_unref (backend);
-}
-
-/**
- * e_book_backend_cancel_operation:
- * @backend: an #EBookBackend
- * @book: an #EDataBook whose operation should be cancelled
- * @error: #GError to set, when something fails
- *
- * Cancel @book's running operation on @backend.
- **/
-void
-e_book_backend_cancel_operation (EBookBackend *backend,
-				 EDataBook    *book,
-				 GError      **error)
-{
-	e_return_data_book_error_if_fail (E_IS_BOOK_BACKEND (backend), E_DATA_BOOK_STATUS_INVALID_ARG);
-	e_return_data_book_error_if_fail (E_IS_DATA_BOOK (book), E_DATA_BOOK_STATUS_INVALID_ARG);
-
-	g_assert (E_BOOK_BACKEND_GET_CLASS (backend)->cancel_operation);
-
-	g_object_ref (backend);
+	g_return_if_fail (credentials != NULL);
+	g_return_if_fail (E_BOOK_BACKEND_GET_CLASS (backend)->authenticate_user);
 
-	(* E_BOOK_BACKEND_GET_CLASS (backend)->cancel_operation) (backend, book, error);
+	if (backend->priv->opened)
+		backend->priv->opening = TRUE;
 
-	g_object_unref (backend);
+	(* E_BOOK_BACKEND_GET_CLASS (backend)->authenticate_user) (backend, cancellable, credentials);
 }
 
 static void
@@ -727,22 +668,6 @@ last_client_gone (EBookBackend *backend)
 }
 
 /**
- * e_book_backend_get_book_views:
- * @backend: an #EBookBackend
- *
- * Gets the list of #EDataBookView views running on this backend.
- *
- * Returns: An #EList of #EDataBookView objects.
- **/
-EList*
-e_book_backend_get_book_views (EBookBackend *backend)
-{
-	g_return_val_if_fail (E_IS_BOOK_BACKEND (backend), NULL);
-
-	return g_object_ref (backend->priv->views);
-}
-
-/**
  * e_book_backend_add_book_view:
  * @backend: an #EBookBackend
  * @view: an #EDataBookView
@@ -757,7 +682,7 @@ e_book_backend_add_book_view (EBookBackend *backend,
 
 	g_mutex_lock (backend->priv->views_mutex);
 
-	e_list_append (backend->priv->views, view);
+	backend->priv->views = g_slist_append (backend->priv->views, view);
 
 	g_mutex_unlock (backend->priv->views_mutex);
 }
@@ -777,7 +702,7 @@ e_book_backend_remove_book_view (EBookBackend *backend,
 
 	g_mutex_lock (backend->priv->views_mutex);
 
-	e_list_remove (backend->priv->views, view);
+	backend->priv->views = g_slist_remove (backend->priv->views, view);
 
 	g_mutex_unlock (backend->priv->views_mutex);
 }
@@ -799,7 +724,7 @@ e_book_backend_add_client (EBookBackend      *backend,
 	g_return_val_if_fail (E_IS_DATA_BOOK (book), FALSE);
 
 	g_mutex_lock (backend->priv->clients_mutex);
-	backend->priv->clients = g_list_prepend (backend->priv->clients, book);
+	backend->priv->clients = g_slist_prepend (backend->priv->clients, book);
 	g_mutex_unlock (backend->priv->clients_mutex);
 
 	return TRUE;
@@ -826,7 +751,7 @@ e_book_backend_remove_client (EBookBackend *backend,
 
 	/* Disconnect */
 	g_mutex_lock (backend->priv->clients_mutex);
-	backend->priv->clients = g_list_remove (backend->priv->clients, book);
+	backend->priv->clients = g_slist_remove (backend->priv->clients, book);
 
 	/* When all clients go away, notify the parent factory about it so that
 	 * it may decide whether to kill the backend or not.
@@ -840,108 +765,162 @@ e_book_backend_remove_client (EBookBackend *backend,
 }
 
 /**
- * e_book_backend_has_out_of_proc_clients:
+ * e_book_backend_foreach_view:
  * @backend: an #EBookBackend
+ * @callback: callback to call
+ * @user_data: user_data passed into the @callback
  *
- * Checks if @backend has clients running in other system processes.
- *
- * Returns: %TRUE if there are clients in other processes, %FALSE otherwise.
+ * Calls @callback for each known book view of this @backend.
+ * @callback returns %FALSE to stop further processing.
  **/
-gboolean
-e_book_backend_has_out_of_proc_clients (EBookBackend *backend)
+void
+e_book_backend_foreach_view (EBookBackend *backend, gboolean (* callback) (EDataBookView *view, gpointer user_data), gpointer user_data)
 {
-	return TRUE;
+	const GSList *views;
+	EDataBookView *view;
+	gboolean stop = FALSE;
+
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (callback != NULL);
+
+	g_mutex_lock (backend->priv->views_mutex);
+
+	for (views = backend->priv->views; views && !stop; views = views->next) {
+		view = E_DATA_BOOK_VIEW (views->data);
+
+		e_data_book_view_ref (view);
+		stop = !callback (view, user_data);
+		e_data_book_view_unref (view);
+	}
+
+	g_mutex_unlock (backend->priv->views_mutex);
 }
 
 /**
- * e_book_backend_get_static_capabilities:
+ * e_book_backend_get_book_backend_property:
  * @backend: an #EBookBackend
+ * @book: an #EDataBook
+ * @opid: the ID to use for this operation
+ * @cancellable: a #GCancellable for the operation
+ * @prop_name: property name to get value of; cannot be NULL
  *
- * Gets the capabilities offered by this @backend.
+ * Calls the get_backend_property method on the given backend.
+ * This might be finished with e_data_book_respond_get_backend_property().
+ * Default implementation takes care of common properties and returns
+ * an 'unsupported' error for any unknown properties. The subclass may
+ * always call this default implementation for properties which fetching
+ * it doesn't overwrite.
  *
- * Returns: A string listing the capabilities.
+ * Since: 3.2
  **/
-gchar *
-e_book_backend_get_static_capabilities (EBookBackend *backend)
+void
+e_book_backend_get_backend_property (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *prop_name)
 {
-	gchar *capabilities;
-
-	g_return_val_if_fail (E_IS_BOOK_BACKEND (backend), NULL);
-
-	g_assert (E_BOOK_BACKEND_GET_CLASS (backend)->get_static_capabilities);
-
-	g_object_ref (backend);
+	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
+	g_return_if_fail (E_BOOK_BACKEND_GET_CLASS (backend)->get_backend_property);
 
-	capabilities = E_BOOK_BACKEND_GET_CLASS (backend)->get_static_capabilities (backend);
+	E_BOOK_BACKEND_GET_CLASS (backend)->get_backend_property (backend, book, opid, cancellable, prop_name);
+}
 
-	g_object_unref (backend);
+/**
+ * e_book_backend_set_backend_property:
+ * @backend: an #EBookBackend
+ * @book: an #EDataBook
+ * @opid: the ID to use for this operation
+ * @cancellable: a #GCancellable for the operation
+ * @prop_name: property name to change; cannot be NULL
+ * @prop_value: value to set to @prop_name; cannot be NULL
+ *
+ * Calls the set_backend_property method on the given backend.
+ * This might be finished with e_data_book_respond_set_backend_property().
+ * Default implementation simply returns an 'unsupported' error.
+ * The subclass may always call this default implementation for properties
+ * which fetching it doesn't overwrite.
+ *
+ * Since: 3.2
+ **/
+void
+e_book_backend_set_backend_property (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *prop_name, const gchar *prop_value)
+{
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
+	g_return_if_fail (prop_name != NULL);
+	g_return_if_fail (prop_value != NULL);
+	g_return_if_fail (E_BOOK_BACKEND_GET_CLASS (backend)->set_backend_property != NULL);
 
-	return capabilities;
+	E_BOOK_BACKEND_GET_CLASS (backend)->set_backend_property (backend, book, opid, cancellable, prop_name, prop_value);
 }
 
 /**
- * e_book_backend_is_loaded:
+ * e_book_backend_is_online:
  * @backend: an #EBookBackend
  *
- * Checks if @backend's storage has been opened and the backend
- * itself is ready for accessing.
+ * Checks if @backend's storage is online.
  *
- * Returns: %TRUE if loaded, %FALSE otherwise.
+ * Returns: %TRUE if online, %FALSE otherwise.
  **/
 gboolean
-e_book_backend_is_loaded (EBookBackend *backend)
+e_book_backend_is_online (EBookBackend *backend)
 {
 	g_return_val_if_fail (E_IS_BOOK_BACKEND (backend), FALSE);
 
-	return backend->priv->loaded;
+	return backend->priv->online;
 }
 
 /**
- * e_book_backend_set_is_loaded:
+ * e_book_backend_is_opened:
  * @backend: an #EBookBackend
- * @is_loaded: A flag indicating whether the backend is loaded
  *
- * Sets the flag indicating whether @backend is loaded to @is_loaded.
- * Meant to be used by backend implementations.
+ * Checks if @backend's storage has been opened (and
+ * authenticated, if necessary) and the backend itself
+ * is ready for accessing. This property is changed automatically
+ * within call of e_book_backend_notify_opened().
+ *
+ * Returns: %TRUE if fully opened, %FALSE otherwise.
  **/
-void
-e_book_backend_set_is_loaded (EBookBackend *backend, gboolean is_loaded)
+gboolean
+e_book_backend_is_opened (EBookBackend *backend)
 {
-	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
+	g_return_val_if_fail (E_IS_BOOK_BACKEND (backend), FALSE);
 
-	backend->priv->loaded = is_loaded;
+	return backend->priv->opened;
 }
 
 /**
- * e_book_backend_is_writable:
+ * e_book_backend_is_opening:
  * @backend: an #EBookBackend
  *
- * Checks if we can write to @backend.
+ * Checks if @backend is processing its opening phase, which
+ * includes everything since the e_book_backend_open() call,
+ * through authentication, up to e_book_backend_notify_opened().
+ * This property is managed automatically and the backend deny
+ * every operation except of cancel and authenticate_user while
+ * it is being opening.
  *
- * Returns: %TRUE if writeable, %FALSE if not.
+ * Returns: %TRUE if opening phase is in the effect, %FALSE otherwise.
  **/
 gboolean
-e_book_backend_is_writable (EBookBackend *backend)
+e_book_backend_is_opening (EBookBackend *backend)
 {
 	g_return_val_if_fail (E_IS_BOOK_BACKEND (backend), FALSE);
 
-	return backend->priv->writable;
+	return backend->priv->opening;
 }
 
 /**
- * e_book_backend_set_is_writable:
+ * e_book_backend_is_readonly:
  * @backend: an #EBookBackend
- * @is_writable: A flag indicating whether the backend is writeable
  *
- * Sets the flag indicating whether @backend is writeable to @is_writeable.
- * Meant to be used by backend implementations.
+ * Checks if we can write to @backend.
+ *
+ * Returns: %TRUE if writeable, %FALSE if not.
  **/
-void
-e_book_backend_set_is_writable (EBookBackend *backend, gboolean is_writable)
+gboolean
+e_book_backend_is_readonly (EBookBackend *backend)
 {
-	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
+	g_return_val_if_fail (E_IS_BOOK_BACKEND (backend), FALSE);
 
-	backend->priv->writable = is_writable;
+	return backend->priv->readonly;
 }
 
 /**
@@ -977,26 +956,19 @@ e_book_backend_set_is_removed (EBookBackend *backend, gboolean is_removed)
 }
 
 /**
- * e_book_backend_set_mode:
+ * e_book_backend_set_online:
  * @backend: an #EBookbackend
- * @mode: a mode indicating the online/offline status of the backend
+ * @is_online: a mode indicating the online/offline status of the backend
  *
- * Sets @backend's online/offline mode to @mode. Mode can be 1 for offline
- * or 2 indicating that it is connected and online.
+ * Sets @backend's online/offline mode to @is_online.
  **/
 void
-e_book_backend_set_mode (EBookBackend *backend,
-			 EDataBookMode mode)
+e_book_backend_set_online (EBookBackend *backend, gboolean is_online)
 {
 	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
+	g_return_if_fail (E_BOOK_BACKEND_GET_CLASS (backend)->set_online);
 
-	g_assert (E_BOOK_BACKEND_GET_CLASS (backend)->set_mode);
-
-	g_object_ref (backend);
-
-	(* E_BOOK_BACKEND_GET_CLASS (backend)->set_mode) (backend,  mode);
-
-	g_object_unref (backend);
+	(* E_BOOK_BACKEND_GET_CLASS (backend)->set_online) (backend,  is_online);
 }
 
 /**
@@ -1022,98 +994,14 @@ e_book_backend_sync (EBookBackend *backend)
 	g_object_unref (backend);
 }
 
-/**
- * e_book_backend_change_add_new:
- * @vcard: a VCard string
- *
- * Creates a new change item indicating @vcard was added.
- * Meant to be used by backend implementations.
- *
- * Returns: A new #EDataBookChange.
- **/
-EDataBookChange *
-e_book_backend_change_add_new     (const gchar *vcard)
-{
-  EDataBookChange *new_change = g_new (EDataBookChange, 1);
-
-	new_change->change_type = E_DATA_BOOK_BACKEND_CHANGE_ADDED;
-	new_change->vcard = g_strdup (vcard);
-
-	return new_change;
-}
-
-/**
- * e_book_backend_change_modify_new:
- * @vcard: a VCard string
- *
- * Creates a new change item indicating @vcard was modified.
- * Meant to be used by backend implementations.
- *
- * Returns: A new #EDataBookChange.
- **/
-EDataBookChange *
-e_book_backend_change_modify_new  (const gchar *vcard)
-{
-  EDataBookChange *new_change = g_new (EDataBookChange, 1);
-
-	new_change->change_type = E_DATA_BOOK_BACKEND_CHANGE_MODIFIED;
-	new_change->vcard = g_strdup (vcard);
-
-	return new_change;
-}
-
-/**
- * e_book_backend_change_delete_new:
- * @vcard: a VCard string
- *
- * Creates a new change item indicating @vcard was deleted.
- * Meant to be used by backend implementations.
- *
- * Returns: A new #EDataBookChange.
- **/
-EDataBookChange *
-e_book_backend_change_delete_new  (const gchar *vcard)
-{
-  EDataBookChange *new_change = g_new (EDataBookChange, 1);
-
-	new_change->change_type = E_DATA_BOOK_BACKEND_CHANGE_DELETED;
-	new_change->vcard = g_strdup (vcard);
-
-	return new_change;
-}
-
 
 
-static void
-e_book_backend_foreach_view (EBookBackend *backend,
-			     void (*callback) (EDataBookView *, gpointer),
-			     gpointer user_data)
-{
-	EList *views;
-	EDataBookView *view;
-	EIterator *iter;
-
-	views = e_book_backend_get_book_views (backend);
-	iter = e_list_get_iterator (views);
-
-	while (e_iterator_is_valid (iter)) {
-		view = (EDataBookView*) e_iterator_get (iter);
-
-		e_data_book_view_ref (view);
-		callback (view, user_data);
-		e_data_book_view_unref (view);
-
-		e_iterator_next (iter);
-	}
-
-	g_object_unref (iter);
-	g_object_unref (views);
-}
-
-static void
+static gboolean
 view_notify_update (EDataBookView *view, gpointer contact)
 {
 	e_data_book_view_notify_update (view, contact);
+
+	return TRUE;
 }
 
 /**
@@ -1129,15 +1017,17 @@ view_notify_update (EDataBookView *view, gpointer contact)
  * contacts are created or modified by another (non-PAS-using) client.
  **/
 void
-e_book_backend_notify_update (EBookBackend *backend, EContact *contact)
+e_book_backend_notify_update (EBookBackend *backend, const EContact *contact)
 {
-	e_book_backend_foreach_view (backend, view_notify_update, contact);
+	e_book_backend_foreach_view (backend, view_notify_update, (gpointer) contact);
 }
 
-static void
+static gboolean
 view_notify_remove (EDataBookView *view, gpointer id)
 {
 	e_data_book_view_notify_remove (view, id);
+
+	return TRUE;
 }
 
 /**
@@ -1158,10 +1048,12 @@ e_book_backend_notify_remove (EBookBackend *backend, const gchar *id)
 	e_book_backend_foreach_view (backend, view_notify_remove, (gpointer) id);
 }
 
-static void
+static gboolean
 view_notify_complete (EDataBookView *view, gpointer unused)
 {
 	e_data_book_view_notify_complete (view, NULL /* SUCCESS */);
+
+	return TRUE;
 }
 
 /**
@@ -1180,31 +1072,56 @@ e_book_backend_notify_complete (EBookBackend *backend)
 
 
 /**
- * e_book_backend_notify_writable:
+ * e_book_backend_notify_error:
  * @backend: an #EBookBackend
- * @is_writable: flag indicating writable status
+ * @message: an error message
  *
- * Notifies all backends clients about the current writable state.
+ * Notifies each backend listener about an error. This is meant to be used
+ * for cases where is no GError return possibility, to notify user about
+ * an issue.
  **/
 void
-e_book_backend_notify_writable (EBookBackend *backend, gboolean is_writable)
+e_book_backend_notify_error (EBookBackend *backend, const gchar *message)
 {
 	EBookBackendPrivate *priv;
-	GList *clients;
+	GSList *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);
+	for (clients = priv->clients; clients != NULL; clients = g_slist_next (clients))
+		e_data_book_report_error (E_DATA_BOOK (clients->data), message);
+
+	g_mutex_unlock (priv->clients_mutex);
+}
+
+/**
+ * e_book_backend_notify_readonly:
+ * @backend: an #EBookBackend
+ * @is_readonly: flag indicating readonly status
+ *
+ * Notifies all backend's clients about the current readonly state.
+ **/
+void
+e_book_backend_notify_readonly (EBookBackend *backend, gboolean is_readonly)
+{
+	EBookBackendPrivate *priv;
+	GSList *clients;
+
+	priv = backend->priv;
+	priv->readonly = is_readonly;
+	g_mutex_lock (priv->clients_mutex);
+
+	for (clients = priv->clients; clients != NULL; clients = g_slist_next (clients))
+		e_data_book_report_readonly (E_DATA_BOOK (clients->data), is_readonly);
 
 	g_mutex_unlock (priv->clients_mutex);
 
 }
 
 /**
- * e_book_backend_notify_connection_status:
+ * e_book_backend_notify_online:
  * @backend: an #EBookBackend
  * @is_online: flag indicating whether @backend is connected and online
  *
@@ -1212,17 +1129,17 @@ e_book_backend_notify_writable (EBookBackend *backend, gboolean is_writable)
  * Meant to be used by backend implementations.
  **/
 void
-e_book_backend_notify_connection_status (EBookBackend *backend, gboolean is_online)
+e_book_backend_notify_online (EBookBackend *backend, gboolean is_online)
 {
 	EBookBackendPrivate *priv;
-	GList *clients;
+	GSList *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);
+	for (clients = priv->clients; clients != NULL; clients = g_slist_next (clients))
+		e_data_book_report_online (E_DATA_BOOK (clients->data), is_online);
 
 	g_mutex_unlock (priv->clients_mutex);
 }
@@ -1230,21 +1147,110 @@ e_book_backend_notify_connection_status (EBookBackend *backend, gboolean is_onli
 /**
  * e_book_backend_notify_auth_required:
  * @backend: an #EBookBackend
+ * @is_self: Use %TRUE to indicate the authentication is required
+ *    for the @backend, otheriwse the authentication is for any
+ *    other source. Having @credentials %NULL means @is_self
+ *    automatically.
+ * @credentials: an #ECredentials that contains extra information for
+ *    a source for which authentication is requested.
+ *    This parameter can be %NULL to indicate "for this book".
  *
  * Notifies clients that @backend requires authentication in order to
- * connect. Means to be used by backend implementations.
+ * connect. This function call does not influence 'opening', but 
+ * influences 'opened' property, which is set to %FALSE when @is_self
+ * is %TRUE or @credentials is %NULL. Opening phase is finished
+ * by e_book_backend_notify_opened() if this is requested for @backend.
+ *
+ * See e_book_backend_open() for a description how the whole opening
+ * phase works.
+ *
+ * Meant to be used by backend implementations.
+ **/
+void
+e_book_backend_notify_auth_required (EBookBackend *backend, gboolean is_self, const ECredentials *credentials)
+{
+	EBookBackendPrivate *priv;
+	GSList *clients;
+
+	priv = backend->priv;
+	g_mutex_lock (priv->clients_mutex);
+
+	if (is_self || !credentials)
+		priv->opened = FALSE;
+
+	for (clients = priv->clients; clients != NULL; clients = g_slist_next (clients))
+		e_data_book_report_auth_required (E_DATA_BOOK (clients->data), credentials);
+
+	g_mutex_unlock (priv->clients_mutex);
+}
+
+/**
+ * e_book_backend_notify_opened:
+ * @backend: an #EBookBackend
+ * @error: a #GError corresponding to the error encountered during
+ *    the opening phase. Use %NULL for success. The @error is freed
+ *    automatically if not %NULL.
+ *
+ * Notifies clients that @backend finished its opening phase.
+ * See e_book_backend_open() for more information how the opening
+ * phase works. Calling this function changes 'opening' property,
+ * same as 'opened'. 'opening' is set to %FALSE and the backend
+ * is considered 'opened' only if the @error is %NULL.
+ *
+ * See also: e_book_backend_respond_opened()
+ *
+ * Note: The @error is freed automatically if not %NULL.
+ *
+ * Meant to be used by backend implementations.
  **/
 void
-e_book_backend_notify_auth_required (EBookBackend *backend)
+e_book_backend_notify_opened (EBookBackend *backend, GError *error)
 {
 	EBookBackendPrivate *priv;
-	GList *clients;
+	GSList *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));
+	priv->opening = FALSE;
+	priv->opened = error == NULL;
+
+	for (clients = priv->clients; clients != NULL; clients = g_slist_next (clients))
+		e_data_book_report_opened (E_DATA_BOOK (clients->data), error);
+
 	g_mutex_unlock (priv->clients_mutex);
+
+	if (error)
+		g_error_free (error);
 }
 
+/**
+ * e_book_backend_respond_opened:
+ * @backend: an #EBookBackend
+ * @book: an #EDataBook
+ * @opid: an operation ID
+ * @error: result error; can be %NULL, if it isn't then it's automatically freed
+ *
+ * This is a replacement for e_data_book_respond_open() for cases where
+ * the finish of 'open' method call also finishes backend opening phase.
+ * This function covers calling of both e_data_book_respond_open() and
+ * e_book_backend_notify_opened() with the same @error.
+ *
+ * See e_book_backend_open() for more details how the opening phase works.
+ **/
+void
+e_book_backend_respond_opened (EBookBackend *backend, EDataBook *book, guint32 opid, GError *error)
+{
+	GError *copy = NULL;
+
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (E_IS_BOOK_BACKEND (backend));
+	g_return_if_fail (book != NULL);
+	g_return_if_fail (opid != 0);
+
+	if (error)
+		copy = g_error_copy (error);
+
+	e_data_book_respond_open (book, opid, error);
+	e_book_backend_notify_opened (backend, copy);
+}
diff --git a/addressbook/libedata-book/e-book-backend.h b/addressbook/libedata-book/e-book-backend.h
index 6d96b1a..ad8be78 100644
--- a/addressbook/libedata-book/e-book-backend.h
+++ b/addressbook/libedata-book/e-book-backend.h
@@ -24,11 +24,13 @@
 
 #include <glib.h>
 #include <glib-object.h>
+#include <gio/gio.h>
+
 #include <libebook/e-contact.h>
 #include <libedata-book/e-data-book-types.h>
 #include <libedata-book/e-data-book.h>
-#include <libedataserver/e-list.h>
 #include <libedataserver/e-source.h>
+#include <libedataserver/e-credentials.h>
 
 G_BEGIN_DECLS
 
@@ -39,6 +41,16 @@ G_BEGIN_DECLS
 #define E_IS_BOOK_BACKEND_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_BOOK_BACKEND))
 #define E_BOOK_BACKEND_GET_CLASS(k) (G_TYPE_INSTANCE_GET_CLASS ((k), E_TYPE_BOOK_BACKEND, EBookBackendClass))
 
+#define CLIENT_BACKEND_PROPERTY_OPENED			"opened"
+#define CLIENT_BACKEND_PROPERTY_OPENING			"opening"
+#define CLIENT_BACKEND_PROPERTY_ONLINE			"online"
+#define CLIENT_BACKEND_PROPERTY_READONLY		"readonly"
+#define CLIENT_BACKEND_PROPERTY_CACHE_DIR		"cache-dir"
+#define CLIENT_BACKEND_PROPERTY_CAPABILITIES		"capabilities"
+#define BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS		"required-fields"
+#define BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS		"supported-fields"
+#define BOOK_BACKEND_PROPERTY_SUPPORTED_AUTH_METHODS	"supported-auth-methods"
+
 typedef struct _EBookBackendPrivate EBookBackendPrivate;
 
 struct _EBookBackend {
@@ -50,153 +62,82 @@ struct _EBookBackendClass {
 	GObjectClass parent_class;
 
 	/* Virtual methods */
-	void (*load_source) (EBookBackend *backend, ESource *source, gboolean only_if_exists, GError **error);
-	void (*remove) (EBookBackend *backend, EDataBook *book, guint32 opid);
-        gchar *(*get_static_capabilities) (EBookBackend *backend);
-
-	void (*create_contact)  (EBookBackend *backend, EDataBook *book, guint32 opid, const gchar *vcard);
-	void (*remove_contacts) (EBookBackend *backend, EDataBook *book, guint32 opid, GList *id_list);
-	void (*modify_contact)  (EBookBackend *backend, EDataBook *book, guint32 opid, const gchar *vcard);
-	void (*get_contact) (EBookBackend *backend, EDataBook *book, guint32 opid, const gchar *id);
-	void (*get_contact_list) (EBookBackend *backend, EDataBook *book, guint32 opid, const gchar *query);
-	void (*start_book_view) (EBookBackend *backend, EDataBookView *book_view);
-	void (*stop_book_view) (EBookBackend *backend, EDataBookView *book_view);
-	void (*get_changes) (EBookBackend *backend, EDataBook *book, guint32 opid, const gchar *change_id);
-	void (*authenticate_user) (EBookBackend *backend, EDataBook *book, guint32 opid, const gchar *user, const gchar *passwd, const gchar *auth_method);
-	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);
-	void (*cancel_operation) (EBookBackend *backend, EDataBook *book, GError **error);
-	void (*set_mode) (EBookBackend *backend, EDataBookMode mode);
+        void	(* get_backend_property)	(EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *prop_name);
+        void	(* set_backend_property)	(EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *prop_name, const gchar *prop_value);
 
-	/* Notification signals */
-	void (* last_client_gone) (EBookBackend *backend);
+	void	(* open)			(EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, gboolean only_if_exists);
+	void	(* remove)			(EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable);
+	void	(* set_online)			(EBookBackend *backend, gboolean is_online);
+	void	(* authenticate_user)		(EBookBackend *backend, GCancellable *cancellable, ECredentials *credentials);
 
-	void (*sync) (EBookBackend *backend);
+	void	(* refresh)			(EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable);
+	void	(* create_contact)		(EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *vcard);
+	void	(* remove_contacts)		(EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const GSList *id_list);
+	void	(* modify_contact)		(EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *vcard);
+	void	(* get_contact)			(EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *id);
+	void	(* get_contact_list)		(EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *query);
 
-	/* Padding for future expansion */
-	void (*_pas_reserved1) (void);
-	void (*_pas_reserved2) (void);
-	void (*_pas_reserved3) (void);
-	void (*_pas_reserved4) (void);
+	void	(* start_book_view)		(EBookBackend *backend, EDataBookView *book_view);
+	void	(* stop_book_view)		(EBookBackend *backend, EDataBookView *book_view);
+
+	/* Notification signals */
+	void	(* last_client_gone)		(EBookBackend *backend);
+	void	(* sync)			(EBookBackend *backend);
 };
 
-const gchar *e_book_backend_get_cache_dir           (EBookBackend             *backend);
-void        e_book_backend_set_cache_dir            (EBookBackend             *backend,
-                                                     const gchar              *cache_dir);
-
-void        e_book_backend_load_source              (EBookBackend             *backend,
-						     ESource                  *source,
-						     gboolean                  only_if_exists,
-						     GError		     **error);
-ESource    *e_book_backend_get_source               (EBookBackend             *backend);
-
-gboolean    e_book_backend_add_client               (EBookBackend             *backend,
-						     EDataBook                *book);
-void        e_book_backend_remove_client            (EBookBackend             *backend,
-						     EDataBook                *book);
-gboolean    e_book_backend_has_out_of_proc_clients (EBookBackend *backend);
-gchar       *e_book_backend_get_static_capabilities  (EBookBackend             *backend);
-
-gboolean    e_book_backend_is_loaded                (EBookBackend             *backend);
-
-gboolean    e_book_backend_is_writable              (EBookBackend             *backend);
-
-gboolean    e_book_backend_is_removed               (EBookBackend             *backend);
-
-void        e_book_backend_open                     (EBookBackend             *backend,
-						     EDataBook                *book,
-						     guint32                   opid,
-						     gboolean                  only_if_exists);
-void        e_book_backend_remove                   (EBookBackend             *backend,
-						     EDataBook                *book,
-						     guint32                   opid);
-void        e_book_backend_create_contact           (EBookBackend             *backend,
-						     EDataBook                *book,
-						     guint32                   opid,
-						     const gchar               *vcard);
-void        e_book_backend_remove_contacts          (EBookBackend             *backend,
-						     EDataBook                *book,
-						     guint32                   opid,
-						     GList                    *id_list);
-void        e_book_backend_modify_contact           (EBookBackend             *backend,
-						     EDataBook                *book,
-						     guint32                   opid,
-						     const gchar               *vcard);
-void        e_book_backend_get_contact              (EBookBackend             *backend,
-						     EDataBook                *book,
-						     guint32                   opid,
-						     const gchar               *id);
-void        e_book_backend_get_contact_list         (EBookBackend             *backend,
-						     EDataBook                *book,
-						     guint32                   opid,
-						     const gchar               *query);
-void        e_book_backend_get_changes              (EBookBackend             *backend,
-						     EDataBook                *book,
-						     guint32                   opid,
-						     const gchar               *change_id);
-void        e_book_backend_authenticate_user        (EBookBackend             *backend,
-						     EDataBook                *book,
-						     guint32                   opid,
-						     const gchar               *user,
-						     const gchar               *passwd,
-						     const gchar               *auth_method);
-void        e_book_backend_get_supported_fields     (EBookBackend             *backend,
-						     EDataBook                *book,
-						     guint32                   opid);
-
-void        e_book_backend_get_required_fields      (EBookBackend             *backend,
-						     EDataBook                *book,
-						     guint32                   opid);
-
-void        e_book_backend_get_supported_auth_methods (EBookBackend           *backend,
-						       EDataBook              *book,
-						       guint32                 opid);
-void		e_book_backend_cancel_operation (EBookBackend           *backend,
-						 EDataBook              *book,
-						 GError **error);
-void        e_book_backend_set_mode (EBookBackend           *backend,
-				     EDataBookMode           mode);
-
-void        e_book_backend_start_book_view            (EBookBackend           *backend,
-						       EDataBookView          *view);
-void        e_book_backend_stop_book_view             (EBookBackend           *backend,
-						       EDataBookView          *view);
-
-void        e_book_backend_add_book_view              (EBookBackend           *backend,
-						       EDataBookView          *view);
-
-void        e_book_backend_remove_book_view           (EBookBackend           *backend,
-						       EDataBookView          *view);
-
-EList      *e_book_backend_get_book_views             (EBookBackend           *backend);
-
-void        e_book_backend_notify_update              (EBookBackend           *backend,
-						       EContact               *contact);
-void        e_book_backend_notify_remove              (EBookBackend           *backend,
-						       const gchar             *id);
-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_sync                       (EBookBackend *backend);
-
-GType       e_book_backend_get_type                 (void);
+GType		e_book_backend_get_type		(void);
+
+const gchar *	e_book_backend_get_cache_dir	(EBookBackend *backend);
+void		e_book_backend_set_cache_dir	(EBookBackend *backend, const gchar *cache_dir);
+
+ESource *	e_book_backend_get_source	(EBookBackend *backend);
+
+gboolean	e_book_backend_add_client	(EBookBackend *backend, EDataBook *book);
+void		e_book_backend_remove_client	(EBookBackend *backend, EDataBook *book);
+
+gboolean	e_book_backend_is_online	(EBookBackend *backend);
+gboolean	e_book_backend_is_opened	(EBookBackend *backend);
+gboolean	e_book_backend_is_opening	(EBookBackend *backend);
+gboolean	e_book_backend_is_readonly	(EBookBackend *backend);
+gboolean	e_book_backend_is_removed	(EBookBackend *backend);
+void		e_book_backend_set_online	(EBookBackend *backend, gboolean is_online);
+void		e_book_backend_authenticate_user(EBookBackend *backend, GCancellable *cancellable, ECredentials *credentials);
+
+void		e_book_backend_get_backend_property (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *prop_name);
+void		e_book_backend_set_backend_property (EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *prop_name, const gchar *prop_value);
+
+void		e_book_backend_open		(EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, gboolean only_if_exists);
+void		e_book_backend_remove		(EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable);
+void		e_book_backend_refresh		(EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable);
+void		e_book_backend_create_contact	(EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *vcard);
+void		e_book_backend_remove_contacts	(EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const GSList *id_list);
+void		e_book_backend_modify_contact	(EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *vcard);
+void		e_book_backend_get_contact	(EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *id);
+void		e_book_backend_get_contact_list	(EBookBackend *backend, EDataBook *book, guint32 opid, GCancellable *cancellable, const gchar *query);
+
+void		e_book_backend_start_book_view	(EBookBackend *backend, EDataBookView *view);
+void		e_book_backend_stop_book_view	(EBookBackend *backend, EDataBookView *view);
+void		e_book_backend_add_book_view	(EBookBackend *backend, EDataBookView *view);
+void		e_book_backend_remove_book_view	(EBookBackend *backend, EDataBookView *view);
+void		e_book_backend_foreach_view	(EBookBackend *backend, gboolean (* callback) (EDataBookView *view, gpointer user_data), gpointer user_data);
+
+void		e_book_backend_notify_update	(EBookBackend *backend, const EContact *contact);
+void		e_book_backend_notify_remove	(EBookBackend *backend, const gchar *id);
+void		e_book_backend_notify_complete	(EBookBackend *backend);
+
+void		e_book_backend_notify_error	(EBookBackend *backend, const gchar *message);
+void		e_book_backend_notify_readonly	(EBookBackend *backend, gboolean is_readonly);
+void		e_book_backend_notify_online	(EBookBackend *backend, gboolean is_online);
+void		e_book_backend_notify_auth_required (EBookBackend *backend, gboolean is_self, const ECredentials *credentials);
+void		e_book_backend_notify_opened	(EBookBackend *backend, GError *error);
+
+void		e_book_backend_sync		(EBookBackend *backend);
 
 /* protected functions for subclasses */
-void        e_book_backend_set_is_loaded            (EBookBackend             *backend,
-						     gboolean                  is_loaded);
-void        e_book_backend_set_is_writable          (EBookBackend             *backend,
-						     gboolean                  is_writable);
-void        e_book_backend_set_is_removed           (EBookBackend             *backend,
-						     gboolean                  is_removed);
-
-/* useful for implementing _get_changes in backends */
-EDataBookChange* e_book_backend_change_add_new     (const gchar *vcard);
-EDataBookChange* e_book_backend_change_modify_new  (const gchar *vcard);
-EDataBookChange* e_book_backend_change_delete_new  (const gchar *id);
+void		e_book_backend_set_is_removed	(EBookBackend *backend, gboolean is_removed);
+
+void		e_book_backend_respond_opened	(EBookBackend *backend, EDataBook *book, guint32 opid, GError *error);
 
 G_END_DECLS
 
 #endif /* __E_BOOK_BACKEND_H__ */
-
diff --git a/addressbook/libedata-book/e-data-book-factory.c b/addressbook/libedata-book/e-data-book-factory.c
index 4fc5fae..e74a108 100644
--- a/addressbook/libedata-book/e-data-book-factory.c
+++ b/addressbook/libedata-book/e-data-book-factory.c
@@ -39,7 +39,7 @@
 #include "e-data-book.h"
 #include "e-book-backend.h"
 
-#include "e-gdbus-egdbusbookfactory.h"
+#include "e-gdbus-book-factory.h"
 
 #ifdef G_OS_WIN32
 #include <windows.h>
@@ -90,7 +90,8 @@ struct _EDataBookFactoryPrivate {
 
 	guint exit_timeout;
 
-        gint mode;
+	/* whether should be online */
+        gboolean is_online;
 };
 
 /* Forward Declarations */
@@ -167,28 +168,27 @@ set_backend_online_status (gpointer key, gpointer value, gpointer data)
 
 	g_return_if_fail (backend != NULL);
 
-	e_book_backend_set_mode (backend,  GPOINTER_TO_INT (data));
+	e_book_backend_set_online (backend,  GPOINTER_TO_INT (data));
 }
 
 /**
- * e_data_book_factory_set_backend_mode:
+ * e_data_book_factory_set_backend_online:
  * @factory: A bookendar factory.
- * @mode: Online mode to set.
+ * @is_online: Online mode to set.
  *
  * Sets the online mode for all backends created by the given factory.
  */
 void
-e_data_book_factory_set_backend_mode (EDataBookFactory *factory,
-                                      gint mode)
+e_data_book_factory_set_backend_online (EDataBookFactory *factory, gboolean is_online)
 {
 	g_return_if_fail (E_IS_DATA_BOOK_FACTORY (factory));
 
-	factory->priv->mode = mode;
+	factory->priv->is_online = is_online;
 	g_mutex_lock (factory->priv->backends_lock);
 	g_hash_table_foreach (
 		factory->priv->backends,
 		set_backend_online_status,
-		GINT_TO_POINTER (factory->priv->mode));
+		GINT_TO_POINTER (factory->priv->is_online));
 	g_mutex_unlock (factory->priv->backends_lock);
 }
 
@@ -291,6 +291,14 @@ backend_gone_cb (EDataBookFactory *factory, GObject *dead)
 	g_mutex_unlock (priv->backends_lock);
 }
 
+static void
+last_client_gone_cb (EBookBackend *backend, EDataBookFactory *factory)
+{
+	backend_gone_cb (factory, (GObject *) backend);
+	g_object_weak_unref (G_OBJECT (backend), (GWeakNotify) backend_gone_cb, factory);
+	g_object_unref (backend);
+}
+
 static gboolean
 impl_BookFactory_getBook (EGdbusBookFactory *object, GDBusMethodInvocation *invocation, const gchar *in_source, EDataBookFactory *factory)
 {
@@ -311,12 +319,6 @@ impl_BookFactory_getBook (EGdbusBookFactory *object, GDBusMethodInvocation *invo
 		return TRUE;
 	}
 
-	/* Remove a pending exit */
-	if (priv->exit_timeout) {
-		g_source_remove (priv->exit_timeout);
-		priv->exit_timeout = 0;
-	}
-
 	g_mutex_lock (priv->backends_lock);
 
 	source = e_source_new_from_standalone_xml (in_source);
@@ -361,8 +363,8 @@ impl_BookFactory_getBook (EGdbusBookFactory *object, GDBusMethodInvocation *invo
 			g_hash_table_insert (
 				priv->backends, uri_key, backend);
 			g_object_weak_ref (G_OBJECT (backend), (GWeakNotify) backend_gone_cb, factory);
-			g_signal_connect (backend, "last-client-gone", G_CALLBACK (g_object_unref), NULL);
-			e_book_backend_set_mode (backend, priv->mode);
+			g_signal_connect (backend, "last-client-gone", G_CALLBACK (last_client_gone_cb), factory);
+			e_book_backend_set_online (backend, priv->is_online);
 		}
 	}
 
@@ -380,6 +382,12 @@ impl_BookFactory_getBook (EGdbusBookFactory *object, GDBusMethodInvocation *invo
 		return TRUE;
 	}
 
+	/* Remove a pending exit */
+	if (priv->exit_timeout) {
+		g_source_remove (priv->exit_timeout);
+		priv->exit_timeout = 0;
+	}
+
 	path = construct_book_factory_path ();
 	book = e_data_book_new (backend, source);
 	g_hash_table_insert (priv->books, g_strdup (path), book);
@@ -403,11 +411,10 @@ impl_BookFactory_getBook (EGdbusBookFactory *object, GDBusMethodInvocation *invo
 	g_object_unref (source);
 	g_free (uri);
 
-	if (error) {
-		g_dbus_method_invocation_return_gerror (invocation, error);
+	e_gdbus_book_factory_complete_get_book (object, invocation, path, error);
+
+	if (error)
 		g_error_free (error);
-	} else
-		e_gdbus_book_factory_complete_get_book (object, invocation, path);
 
 	g_free (path);
 
@@ -523,9 +530,7 @@ offline_state_changed_cb (EOfflineListener *eol, EDataBookFactory *factory)
 
 	g_return_if_fail (state == EOL_STATE_ONLINE || state == EOL_STATE_OFFLINE);
 
-	e_data_book_factory_set_backend_mode (
-		factory, state == EOL_STATE_ONLINE ?
-		E_DATA_BOOK_MODE_REMOTE : E_DATA_BOOK_MODE_LOCAL);
+	e_data_book_factory_set_backend_online (factory, state == EOL_STATE_ONLINE);
 }
 
 static void
diff --git a/addressbook/libedata-book/e-data-book-factory.h b/addressbook/libedata-book/e-data-book-factory.h
index 636ee53..90c68c6 100644
--- a/addressbook/libedata-book/e-data-book-factory.h
+++ b/addressbook/libedata-book/e-data-book-factory.h
@@ -52,7 +52,7 @@ GQuark e_data_book_factory_error_quark (void);
 
 GType e_data_book_factory_get_type (void);
 
-void e_data_book_factory_set_backend_mode (EDataBookFactory *factory, gint mode);
+void e_data_book_factory_set_backend_online (EDataBookFactory *factory, gboolean is_online);
 
 G_END_DECLS
 
diff --git a/addressbook/libedata-book/e-data-book-types.h b/addressbook/libedata-book/e-data-book-types.h
index c6cdfaa..5434815 100644
--- a/addressbook/libedata-book/e-data-book-types.h
+++ b/addressbook/libedata-book/e-data-book-types.h
@@ -46,6 +46,7 @@ typedef struct _EDataBookClass   EDataBookClass;
 
 typedef enum {
 	E_DATA_BOOK_STATUS_SUCCESS,
+	E_DATA_BOOK_STATUS_BUSY,
 	E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE,
 	E_DATA_BOOK_STATUS_PERMISSION_DENIED,
 	E_DATA_BOOK_STATUS_CONTACT_NOT_FOUND,
@@ -70,23 +71,6 @@ typedef enum {
 	E_DATA_BOOK_STATUS_NOT_SUPPORTED
 } EDataBookStatus;
 
-typedef enum {
-	E_DATA_BOOK_MODE_LOCAL,
-	E_DATA_BOOK_MODE_REMOTE,
-	E_DATA_BOOK_MODE_ANY,
-} EDataBookMode;
-
-typedef enum {
-	E_DATA_BOOK_BACKEND_CHANGE_ADDED,
-	E_DATA_BOOK_BACKEND_CHANGE_DELETED,
-	E_DATA_BOOK_BACKEND_CHANGE_MODIFIED
-} EDataBookChangeType;
-
-typedef struct {
-	EDataBookChangeType change_type;
-	gchar *vcard;
-} EDataBookChange;
-
 G_END_DECLS
 
 #endif /* __E_DATA_BOOK_TYPES_H__ */
diff --git a/addressbook/libedata-book/e-data-book-view.c b/addressbook/libedata-book/e-data-book-view.c
index 2ecfbc5..6666cb5 100644
--- a/addressbook/libedata-book/e-data-book-view.c
+++ b/addressbook/libedata-book/e-data-book-view.c
@@ -29,7 +29,7 @@
 #include "libedataserver/e-data-server-util.h"
 #include "e-data-book-view.h"
 
-#include "e-gdbus-egdbusbookview.h"
+#include "e-gdbus-book-view.h"
 
 static void reset_array (GArray *array);
 static void ensure_pending_flush_timeout (EDataBookView *view);
@@ -47,7 +47,6 @@ struct _EDataBookViewPrivate {
 
 	gchar * card_query;
 	EBookBackendSExp *card_sexp;
-	gint max_results;
 
 	gboolean running;
 	GMutex *pending_mutex;
@@ -60,6 +59,9 @@ struct _EDataBookViewPrivate {
 	guint idle_id;
 
 	guint flush_id;
+
+	/* which fields is listener interested in */
+	GHashTable *fields_of_interest;
 };
 
 static void e_data_book_view_dispose (GObject *object);
@@ -76,6 +78,43 @@ e_data_book_view_class_init (EDataBookViewClass *klass)
 	object_class->finalize = e_data_book_view_finalize;
 }
 
+static guint
+str_ic_hash (gconstpointer key)
+{
+	guint32 hash = 5381;
+	const gchar *str = key;
+	gint ii;
+
+	if (!str)
+		return hash;
+
+	for (ii = 0; str[ii]; ii++) {
+		hash = hash * 33 + g_ascii_tolower (str[ii]);
+	}
+
+	return hash;
+}
+
+static gboolean
+str_ic_equal (gconstpointer a, gconstpointer b)
+{
+	const gchar *stra = a, *strb = b;
+	gint ii;
+
+	if (!stra && !strb)
+		return TRUE;
+
+	if (!stra || !strb)
+		return FALSE;
+
+	for (ii = 0; stra[ii] && strb[ii]; ii++) {
+		if (g_ascii_tolower (stra[ii]) != g_ascii_tolower (strb[ii]))
+			return FALSE;
+	}
+
+	return stra[ii] == strb[ii];
+}
+
 /**
  * e_data_book_view_register_gdbus_object:
  *
@@ -117,7 +156,7 @@ send_pending_adds (EDataBookView *view)
 	if (priv->adds->len == 0)
 		return;
 
-	e_gdbus_book_view_emit_contacts_added (view->priv->gdbus_object, (const gchar * const *) priv->adds->data);
+	e_gdbus_book_view_emit_objects_added (view->priv->gdbus_object, (const gchar * const *) priv->adds->data);
 	reset_array (priv->adds);
 }
 
@@ -129,7 +168,7 @@ send_pending_changes (EDataBookView *view)
 	if (priv->changes->len == 0)
 		return;
 
-	e_gdbus_book_view_emit_contacts_changed (view->priv->gdbus_object, (const gchar * const *) priv->changes->data);
+	e_gdbus_book_view_emit_objects_modified (view->priv->gdbus_object, (const gchar * const *) priv->changes->data);
 	reset_array (priv->changes);
 }
 
@@ -141,7 +180,7 @@ send_pending_removes (EDataBookView *view)
 	if (priv->removes->len == 0)
 		return;
 
-	e_gdbus_book_view_emit_contacts_removed (view->priv->gdbus_object, (const gchar * const *) priv->removes->data);
+	e_gdbus_book_view_emit_objects_removed (view->priv->gdbus_object, (const gchar * const *) priv->removes->data);
 	reset_array (priv->removes);
 }
 
@@ -244,6 +283,37 @@ notify_add (EDataBookView *view, const gchar *id, const gchar *vcard)
 	ensure_pending_flush_timeout (view);
 }
 
+static gboolean
+impl_DataBookView_setFieldsOfInterest (EGdbusBookView *object, GDBusMethodInvocation *invocation, const gchar * const *in_fields_of_interest, EDataBookView *view)
+{
+	EDataBookViewPrivate *priv;
+	gint ii;
+
+	g_return_val_if_fail (in_fields_of_interest != NULL, TRUE);
+
+	priv = view->priv;
+
+	if (priv->fields_of_interest)
+		g_hash_table_destroy (priv->fields_of_interest);
+	priv->fields_of_interest = NULL;
+
+	for (ii = 0; in_fields_of_interest[ii]; ii++) {
+		const gchar *field = in_fields_of_interest[ii];
+
+		if (!*field)
+			continue;
+
+		if (!priv->fields_of_interest)
+			priv->fields_of_interest = g_hash_table_new_full (str_ic_hash, str_ic_equal, g_free, NULL);
+
+		g_hash_table_insert (priv->fields_of_interest, g_strdup (field), GINT_TO_POINTER (1));
+	}
+
+	e_gdbus_book_view_complete_set_fields_of_interest (object, invocation, NULL);
+
+	return TRUE;
+}
+
 static void
 reset_array (GArray *array)
 {
@@ -288,8 +358,7 @@ id_is_in_view (EDataBookView *book_view, const gchar *id)
  * by @book_view.
  **/
 void
-e_data_book_view_notify_update (EDataBookView *book_view,
-                                EContact      *contact)
+e_data_book_view_notify_update (EDataBookView *book_view, const EContact *contact)
 {
 	EDataBookViewPrivate *priv = book_view->priv;
 	gboolean currently_in_view, want_in_view;
@@ -301,11 +370,11 @@ e_data_book_view_notify_update (EDataBookView *book_view,
 
 	g_mutex_lock (priv->pending_mutex);
 
-	id = e_contact_get_const (contact, E_CONTACT_UID);
+	id = e_contact_get_const ((EContact *) contact, E_CONTACT_UID);
 
 	currently_in_view = id_is_in_view (book_view, id);
 	want_in_view =
-		e_book_backend_sexp_match_contact (priv->card_sexp, contact);
+		e_book_backend_sexp_match_contact (priv->card_sexp, (EContact *) contact);
 
 	if (want_in_view) {
 		vcard = e_vcard_to_string (E_VCARD (contact),
@@ -459,7 +528,7 @@ void
 e_data_book_view_notify_complete (EDataBookView *book_view, const GError *error)
 {
 	EDataBookViewPrivate *priv = book_view->priv;
-	gchar *gdbus_error_msg = NULL;
+	gchar **strv_error;
 
 	if (!priv->running)
 		return;
@@ -472,17 +541,15 @@ e_data_book_view_notify_complete (EDataBookView *book_view, const GError *error)
 
 	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... */
-
-	e_gdbus_book_view_emit_complete (priv->gdbus_object, error ? error->code : 0, e_util_ensure_gdbus_string (error ? error->message : "", &gdbus_error_msg));
-
-	g_free (gdbus_error_msg);
+	strv_error = e_gdbus_templates_encode_error (error);
+	e_gdbus_book_view_emit_complete (priv->gdbus_object, (const gchar * const *) strv_error);
+	g_strfreev (strv_error);
 }
 
 /**
- * e_data_book_view_notify_status_message:
+ * e_data_book_view_notify_progress:
  * @book_view: an #EDataBookView
+ * @percent: percent done; use -1 when not available
  * @message: a text message
  *
  * Provides listeners with a human-readable text describing the
@@ -490,7 +557,7 @@ e_data_book_view_notify_complete (EDataBookView *book_view, const GError *error)
  * reporting.
  **/
 void
-e_data_book_view_notify_status_message (EDataBookView *book_view, const gchar *message)
+e_data_book_view_notify_progress (EDataBookView *book_view, guint percent, const gchar *message)
 {
 	EDataBookViewPrivate *priv = book_view->priv;
 	gchar *gdbus_message = NULL;
@@ -498,7 +565,7 @@ e_data_book_view_notify_status_message (EDataBookView *book_view, const gchar *m
 	if (!priv->running)
 		return;
 
-	e_gdbus_book_view_emit_status_message (priv->gdbus_object, e_util_ensure_gdbus_string (message, &gdbus_message));
+	e_gdbus_book_view_emit_progress (priv->gdbus_object, percent, e_util_ensure_gdbus_string (message, &gdbus_message));
 
 	g_free (gdbus_message);
 }
@@ -508,13 +575,12 @@ e_data_book_view_notify_status_message (EDataBookView *book_view, const gchar *m
  * @book: The #EDataBook to search
  * @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 gchar *card_query, EBookBackendSExp *card_sexp, gint max_results)
+e_data_book_view_new (EDataBook *book, const gchar *card_query, EBookBackendSExp *card_sexp)
 {
 	EDataBookView *view;
 	EDataBookViewPrivate *priv;
@@ -528,7 +594,6 @@ e_data_book_view_new (EDataBook *book, const gchar *card_query, EBookBackendSExp
 	priv->backend = g_object_ref (e_data_book_get_backend (book));
 	priv->card_query = e_util_utf8_make_valid (card_query);
 	priv->card_sexp = card_sexp;
-	priv->max_results = max_results;
 
 	return view;
 }
@@ -551,7 +616,7 @@ impl_DataBookView_start (EGdbusBookView *object, GDBusMethodInvocation *invocati
 {
 	book_view->priv->idle_id = g_idle_add (bookview_idle_start, book_view);
 
-	e_gdbus_book_view_complete_start (object, invocation);
+	e_gdbus_book_view_complete_start (object, invocation, NULL);
 
 	return TRUE;
 }
@@ -577,7 +642,7 @@ impl_DataBookView_stop (EGdbusBookView *object, GDBusMethodInvocation *invocatio
 
 	book_view->priv->idle_id = g_idle_add (bookview_idle_stop, book_view);
 
-	e_gdbus_book_view_complete_stop (object, invocation);
+	e_gdbus_book_view_complete_stop (object, invocation, NULL);
 
 	return TRUE;
 }
@@ -585,7 +650,10 @@ impl_DataBookView_stop (EGdbusBookView *object, GDBusMethodInvocation *invocatio
 static gboolean
 impl_DataBookView_dispose (EGdbusBookView *object, GDBusMethodInvocation *invocation, EDataBookView *book_view)
 {
-	e_gdbus_book_view_complete_dispose (object, invocation);
+	e_gdbus_book_view_complete_dispose (object, invocation, NULL);
+
+	e_book_backend_stop_book_view (book_view->priv->backend, book_view);
+	book_view->priv->running = FALSE;
 
 	g_object_unref (book_view);
 
@@ -604,7 +672,9 @@ e_data_book_view_init (EDataBookView *book_view)
 	g_signal_connect (priv->gdbus_object, "handle-start", G_CALLBACK (impl_DataBookView_start), book_view);
 	g_signal_connect (priv->gdbus_object, "handle-stop", G_CALLBACK (impl_DataBookView_stop), book_view);
 	g_signal_connect (priv->gdbus_object, "handle-dispose", G_CALLBACK (impl_DataBookView_dispose), book_view);
+	g_signal_connect (priv->gdbus_object, "handle-set-fields-of-interest", G_CALLBACK (impl_DataBookView_setFieldsOfInterest), book_view);
 
+	priv->fields_of_interest = NULL;
 	priv->running = FALSE;
 	priv->pending_mutex = g_mutex_new ();
 
@@ -669,9 +739,11 @@ e_data_book_view_finalize (GObject *object)
 	g_array_free (priv->adds, TRUE);
 	g_array_free (priv->changes, TRUE);
 	g_array_free (priv->removes, TRUE);
-
 	g_free (priv->card_query);
 
+	if (priv->fields_of_interest)
+		g_hash_table_destroy (priv->fields_of_interest);
+
 	g_mutex_free (priv->pending_mutex);
 
 	g_hash_table_destroy (priv->ids);
@@ -679,16 +751,6 @@ e_data_book_view_finalize (GObject *object)
 	G_OBJECT_CLASS (e_data_book_view_parent_class)->finalize (object);
 }
 
-void
-e_data_book_view_set_thresholds (EDataBookView *book_view,
-                                 gint minimum_grouping_threshold,
-                                 gint maximum_grouping_threshold)
-{
-	g_return_if_fail (E_IS_DATA_BOOK_VIEW (book_view));
-
-	g_debug ("e_data_book_view_set_thresholds does nothing in eds-dbus");
-}
-
 /**
  * e_data_book_view_get_card_query:
  * @book_view: an #EDataBookView
@@ -724,36 +786,39 @@ e_data_book_view_get_card_sexp (EDataBookView *book_view)
 }
 
 /**
- * e_data_book_view_get_max_results:
+ * e_data_book_view_get_backend:
  * @book_view: an #EDataBookView
  *
- * Gets the maximum number of results returned by
- * @book_view's query.
+ * Gets the backend that @book_view is querying.
  *
- * Returns: The maximum number of results returned.
+ * Returns: The associated #EBookBackend.
  **/
-gint
-e_data_book_view_get_max_results (EDataBookView *book_view)
+EBookBackend*
+e_data_book_view_get_backend (EDataBookView *book_view)
 {
-	g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (book_view), 0);
+	g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (book_view), NULL);
 
-	return book_view->priv->max_results;
+	return book_view->priv->backend;
 }
 
 /**
- * e_data_book_view_get_backend:
- * @book_view: an #EDataBookView
+ * e_data_book_view_get_fields_of_interest:
+ * @view: A view object.
  *
- * Gets the backend that @book_view is querying.
+ * Returns: Hash table of field names which the listener is interested in.
+ * Backends can return fully populated objects, but the listener advertised
+ * that it will use only these. Returns %NULL for all available fields.
  *
- * Returns: The associated #EBookBackend.
+ * Note: The data pointer in the hash table has no special meaning, it's
+ * only GINT_TO_POINTER(1) for easier checking. Also, field names are
+ * compared case insensitively.
  **/
-EBookBackend*
-e_data_book_view_get_backend (EDataBookView *book_view)
+/* const */ GHashTable *
+e_data_book_view_get_fields_of_interest (EDataBookView *view)
 {
-	g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (book_view), NULL);
+	g_return_val_if_fail (E_IS_DATA_BOOK_VIEW (view), NULL);
 
-	return book_view->priv->backend;
+	return view->priv->fields_of_interest;
 }
 
 /**
diff --git a/addressbook/libedata-book/e-data-book-view.h b/addressbook/libedata-book/e-data-book-view.h
index 1f856b9..9a19aad 100644
--- a/addressbook/libedata-book/e-data-book-view.h
+++ b/addressbook/libedata-book/e-data-book-view.h
@@ -52,40 +52,25 @@ struct _EDataBookViewClass {
 	GObjectClass parent;
 };
 
-EDataBookView *e_data_book_view_new                  (EDataBook        *book,
-						      const gchar      *card_query,
-						      EBookBackendSExp *card_sexp,
-						      gint              max_results);
+GType			e_data_book_view_get_type		(void);
+EDataBookView *		e_data_book_view_new			(EDataBook *book, const gchar *card_query, EBookBackendSExp *card_sexp);
+guint			e_data_book_view_register_gdbus_object	(EDataBookView *query, GDBusConnection *connection, const gchar *object_path, GError **error);
 
-guint e_data_book_view_register_gdbus_object (EDataBookView *query, GDBusConnection *connection, const gchar *object_path, GError **error);
+const gchar *		e_data_book_view_get_card_query		(EDataBookView *book_view);
+EBookBackendSExp *	e_data_book_view_get_card_sexp		(EDataBookView *book_view);
+EBookBackend *		e_data_book_view_get_backend		(EDataBookView *book_view);
+void			e_data_book_view_notify_update		(EDataBookView *book_view, const EContact *contact);
 
-void              e_data_book_view_set_thresholds    (EDataBookView *book_view,
-						      gint minimum_grouping_threshold,
-						      gint maximum_grouping_threshold);
+void			e_data_book_view_notify_update_vcard	(EDataBookView *book_view, gchar *vcard);
+void			e_data_book_view_notify_update_prefiltered_vcard (EDataBookView *book_view, const gchar *id, gchar *vcard);
 
-const gchar *       e_data_book_view_get_card_query    (EDataBookView                *book_view);
-EBookBackendSExp* e_data_book_view_get_card_sexp     (EDataBookView                *book_view);
-gint               e_data_book_view_get_max_results   (EDataBookView                *book_view);
-EBookBackend*     e_data_book_view_get_backend       (EDataBookView                *book_view);
-void         e_data_book_view_notify_update          (EDataBookView                *book_view,
-						      EContact                     *contact);
+void			e_data_book_view_notify_remove		(EDataBookView *book_view, const gchar *id);
+void			e_data_book_view_notify_complete	(EDataBookView *book_view, const GError *error);
+void			e_data_book_view_notify_progress        (EDataBookView *book_view, guint percent, const gchar *message);
+void			e_data_book_view_ref			(EDataBookView *book_view);
+void			e_data_book_view_unref			(EDataBookView *book_view);
 
-void         e_data_book_view_notify_update_vcard    (EDataBookView                *book_view,
-						      gchar                         *vcard);
-void         e_data_book_view_notify_update_prefiltered_vcard (EDataBookView       *book_view,
-                                                               const gchar          *id,
-                                                               gchar                *vcard);
-
-void         e_data_book_view_notify_remove          (EDataBookView                *book_view,
-						      const gchar                   *id);
-void         e_data_book_view_notify_complete        (EDataBookView                *book_view,
-						      const GError                 *error);
-void         e_data_book_view_notify_status_message  (EDataBookView                *book_view,
-						      const gchar                   *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);
+/* const */ GHashTable *e_data_book_view_get_fields_of_interest	(EDataBookView *view);
 
 G_END_DECLS
 
diff --git a/addressbook/libedata-book/e-data-book.c b/addressbook/libedata-book/e-data-book.c
index 71a98c2..a4ce8d8 100644
--- a/addressbook/libedata-book/e-data-book.c
+++ b/addressbook/libedata-book/e-data-book.c
@@ -26,16 +26,17 @@
 #include <glib-object.h>
 #include <gio/gio.h>
 
-#include "libedataserver/e-data-server-util.h"
+#include <libedataserver/e-credentials.h>
+#include <libedataserver/e-data-server-util.h>
+#include <libedataserver/e-operation-pool.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-sexp.h"
-#include "opid.h"
 
-#include "e-gdbus-egdbusbook.h"
+#include "e-gdbus-book.h"
 
 G_DEFINE_TYPE (EDataBook, e_data_book, G_TYPE_OBJECT)
 
@@ -45,53 +46,87 @@ struct _EDataBookPrivate
 
 	EBookBackend *backend;
 	ESource *source;
-};
 
-static void return_error_and_list (EGdbusBook *gdbus_object, void (* complete_func) (EGdbusBook *object, GDBusMethodInvocation *invocation, const gchar * const *out_array), guint32 opid, GError *error, const gchar *error_fmt, GList *list, gboolean free_data);
-static void data_book_return_error (GDBusMethodInvocation *invocation, const GError *error, const gchar *error_fmt);
+	GStaticRecMutex pending_ops_lock;
+	GHashTable *pending_ops; /* opid to GCancellable for still running operations */
+};
 
-static GThreadPool *op_pool = NULL;
+static EOperationPool *ops_pool = NULL;
 
 typedef enum {
 	OP_OPEN,
-	OP_AUTHENTICATE,
-	OP_ADD_CONTACT,
+	OP_REMOVE,
+	OP_REFRESH,
 	OP_GET_CONTACT,
 	OP_GET_CONTACTS,
-	OP_MODIFY_CONTACT,
+	OP_AUTHENTICATE,
+	OP_ADD_CONTACT,
 	OP_REMOVE_CONTACTS,
-	OP_GET_CHANGES,
+	OP_MODIFY_CONTACT,
+	OP_GET_BACKEND_PROPERTY,
+	OP_SET_BACKEND_PROPERTY,
+	OP_GET_BOOK_VIEW,
+	OP_CANCEL_OPERATION,
+	OP_CANCEL_ALL,
+	OP_CLOSE
 } OperationID;
 
 typedef struct {
 	OperationID op;
 	guint32 id; /* operation id */
 	EDataBook *book; /* book */
+	GCancellable *cancellable;
+
 	union {
 		/* OP_OPEN */
 		gboolean only_if_exists;
+		/* OP_GET_CONTACT */
+		gchar *uid;
 		/* OP_AUTHENTICATE */
-		struct {
-			gchar *username;
-			gchar *password;
-			gchar *method;
-		} auth;
+		ECredentials *credentials;
+		/* OP_REMOVE_CONTACTS */
+		GSList *ids;
 		/* OP_ADD_CONTACT */
 		/* OP_MODIFY_CONTACT */
 		gchar *vcard;
-		/* OP_GET_CONTACT */
-		gchar *uid;
+		/* OP_GET_BOOK_VIEW */
 		/* OP_GET_CONTACTS */
 		gchar *query;
-		/* OP_MODIFY_CONTACT */
-		gchar **vcards;
-		/* OP_REMOVE_CONTACTS */
-		GList *ids;
-		/* OP_GET_CHANGES */
-		gchar *change_id;
+		/* OP_CANCEL_OPERATION */
+		guint opid;
+		/* OP_GET_BACKEND_PROPERTY */
+		gchar *prop_name;
+		/* OP_SET_BACKEND_PROPERTY */
+		struct _sbp {
+			gchar *prop_name;
+			gchar *prop_value;
+		} sbp;
+
+		/* OP_REMOVE */
+		/* OP_REFRESH */
+		/* OP_CANCEL_ALL */
+		/* OP_CLOSE */
 	} d;
 } OperationData;
 
+static gchar *
+construct_bookview_path (void)
+{
+	static volatile guint counter = 1;
+
+	return g_strdup_printf ("/org/gnome/evolution/dataserver/AddressBookView/%d/%d",
+				getpid (),
+				g_atomic_int_exchange_and_add ((int*)&counter, 1));
+}
+
+static void
+cancel_ops_cb (gpointer opid, gpointer cancellable, gpointer user_data)
+{
+	g_return_if_fail (cancellable != NULL);
+
+	g_cancellable_cancel (cancellable);
+}
+
 static void
 operation_thread (gpointer data, gpointer user_data)
 {
@@ -102,61 +137,145 @@ operation_thread (gpointer data, gpointer user_data)
 
 	switch (op->op) {
 	case OP_OPEN:
-		e_book_backend_open (backend, op->book, op->id, op->d.only_if_exists);
-		break;
-	case OP_AUTHENTICATE:
-		e_book_backend_authenticate_user (backend, op->book, op->id,
-						  op->d.auth.username,
-						  op->d.auth.password,
-						  op->d.auth.method);
-		g_free (op->d.auth.username);
-		g_free (op->d.auth.password);
-		g_free (op->d.auth.method);
+		e_book_backend_open (backend, op->book, op->id, op->cancellable, op->d.only_if_exists);
 		break;
 	case OP_ADD_CONTACT:
-		e_book_backend_create_contact (backend, op->book, op->id, op->d.vcard);
+		e_book_backend_create_contact (backend, op->book, op->id, op->cancellable, op->d.vcard);
 		g_free (op->d.vcard);
 		break;
 	case OP_GET_CONTACT:
-		e_book_backend_get_contact (backend, op->book, op->id, op->d.uid);
+		e_book_backend_get_contact (backend, op->book, op->id, op->cancellable, op->d.uid);
 		g_free (op->d.uid);
 		break;
 	case OP_GET_CONTACTS:
-		e_book_backend_get_contact_list (backend, op->book, op->id, op->d.query);
+		e_book_backend_get_contact_list (backend, op->book, op->id, op->cancellable, op->d.query);
 		g_free (op->d.query);
 		break;
 	case OP_MODIFY_CONTACT:
-		e_book_backend_modify_contact (backend, op->book, op->id, op->d.vcard);
+		e_book_backend_modify_contact (backend, op->book, op->id, op->cancellable, op->d.vcard);
 		g_free (op->d.vcard);
 		break;
 	case OP_REMOVE_CONTACTS:
-		e_book_backend_remove_contacts (backend, op->book, op->id, op->d.ids);
-		g_list_foreach (op->d.ids, (GFunc) g_free, NULL);
-		g_list_free (op->d.ids);
+		e_book_backend_remove_contacts (backend, op->book, op->id, op->cancellable, op->d.ids);
+		g_slist_foreach (op->d.ids, (GFunc) g_free, NULL);
+		g_slist_free (op->d.ids);
+		break;
+	case OP_REMOVE:
+		e_book_backend_remove (backend, op->book, op->id, op->cancellable);
+		break;
+	case OP_REFRESH:
+		e_book_backend_refresh (backend, op->book, op->id, op->cancellable);
 		break;
-	case OP_GET_CHANGES:
-		e_book_backend_get_changes (backend, op->book, op->id, op->d.change_id);
-		g_free (op->d.change_id);
+	case OP_GET_BACKEND_PROPERTY:
+		e_book_backend_get_backend_property (backend, op->book, op->id, op->cancellable, op->d.prop_name);
+		g_free (op->d.prop_name);
+		break;
+	case OP_SET_BACKEND_PROPERTY:
+		e_book_backend_set_backend_property (backend, op->book, op->id, op->cancellable, op->d.sbp.prop_name, op->d.sbp.prop_value);
+		g_free (op->d.sbp.prop_name);
+		g_free (op->d.sbp.prop_value);
+		break;
+	case OP_GET_BOOK_VIEW:
+		if (op->d.query) {
+			EBookBackendSExp *card_sexp;
+			EDataBookView *book_view;
+			gchar *path;
+			GError *error = NULL;
+
+			card_sexp = e_book_backend_sexp_new (op->d.query);
+			if (!card_sexp) {
+				error = e_data_book_create_error (E_DATA_BOOK_STATUS_INVALID_QUERY, NULL);
+				/* Translators: This is prefix to a detailed error message */
+				g_prefix_error (&error, "%s", _("Invalid query: "));
+				e_gdbus_book_emit_get_view_done (op->book->priv->gdbus_object, op->id, error, NULL);
+				g_error_free (error);
+				break;
+			}
+
+			path = construct_bookview_path ();
+			
+			book_view = e_data_book_view_new (op->book, op->d.query, card_sexp);
+			e_data_book_view_register_gdbus_object (book_view, e_gdbus_book_stub_get_connection (op->book->priv->gdbus_object), path, &error);
+
+			if (error) {
+				/* Translators: This is prefix to a detailed error message */
+				g_prefix_error (&error, "%s", _("Invalid query: "));
+				e_gdbus_book_emit_get_view_done (op->book->priv->gdbus_object, op->id, error, NULL);
+				g_error_free (error);
+				g_object_unref (book_view);
+				g_free (path);
+
+				break;
+			}
+
+			e_book_backend_add_book_view (backend, book_view);
+
+			e_gdbus_book_emit_get_view_done (op->book->priv->gdbus_object, op->id, NULL, path);
+
+			g_free (path);
+		}
+		g_free (op->d.query);
+		break;
+	case OP_AUTHENTICATE:
+		e_book_backend_authenticate_user (backend, op->cancellable, op->d.credentials);
+		e_credentials_free (op->d.credentials);
+		break;
+	case OP_CANCEL_OPERATION:
+		g_static_rec_mutex_lock (&op->book->priv->pending_ops_lock);
+
+		if (g_hash_table_lookup (op->book->priv->pending_ops, GUINT_TO_POINTER (op->d.opid))) {
+			GCancellable *cancellable = g_hash_table_lookup (op->book->priv->pending_ops, GUINT_TO_POINTER (op->d.opid));
+
+			g_cancellable_cancel (cancellable);
+		}
+
+		g_static_rec_mutex_unlock (&op->book->priv->pending_ops_lock);
+		break;
+	case OP_CLOSE:
+		/* close just cancels all pending ops and frees data book */
+		e_book_backend_remove_client (backend, op->book);
+	case OP_CANCEL_ALL:
+		g_static_rec_mutex_lock (&op->book->priv->pending_ops_lock);
+		g_hash_table_foreach (op->book->priv->pending_ops, cancel_ops_cb, NULL);
+		g_static_rec_mutex_unlock (&op->book->priv->pending_ops_lock);
 		break;
 	}
 
 	g_object_unref (op->book);
+	g_object_unref (op->cancellable);
 	g_slice_free (OperationData, op);
 }
 
 static OperationData *
-op_new (OperationID op, EDataBook *book, GDBusMethodInvocation *invocation)
+op_new (OperationID op, EDataBook *book)
 {
 	OperationData *data;
 
 	data = g_slice_new0 (OperationData);
 	data->op = op;
 	data->book = g_object_ref (book);
-	data->id = opid_store (invocation);
+	data->id = e_operation_pool_reserve_opid (ops_pool);
+	data->cancellable = g_cancellable_new ();
+
+	g_static_rec_mutex_lock (&book->priv->pending_ops_lock);
+	g_hash_table_insert (book->priv->pending_ops, GUINT_TO_POINTER (data->id), g_object_ref (data->cancellable));
+	g_static_rec_mutex_unlock (&book->priv->pending_ops_lock);
 
 	return data;
 }
 
+static void
+op_complete (EDataBook *book, guint32 opid)
+{
+	g_return_if_fail (book != NULL);
+
+	e_operation_pool_release_opid (ops_pool, opid);
+
+	g_static_rec_mutex_lock (&book->priv->pending_ops_lock);
+	g_hash_table_remove (book->priv->pending_ops, GUINT_TO_POINTER (opid));
+	g_static_rec_mutex_unlock (&book->priv->pending_ops_lock);
+}
+
 /**
  * e_data_book_status_to_string:
  *
@@ -171,6 +290,7 @@ e_data_book_status_to_string (EDataBookStatus status)
 		const gchar *msg;
 	} statuses[] = {
 		{ E_DATA_BOOK_STATUS_SUCCESS,				N_("Success") },
+		{ E_DATA_BOOK_STATUS_BUSY,				N_("Backend is busy") },
 		{ E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE,		N_("Repository offline") },
 		{ E_DATA_BOOK_STATUS_PERMISSION_DENIED,			N_("Permission denied") },
 		{ E_DATA_BOOK_STATUS_CONTACT_NOT_FOUND,			N_("Contact not found") },
@@ -212,6 +332,7 @@ e_data_book_error_quark (void)
 
 	static const GDBusErrorEntry entries[] = {
 		{ E_DATA_BOOK_STATUS_SUCCESS,				ERR_PREFIX "Success" },
+		{ E_DATA_BOOK_STATUS_BUSY,				ERR_PREFIX "Busy" },
 		{ E_DATA_BOOK_STATUS_REPOSITORY_OFFLINE,		ERR_PREFIX "RepositoryOffline" },
 		{ E_DATA_BOOK_STATUS_PERMISSION_DENIED,			ERR_PREFIX "PermissionDenied" },
 		{ E_DATA_BOOK_STATUS_CONTACT_NOT_FOUND,			ERR_PREFIX "ContactNotFound" },
@@ -303,527 +424,572 @@ e_data_book_get_backend (EDataBook *book)
 	return book->priv->backend;
 }
 
-static gboolean
-impl_Book_open (EGdbusBook *object, GDBusMethodInvocation *invocation, gboolean only_if_exists, EDataBook *book)
+static void
+data_book_return_error (GDBusMethodInvocation *invocation, const GError *perror, const gchar *error_prefix)
 {
-	OperationData *op;
+	GError *error;
 
-	op = op_new (OP_OPEN, book, invocation);
-	op->d.only_if_exists = only_if_exists;
-	g_thread_pool_push (op_pool, op, NULL);
+	if (perror == NULL)
+		error = g_error_new (E_DATA_BOOK_ERROR, E_DATA_BOOK_STATUS_OTHER_ERROR, "%s", _("Unknown error"));
+	else
+		error = g_error_new (E_DATA_BOOK_ERROR, perror->code, "%s", perror->message);
 
-	return TRUE;
+	g_prefix_error (&error, "%s", error_prefix);
+
+	g_dbus_method_invocation_return_gerror (invocation, error);
+
+	g_error_free (error);
 }
 
-void
-e_data_book_respond_open (EDataBook *book, guint opid, GError *error)
+/* takes a list of strings and converts it to a comma-separated string of values;
+   free returned pointer with g_free() */
+gchar *
+e_data_book_string_slist_to_comma_string (const GSList *strings)
 {
-	GDBusMethodInvocation *invocation = opid_fetch (opid);
+	GString *tmp;
+	gchar *res;
+	const GSList *l;
 
-	if (error) {
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_book_return_error (invocation, error, _("Cannot open book: %s"));
-		g_error_free (error);
-	} else {
-		e_gdbus_book_complete_open (book->priv->gdbus_object, invocation);
+	tmp = g_string_new ("");
+	for (l = strings; l != NULL; l = l->next) {
+		const gchar *str = l->data;
+
+		if (!str)
+			continue;
+
+		if (strchr (str, ',')) {
+			g_warning ("%s: String cannot contain comma; skipping value '%s'\n", G_STRFUNC, str);
+			continue;
+		}
+
+		if (tmp->len)
+			g_string_append_c (tmp, ',');
+		g_string_append (tmp, str);
 	}
+
+	res = e_util_utf8_make_valid (tmp->str);
+
+	g_string_free (tmp, TRUE);
+
+	return res;
+}
+
+static gboolean
+impl_Book_open (EGdbusBook *object, GDBusMethodInvocation *invocation, gboolean only_if_exists, EDataBook *book)
+{
+	OperationData *op;
+
+	op = op_new (OP_OPEN, book);
+	op->d.only_if_exists = only_if_exists;
+
+	e_gdbus_book_complete_open (book->priv->gdbus_object, invocation, op->id);
+	e_operation_pool_push (ops_pool, op);
+
+	return TRUE;
 }
 
 static gboolean
 impl_Book_remove (EGdbusBook *object, GDBusMethodInvocation *invocation, EDataBook *book)
 {
-	e_book_backend_remove (book->priv->backend, book, opid_store (invocation));
+	OperationData *op;
+
+	op = op_new (OP_REMOVE, book);
+
+	e_gdbus_book_complete_remove (book->priv->gdbus_object, invocation, op->id);
+	e_operation_pool_push (ops_pool, op);
 
 	return TRUE;
 }
 
-void
-e_data_book_respond_remove (EDataBook *book, guint opid, GError *error)
+static gboolean
+impl_Book_refresh (EGdbusBook *object, GDBusMethodInvocation *invocation, EDataBook *book)
 {
-	GDBusMethodInvocation *invocation = opid_fetch (opid);
+	OperationData *op;
 
-	if (error) {
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_book_return_error (invocation, error, _("Cannot remove book: %s"));
-		g_error_free (error);
-	} else {
-		e_gdbus_book_complete_remove (book->priv->gdbus_object, invocation);
-	}
+	op = op_new (OP_REFRESH, book);
+
+	e_gdbus_book_complete_refresh (book->priv->gdbus_object, invocation, op->id);
+	e_operation_pool_push (ops_pool, op);
+
+	return TRUE;
 }
 
 static gboolean
-impl_Book_getContact (EGdbusBook *object, GDBusMethodInvocation *invocation, const gchar *IN_uid, EDataBook *book)
+impl_Book_getContact (EGdbusBook *object, GDBusMethodInvocation *invocation, const gchar *in_uid, EDataBook *book)
 {
 	OperationData *op;
 
-	if (IN_uid == NULL) {
+	if (in_uid == NULL) {
 		GError *error;
 
 		error = e_data_book_create_error (E_DATA_BOOK_STATUS_CONTACT_NOT_FOUND, NULL);
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_book_return_error (invocation, error, _("Cannot get contact: %s"));
+		/* Translators: This is prefix to a detailed error message */
+		data_book_return_error (invocation, error, _("Cannot get contact: "));
 		g_error_free (error);
 		return TRUE;
 	}
 
-	op = op_new (OP_GET_CONTACT, book, invocation);
-	op->d.uid = g_strdup (IN_uid);
-	g_thread_pool_push (op_pool, op, NULL);
+	op = op_new (OP_GET_CONTACT, book);
+	op->d.uid = g_strdup (in_uid);
+
+	e_gdbus_book_complete_get_contact (book->priv->gdbus_object, invocation, op->id);
+	e_operation_pool_push (ops_pool, op);
 
 	return TRUE;
 }
 
-void
-e_data_book_respond_get_contact (EDataBook *book, guint32 opid, GError *error, const gchar *vcard)
+static gboolean
+impl_Book_getContactList (EGdbusBook *object, GDBusMethodInvocation *invocation, const gchar *in_query, EDataBook *book)
 {
-	GDBusMethodInvocation *invocation = opid_fetch (opid);
+	OperationData *op;
 
-	if (error) {
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_book_return_error  (invocation, error, _("Cannot get contact: %s"));
+	if (in_query == NULL || !*in_query) {
+		GError *error = e_data_book_create_error (E_DATA_BOOK_STATUS_INVALID_QUERY, NULL);
+		/* Translators: This is prefix to a detailed error message */
+		data_book_return_error (invocation, error, _("Empty query: "));
 		g_error_free (error);
-	} else {
-		gchar *gdbus_vcard = NULL;
+		return TRUE;
+	}
 
-		e_gdbus_book_complete_get_contact (book->priv->gdbus_object, invocation, e_util_ensure_gdbus_string (vcard, &gdbus_vcard));
+	op = op_new (OP_GET_CONTACTS, book);
+	op->d.query = g_strdup (in_query);
 
-		g_free (gdbus_vcard);
-	}
+	e_gdbus_book_complete_get_contact_list (book->priv->gdbus_object, invocation, op->id);
+	e_operation_pool_push (ops_pool, op);
+
+	return TRUE;
 }
 
 static gboolean
-impl_Book_getContactList (EGdbusBook *object, GDBusMethodInvocation *invocation, const gchar *query, EDataBook *book)
+impl_Book_addContact (EGdbusBook *object, GDBusMethodInvocation *invocation, const gchar *in_vcard, EDataBook *book)
 {
 	OperationData *op;
 
-	if (query == NULL || query[0] == '\0') {
+	if (in_vcard == NULL || !*in_vcard) {
 		GError *error = e_data_book_create_error (E_DATA_BOOK_STATUS_INVALID_QUERY, NULL);
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_book_return_error (invocation, error, _("Empty query: %s"));
+		/* Translators: This is prefix to a detailed error message */
+		data_book_return_error (invocation, error, _("Cannot add contact: "));
 		g_error_free (error);
 		return TRUE;
 	}
 
-	op = op_new (OP_GET_CONTACTS, book, invocation);
-	op->d.query = g_strdup (query);
-	g_thread_pool_push (op_pool, op, NULL);
+	op = op_new (OP_ADD_CONTACT, book);
+	op->d.vcard = g_strdup (in_vcard);
 
-	return TRUE;
-}
+	e_gdbus_book_complete_add_contact (book->priv->gdbus_object, invocation, op->id);
+	e_operation_pool_push (ops_pool, op);
 
-void
-e_data_book_respond_get_contact_list (EDataBook *book, guint32 opid, GError *error, GList *cards)
-{
-	/* Translators: The '%s' is replaced with a detailed error message */
-	return_error_and_list (book->priv->gdbus_object, e_gdbus_book_complete_get_contact_list, opid, error, _("Cannot get contact list: %s"), cards, TRUE);
+	return TRUE;
 }
 
 static gboolean
-impl_Book_authenticateUser (EGdbusBook *object, GDBusMethodInvocation *invocation, const gchar *IN_user, const gchar *IN_passwd, const gchar *IN_auth_method, EDataBook *book)
+impl_Book_modifyContact (EGdbusBook *object, GDBusMethodInvocation *invocation, const gchar *in_vcard, EDataBook *book)
 {
 	OperationData *op;
 
-	op = op_new (OP_AUTHENTICATE, book, invocation);
-	op->d.auth.username = g_strdup (IN_user);
-	op->d.auth.password = g_strdup (IN_passwd);
-	op->d.auth.method = g_strdup (IN_auth_method);
-	g_thread_pool_push (op_pool, op, NULL);
+	if (in_vcard == NULL) {
+		GError *error = e_data_book_create_error (E_DATA_BOOK_STATUS_INVALID_QUERY, NULL);
+		/* Translators: This is prefix to a detailed error message */
+		data_book_return_error (invocation, error, _("Cannot modify contact: "));
+		g_error_free (error);
+		return TRUE;
+	}
+
+	op = op_new (OP_MODIFY_CONTACT, book);
+	op->d.vcard = g_strdup (in_vcard);
+
+	e_gdbus_book_complete_modify_contact (book->priv->gdbus_object, invocation, op->id);
+	e_operation_pool_push (ops_pool, op);
 
 	return TRUE;
 }
 
-static void
-data_book_return_error (GDBusMethodInvocation *invocation, const GError *perror, const gchar *error_fmt)
+static gboolean
+impl_Book_removeContacts (EGdbusBook *object, GDBusMethodInvocation *invocation, const gchar * const *in_uids, EDataBook *book)
 {
-	GError *error;
-
-	if (perror == NULL)
-		error = g_error_new (E_DATA_BOOK_ERROR, E_DATA_BOOK_STATUS_OTHER_ERROR, error_fmt, _("Unknown error"));
-	else
-		error = g_error_new (E_DATA_BOOK_ERROR, perror->code, error_fmt, perror->message);
+	OperationData *op;
 
-	g_dbus_method_invocation_return_gerror (invocation, error);
+	op = op_new (OP_REMOVE_CONTACTS, book);
 
-	g_error_free (error);
-}
+	/* Allow an empty array to be removed */
+	for (; in_uids && *in_uids; in_uids++) {
+		op->d.ids = g_slist_prepend (op->d.ids, g_strdup (*in_uids));
+	}
 
-void
-e_data_book_respond_authenticate_user (EDataBook *book, guint32 opid, GError *error)
-{
-	GDBusMethodInvocation *invocation = opid_fetch (opid);
+	e_gdbus_book_complete_remove_contacts (book->priv->gdbus_object, invocation, op->id);
+	e_operation_pool_push (ops_pool, op);
 
-	if (error) {
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_book_return_error (invocation, error, _("Cannot authenticate user: %s"));
-		g_error_free (error);
-	} else {
-		e_gdbus_book_complete_authenticate_user (book->priv->gdbus_object, invocation);
-	}
+	return TRUE;
 }
 
 static gboolean
-impl_Book_addContact (EGdbusBook *object, GDBusMethodInvocation *invocation, const gchar *IN_vcard, EDataBook *book)
+impl_Book_getBackendProperty (EGdbusBook *object, GDBusMethodInvocation *invocation, const gchar *in_prop_name, EDataBook *book)
 {
 	OperationData *op;
 
-	if (IN_vcard == NULL || IN_vcard[0] == '\0') {
-		GError *error = e_data_book_create_error (E_DATA_BOOK_STATUS_INVALID_QUERY, NULL);
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_book_return_error (invocation, error, _("Cannot add contact: %s"));
-		g_error_free (error);
-		return TRUE;
-	}
+	op = op_new (OP_GET_BACKEND_PROPERTY, book);
+	op->d.prop_name = g_strdup (in_prop_name);
 
-	op = op_new (OP_ADD_CONTACT, book, invocation);
-	op->d.vcard = g_strdup (IN_vcard);
-	g_thread_pool_push (op_pool, op, NULL);
+	e_gdbus_book_complete_get_backend_property (book->priv->gdbus_object, invocation, op->id);
+	e_operation_pool_push (ops_pool, op);
 
 	return TRUE;
 }
 
-void
-e_data_book_respond_create (EDataBook *book, guint32 opid, GError *error, EContact *contact)
+static gboolean
+impl_Book_setBackendProperty (EGdbusBook *object, GDBusMethodInvocation *invocation, const gchar * const *in_prop_name_value, EDataBook *book)
 {
-	GDBusMethodInvocation *invocation = opid_fetch (opid);
-
-	if (error) {
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_book_return_error (invocation, error, _("Cannot add contact: %s"));
-		g_error_free (error);
-	} else {
-		gchar *gdbus_uid = NULL;
+	OperationData *op;
 
-		e_book_backend_notify_update (e_data_book_get_backend (book), contact);
-		e_book_backend_notify_complete (e_data_book_get_backend (book));
+	op = op_new (OP_SET_BACKEND_PROPERTY, book);
+	g_return_val_if_fail (e_gdbus_book_decode_set_backend_property (in_prop_name_value, &op->d.sbp.prop_name, &op->d.sbp.prop_value), FALSE);
 
-		e_gdbus_book_complete_add_contact (book->priv->gdbus_object, invocation, e_util_ensure_gdbus_string (e_contact_get_const (contact, E_CONTACT_UID), &gdbus_uid));
+	e_gdbus_book_complete_set_backend_property (book->priv->gdbus_object, invocation, op->id);
+	e_operation_pool_push (ops_pool, op);
 
-		g_free (gdbus_uid);
-	}
+	return TRUE;
 }
 
 static gboolean
-impl_Book_modifyContact (EGdbusBook *object, GDBusMethodInvocation *invocation, const gchar *IN_vcard, EDataBook *book)
+impl_Book_getBookView (EGdbusBook *object, GDBusMethodInvocation *invocation, const gchar *in_query, EDataBook *book)
 {
 	OperationData *op;
 
-	if (IN_vcard == NULL) {
-		GError *error = e_data_book_create_error (E_DATA_BOOK_STATUS_INVALID_QUERY, NULL);
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_book_return_error (invocation, error, _("Cannot modify contact: %s"));
+	if (!in_query || !*in_query) {
+		GError *error;
+
+		error = e_data_book_create_error (E_DATA_BOOK_STATUS_INVALID_QUERY, NULL);
+		/* Translators: This is prefix to a detailed error message */
+		data_book_return_error (invocation, error, _("Invalid query: "));
 		g_error_free (error);
+
 		return TRUE;
 	}
 
-	op = op_new (OP_MODIFY_CONTACT, book, invocation);
-	op->d.vcard = g_strdup (IN_vcard);
-	g_thread_pool_push (op_pool, op, NULL);
+	op = op_new (OP_GET_BOOK_VIEW, book);
+	op->d.query = g_strdup (in_query);
 
-	return TRUE;
-}
-
-void
-e_data_book_respond_modify (EDataBook *book, guint32 opid, GError *error, EContact *contact)
-{
-	GDBusMethodInvocation *invocation = opid_fetch (opid);
-
-	if (error) {
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_book_return_error (invocation, error, _("Cannot modify contact: %s"));
-		g_error_free (error);
-	} else {
-		e_book_backend_notify_update (e_data_book_get_backend (book), contact);
-		e_book_backend_notify_complete (e_data_book_get_backend (book));
+	e_gdbus_book_complete_get_view (book->priv->gdbus_object, invocation, op->id);
+	e_operation_pool_push (ops_pool, op);
 
-		e_gdbus_book_complete_modify_contact (book->priv->gdbus_object, invocation);
-	}
+	return TRUE;
 }
 
 static gboolean
-impl_Book_removeContacts (EGdbusBook *object, GDBusMethodInvocation *invocation, const gchar * const *IN_uids, EDataBook *book)
+impl_Book_authenticateUser (EGdbusBook *object, GDBusMethodInvocation *invocation, const gchar * const *in_credentials, EDataBook *book)
 {
 	OperationData *op;
 
-	/* Allow an empty array to be removed */
-	if (IN_uids == NULL) {
-		e_gdbus_book_complete_remove_contacts (object, invocation);
+	if (in_credentials == NULL) {
+		GError *error = e_data_book_create_error (E_DATA_BOOK_STATUS_INVALID_ARG, NULL);
+		/* Translators: This is prefix to a detailed error message */
+		data_book_return_error (invocation, error, _("Cannot authenticate user: "));
+		g_error_free (error);
 		return TRUE;
 	}
 
-	op = op_new (OP_REMOVE_CONTACTS, book, invocation);
+	op = op_new (OP_AUTHENTICATE, book);
+	op->d.credentials = e_credentials_new_strv (in_credentials);
 
-	for (; *IN_uids; IN_uids++) {
-		op->d.ids = g_list_prepend (op->d.ids, g_strdup (*IN_uids));
-	}
-
-	g_thread_pool_push (op_pool, op, NULL);
+	e_gdbus_book_complete_authenticate_user (book->priv->gdbus_object, invocation, NULL);
+	e_operation_pool_push (ops_pool, op);
 
 	return TRUE;
 }
 
-void
-e_data_book_respond_remove_contacts (EDataBook *book, guint32 opid, GError *error, GList *ids)
+static gboolean
+impl_Book_cancelOperation (EGdbusBook *object, GDBusMethodInvocation *invocation, guint in_opid, EDataBook *book)
 {
-	GDBusMethodInvocation *invocation = opid_fetch (opid);
+	OperationData *op;
 
-	if (error) {
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_book_return_error (invocation, error, _("Cannot remove contacts: %s"));
-		g_error_free (error);
-	} else {
-		GList *i;
+	op = op_new (OP_CANCEL_OPERATION, book);
+	op->d.opid = in_opid;
 
-		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));
+	e_gdbus_book_complete_cancel_operation (book->priv->gdbus_object, invocation, NULL);
+	e_operation_pool_push (ops_pool, op);
 
-		e_gdbus_book_complete_remove_contacts (book->priv->gdbus_object, invocation);
-	}
+	return TRUE;
 }
 
 static gboolean
-impl_Book_getStaticCapabilities (EGdbusBook *object, GDBusMethodInvocation *invocation, EDataBook *book)
+impl_Book_cancelAll (EGdbusBook *object, GDBusMethodInvocation *invocation, EDataBook *book)
 {
-	gchar *capabilities = e_book_backend_get_static_capabilities (e_data_book_get_backend (book));
-	gchar *gdbus_capabilities = NULL;
+	OperationData *op;
 
-	e_gdbus_book_complete_get_static_capabilities (object, invocation, e_util_ensure_gdbus_string (capabilities, &gdbus_capabilities));
+	op = op_new (OP_CANCEL_ALL, book);
 
-	g_free (capabilities);
-	g_free (gdbus_capabilities);
+	e_gdbus_book_complete_cancel_all (book->priv->gdbus_object, invocation, NULL);
+	e_operation_pool_push (ops_pool, op);
 
 	return TRUE;
 }
 
 static gboolean
-impl_Book_getSupportedFields (EGdbusBook *object, GDBusMethodInvocation *invocation, EDataBook *book)
+impl_Book_close (EGdbusBook *object, GDBusMethodInvocation *invocation, EDataBook *book)
 {
-	e_book_backend_get_supported_fields (e_data_book_get_backend (book), book, opid_store (invocation));
+	OperationData *op;
+
+	op = op_new (OP_CLOSE, book);
+
+	e_gdbus_book_complete_close (book->priv->gdbus_object, invocation, NULL);
+	e_operation_pool_push (ops_pool, op);
+
+	g_object_unref (book);
 
 	return TRUE;
 }
 
 void
-e_data_book_respond_get_supported_fields (EDataBook *book, guint32 opid, GError *error, GList *fields)
+e_data_book_respond_open (EDataBook *book, guint opid, GError *error)
 {
-	/* Translators: The '%s' is replaced with a detailed error message */
-	return_error_and_list (book->priv->gdbus_object, e_gdbus_book_complete_get_supported_fields, opid, error, _("Cannot get supported fields: %s"), fields, FALSE);
-}
+	op_complete (book, opid);
 
-static gboolean
-impl_Book_getRequiredFields (EGdbusBook *object, GDBusMethodInvocation *invocation, EDataBook *book)
-{
-	e_book_backend_get_required_fields (e_data_book_get_backend (book), book, opid_store (invocation));
+	/* Translators: This is prefix to a detailed error message */
+	g_prefix_error (&error, "%s", _("Cannot open book: "));
 
-	return TRUE;
+	e_gdbus_book_emit_open_done (book->priv->gdbus_object, opid, error);
+
+	if (error)
+		g_error_free (error);
 }
 
 void
-e_data_book_respond_get_required_fields (EDataBook *book, guint32 opid, GError *error, GList *fields)
+e_data_book_respond_remove (EDataBook *book, guint opid, GError *error)
 {
-	/* Translators: The '%s' is replaced with a detailed error message */
-	return_error_and_list (book->priv->gdbus_object, e_gdbus_book_complete_get_required_fields, opid, error, _("Cannot get required fields: %s"), fields, FALSE);
-}
+	op_complete (book, opid);
 
-static gboolean
-impl_Book_getSupportedAuthMethods (EGdbusBook *object, GDBusMethodInvocation *invocation, EDataBook *book)
-{
-	e_book_backend_get_supported_auth_methods (e_data_book_get_backend (book), book, opid_store (invocation));
+	/* Translators: This is prefix to a detailed error message */
+	g_prefix_error (&error, "%s", _("Cannot remove book: "));
 
-	return TRUE;
+	e_gdbus_book_emit_remove_done (book->priv->gdbus_object, opid, error);
+
+	if (error)
+		g_error_free (error);
+	else
+		e_book_backend_set_is_removed (book->priv->backend, TRUE);
 }
 
+/**
+ * e_data_book_respond_refresh:
+ * @book: An addressbook client interface.
+ * @error: Operation error, if any, automatically freed if passed it.
+ *
+ * Notifies listeners of the completion of the refresh method call.
+ *
+ * Since: 3.2
+ */
 void
-e_data_book_respond_get_supported_auth_methods (EDataBook *book, guint32 opid, GError *error, GList *auth_methods)
+e_data_book_respond_refresh (EDataBook *book, guint32 opid, GError *error)
 {
-	/* Translators: The '%s' is replaced with a detailed error message */
-	return_error_and_list (book->priv->gdbus_object, e_gdbus_book_complete_get_supported_auth_methods, opid, error, _("Cannot get supported authentication methods: %s"), auth_methods, FALSE);
-}
+	op_complete (book, opid);
 
-static gchar *
-construct_bookview_path (void)
-{
-	static volatile guint counter = 1;
+	/* Translators: This is prefix to a detailed error message */
+	g_prefix_error (&error, "%s", _("Cannot refresh address book: "));
 
-	return g_strdup_printf ("/org/gnome/evolution/dataserver/AddressBookView/%d/%d",
-				getpid (),
-				g_atomic_int_exchange_and_add ((int*)&counter, 1));
+	e_gdbus_book_emit_refresh_done (book->priv->gdbus_object, opid, error);
+
+	if (error)
+		g_error_free (error);
 }
 
-static gboolean
-impl_Book_getBookView (EGdbusBook *object, GDBusMethodInvocation *invocation, const gchar *search, const guint max_results, EDataBook *book)
+void
+e_data_book_respond_get_backend_property (EDataBook *book, guint32 opid, GError *error, const gchar *prop_value)
 {
-	EBookBackend *backend = e_data_book_get_backend (book);
-	EBookBackendSExp *card_sexp;
-	EDataBookView *book_view;
-	gchar *path;
-	GError *error = NULL;
+	gchar *gdbus_prop_value = NULL;
 
-	card_sexp = e_book_backend_sexp_new (search);
-	if (!card_sexp) {
-		error = e_data_book_create_error (E_DATA_BOOK_STATUS_INVALID_QUERY, NULL);
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_book_return_error (invocation, error, _("Invalid query: %s"));
-		g_error_free (error);
-		return TRUE;
-	}
+	op_complete (book, opid);
 
-	path = construct_bookview_path ();
-	book_view = e_data_book_view_new (book, search, card_sexp, max_results);
-	e_data_book_view_register_gdbus_object (book_view, g_dbus_method_invocation_get_connection (invocation), path, &error);
+	/* Translators: This is prefix to a detailed error message */
+	g_prefix_error (&error, "%s", _("Cannot get backend property: "));
 
-	if (error) {
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_book_return_error (invocation, error, _("Invalid query: %s"));
+	e_gdbus_book_emit_get_backend_property_done (book->priv->gdbus_object, opid, error, e_util_ensure_gdbus_string (prop_value, &gdbus_prop_value));
+
+	if (error)
 		g_error_free (error);
-		g_object_unref (book_view);
-		g_free (path);
 
-		return TRUE;
-	}
+	g_free (gdbus_prop_value);
+}
 
-	e_book_backend_add_book_view (backend, book_view);
+void
+e_data_book_respond_set_backend_property (EDataBook *book, guint32 opid, GError *error)
+{
+	op_complete (book, opid);
 
-	e_gdbus_book_complete_get_book_view (object, invocation, path);
+	/* Translators: This is prefix to a detailed error message */
+	g_prefix_error (&error, "%s", _("Cannot set backend property: "));
 
-	g_free (path);
+	e_gdbus_book_emit_set_backend_property_done (book->priv->gdbus_object, opid, error);
 
-	return TRUE;
+	if (error)
+		g_error_free (error);
 }
 
-static gboolean
-impl_Book_getChanges (EGdbusBook *object, GDBusMethodInvocation *invocation, const gchar *IN_change_id, EDataBook *book)
+void
+e_data_book_respond_get_contact (EDataBook *book, guint32 opid, GError *error, const gchar *vcard)
 {
-	OperationData *op;
+	gchar *gdbus_vcard = NULL;
 
-	op = op_new (OP_GET_CHANGES, book, invocation);
-	op->d.change_id = g_strdup (IN_change_id);
-	g_thread_pool_push (op_pool, op, NULL);
+	op_complete (book, opid);
 
-	return TRUE;
+	/* Translators: This is prefix to a detailed error message */
+	g_prefix_error (&error, "%s", _("Cannot get contact: "));
+
+	e_gdbus_book_emit_get_contact_done (book->priv->gdbus_object, opid, error, e_util_ensure_gdbus_string (vcard, &gdbus_vcard));
+
+	if (error)
+		g_error_free (error);
+
+	g_free (gdbus_vcard);
 }
 
 void
-e_data_book_respond_get_changes (EDataBook *book, guint32 opid, GError *error, GList *changes)
+e_data_book_respond_get_contact_list (EDataBook *book, guint32 opid, GError *error, const GSList *cards)
 {
-	GDBusMethodInvocation *invocation = opid_fetch (opid);
-
 	if (error) {
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_book_return_error (invocation, error, _("Cannot get changes: %s"));
+		/* Translators: This is prefix to a detailed error message */
+		g_prefix_error (&error, "%s", _("Cannot get contact list: "));
+		e_gdbus_book_emit_get_contact_list_done (book->priv->gdbus_object, opid, error, NULL);
 		g_error_free (error);
 	} else {
-		GVariantBuilder *builder;
-		GVariant *variant;
-
-		builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
+		gchar **array;
+		const GSList *l;
+		gint i = 0;
 
-		while (changes != NULL) {
-			EDataBookChange *change = (EDataBookChange *) changes->data;
-			gchar *gdbus_vcard = NULL;
+		array = g_new0 (gchar *, g_slist_length ((GSList *) cards) + 1);
+		for (l = cards; l != NULL; l = l->next) {
+			array[i++] = e_util_utf8_make_valid (l->data);
+		}
 
-			g_variant_builder_add (builder, "(us)", change->change_type, e_util_ensure_gdbus_string (change->vcard, &gdbus_vcard));
+		e_gdbus_book_emit_get_contact_list_done (book->priv->gdbus_object, opid, NULL, (const gchar * const *) array);
 
-			g_free (gdbus_vcard);
-			g_free (change->vcard);
-			g_free (change);
+		g_strfreev (array);
+	}
+}
 
-			changes = g_list_remove (changes, change);
-		}
+void
+e_data_book_respond_create (EDataBook *book, guint32 opid, GError *error, const EContact *contact)
+{
+	gchar *gdbus_uid = NULL;
 
-		/* always add one empty value */
-		g_variant_builder_add (builder, "(us)", -1, "");
+	op_complete (book, opid);
 
-		variant = g_variant_builder_end (builder);
-		g_variant_builder_unref (builder);
+	/* Translators: This is prefix to a detailed error message */
+	g_prefix_error (&error, "%s", _("Cannot add contact: "));
 
-		e_gdbus_book_complete_get_changes (book->priv->gdbus_object, invocation, variant);
+	e_gdbus_book_emit_add_contact_done (book->priv->gdbus_object, opid, error, e_util_ensure_gdbus_string (e_contact_get_const ((EContact *) contact, E_CONTACT_UID), &gdbus_uid));
 
-		g_variant_unref (variant);
+	g_free (gdbus_uid);
+	if (error) {
+		g_error_free (error);
+	} else {
+		e_book_backend_notify_update (e_data_book_get_backend (book), contact);
+		e_book_backend_notify_complete (e_data_book_get_backend (book));
 	}
 }
 
-static gboolean
-impl_Book_cancelOperation (EGdbusBook *object, GDBusMethodInvocation *invocation, EDataBook *book)
+void
+e_data_book_respond_modify (EDataBook *book, guint32 opid, GError *error, const EContact *contact)
 {
-	GError *error = NULL;
+	op_complete (book, opid);
+
+	/* Translators: This is prefix to a detailed error message */
+	g_prefix_error (&error, "%s", _("Cannot modify contact: "));
 
-	e_book_backend_cancel_operation (e_data_book_get_backend (book), book, &error);
+	e_gdbus_book_emit_modify_contact_done (book->priv->gdbus_object, opid, error);
 
 	if (error) {
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_book_return_error (invocation, error, _("Cancel operation failed: %s"));
 		g_error_free (error);
 	} else {
-		e_gdbus_book_complete_cancel_operation (object, invocation);
+		e_book_backend_notify_update (e_data_book_get_backend (book), contact);
+		e_book_backend_notify_complete (e_data_book_get_backend (book));
 	}
-
-	return TRUE;
 }
 
-static gboolean
-impl_Book_close (EGdbusBook *object, GDBusMethodInvocation *invocation, EDataBook *book)
+void
+e_data_book_respond_remove_contacts (EDataBook *book, guint32 opid, GError *error, const GSList *ids)
 {
-	e_book_backend_cancel_operation (e_data_book_get_backend (book), book, NULL);
-	e_book_backend_remove_client (e_data_book_get_backend (book), book);
+	op_complete (book, opid);
 
-	e_gdbus_book_complete_close (object, invocation);
-	g_object_unref (book);
+	/* Translators: This is prefix to a detailed error message */
+	g_prefix_error (&error, "%s", _("Cannot remove contacts: "));
+
+	e_gdbus_book_emit_remove_contacts_done (book->priv->gdbus_object, opid, error);
+
+	if (error) {
+		g_error_free (error);
+	} else {
+		const GSList *ii;
+
+		for (ii = ids; ii; ii = ii->next)
+			e_book_backend_notify_remove (e_data_book_get_backend (book), ii->data);
+
+		e_book_backend_notify_complete (e_data_book_get_backend (book));
+	}
 
-	return TRUE;
 }
 
 void
-e_data_book_report_writable (EDataBook *book, gboolean writable)
+e_data_book_report_error (EDataBook *book, const gchar *message)
 {
 	g_return_if_fail (book != NULL);
+	g_return_if_fail (message != NULL);
 
-	e_gdbus_book_emit_writable (book->priv->gdbus_object, writable);
+	e_gdbus_book_emit_backend_error (book->priv->gdbus_object, message);
 }
 
 void
-e_data_book_report_connection_status (EDataBook *book, gboolean connected)
+e_data_book_report_readonly (EDataBook *book, gboolean readonly)
 {
 	g_return_if_fail (book != NULL);
 
-	e_gdbus_book_emit_connection (book->priv->gdbus_object, connected);
+	e_gdbus_book_emit_readonly (book->priv->gdbus_object, readonly);
 }
 
 void
-e_data_book_report_auth_required (EDataBook *book)
+e_data_book_report_online (EDataBook *book, gboolean is_online)
 {
 	g_return_if_fail (book != NULL);
 
-	e_gdbus_book_emit_auth_required (book->priv->gdbus_object);
+	e_gdbus_book_emit_online (book->priv->gdbus_object, is_online);
 }
 
-static void
-return_error_and_list (EGdbusBook *gdbus_object, void (* complete_func) (EGdbusBook *object, GDBusMethodInvocation *invocation, const gchar * const *out_array), guint32 opid, GError *error, const gchar *error_fmt, GList *list, gboolean free_data)
+/* credentilas contains extra information for a source for which authentication is requested.
+   This parameter can be NULL to indicate "for this book".
+*/
+void
+e_data_book_report_auth_required (EDataBook *book, const ECredentials *credentials)
 {
-	GDBusMethodInvocation *invocation = opid_fetch (opid);
+	gchar *empty_strv[2];
+	gchar **strv = NULL;
 
-	g_return_if_fail (error_fmt != NULL);
-	g_return_if_fail (complete_func != NULL);
+	g_return_if_fail (book != NULL);
 
-	if (error) {
-		data_book_return_error (invocation, error, error_fmt);
-		g_error_free (error);
-	} else {
-		gchar **array;
-		GList *l;
-		gint i = 0;
+	empty_strv[0] = NULL;
+	empty_strv[1] = NULL;
 
-		array = g_new0 (gchar *, g_list_length (list) + 1);
-		for (l = list; l != NULL; l = l->next) {
-			array[i++] = e_util_utf8_make_valid (l->data);
-			if (free_data)
-				g_free (l->data);
-		}
+	if (credentials)
+		strv = e_credentials_to_strv (credentials);
 
-		complete_func (gdbus_object, invocation, (const gchar * const *) array);
+	e_gdbus_book_emit_auth_required (book->priv->gdbus_object, (const gchar * const *) (strv ? strv : empty_strv));
 
-		g_strfreev (array);
-	}
+	g_strfreev (strv);
+}
+
+/* Reports to associated client that opening phase of the book is finished.
+   error being NULL means successfully, otherwise reports an error which happened
+   during opening phase. By opening phase is meant a process including successfull
+   authentication to the server/storage.
+*/
+void
+e_data_book_report_opened (EDataBook *book, const GError *error)
+{
+	gchar **strv_error;
+
+	strv_error = e_gdbus_templates_encode_error (error);
+
+	e_gdbus_book_emit_opened (book->priv->gdbus_object, (const gchar * const *) strv_error);
+
+	g_strfreev (strv_error);
 }
 
 /**
@@ -854,28 +1020,29 @@ e_data_book_init (EDataBook *ebook)
 		ebook, E_TYPE_DATA_BOOK, EDataBookPrivate);
 
 	ebook->priv->gdbus_object = e_gdbus_book_stub_new ();
+	ebook->priv->pending_ops = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
+	g_static_rec_mutex_init (&ebook->priv->pending_ops_lock);
 
 	gdbus_object = ebook->priv->gdbus_object;
 	g_signal_connect (gdbus_object, "handle-open", G_CALLBACK (impl_Book_open), ebook);
 	g_signal_connect (gdbus_object, "handle-remove", G_CALLBACK (impl_Book_remove), ebook);
+	g_signal_connect (gdbus_object, "handle-refresh", G_CALLBACK (impl_Book_refresh), ebook);
 	g_signal_connect (gdbus_object, "handle-get-contact", G_CALLBACK (impl_Book_getContact), ebook);
 	g_signal_connect (gdbus_object, "handle-get-contact-list", G_CALLBACK (impl_Book_getContactList), ebook);
 	g_signal_connect (gdbus_object, "handle-authenticate-user", G_CALLBACK (impl_Book_authenticateUser), ebook);
 	g_signal_connect (gdbus_object, "handle-add-contact", G_CALLBACK (impl_Book_addContact), ebook);
 	g_signal_connect (gdbus_object, "handle-remove-contacts", G_CALLBACK (impl_Book_removeContacts), ebook);
 	g_signal_connect (gdbus_object, "handle-modify-contact", G_CALLBACK (impl_Book_modifyContact), ebook);
-	g_signal_connect (gdbus_object, "handle-get-static-capabilities", G_CALLBACK (impl_Book_getStaticCapabilities), ebook);
-	g_signal_connect (gdbus_object, "handle-get-required-fields", G_CALLBACK (impl_Book_getRequiredFields), ebook);
-	g_signal_connect (gdbus_object, "handle-get-supported-fields", G_CALLBACK (impl_Book_getSupportedFields), ebook);
-	g_signal_connect (gdbus_object, "handle-get-supported-auth-methods", G_CALLBACK (impl_Book_getSupportedAuthMethods), ebook);
-	g_signal_connect (gdbus_object, "handle-get-book-view", G_CALLBACK (impl_Book_getBookView), ebook);
-	g_signal_connect (gdbus_object, "handle-get-changes", G_CALLBACK (impl_Book_getChanges), ebook);
+	g_signal_connect (gdbus_object, "handle-get-backend-property", G_CALLBACK (impl_Book_getBackendProperty), ebook);
+	g_signal_connect (gdbus_object, "handle-set-backend-property", G_CALLBACK (impl_Book_setBackendProperty), ebook);
+	g_signal_connect (gdbus_object, "handle-get-view", G_CALLBACK (impl_Book_getBookView), ebook);
 	g_signal_connect (gdbus_object, "handle-cancel-operation", G_CALLBACK (impl_Book_cancelOperation), ebook);
+	g_signal_connect (gdbus_object, "handle-cancel-all", G_CALLBACK (impl_Book_cancelAll), ebook);
 	g_signal_connect (gdbus_object, "handle-close", G_CALLBACK (impl_Book_close), ebook);
 }
 
 static void
-e_data_book_dispose (GObject *object)
+data_book_dispose (GObject *object)
 {
 	EDataBook *book = E_DATA_BOOK (object);
 
@@ -897,6 +1064,13 @@ data_book_finalize (GObject *object)
 {
 	EDataBook *book = E_DATA_BOOK (object);
 
+	if (book->priv->pending_ops) {
+		g_hash_table_destroy (book->priv->pending_ops);
+		book->priv->pending_ops = NULL;
+	}
+
+	g_static_rec_mutex_free (&book->priv->pending_ops_lock);
+
 	if (book->priv->gdbus_object) {
 		g_object_unref (book->priv->gdbus_object);
 		book->priv->gdbus_object = NULL;
@@ -912,15 +1086,11 @@ e_data_book_class_init (EDataBookClass *klass)
 
 	g_type_class_add_private (klass, sizeof (EDataBookPrivate));
 
-	object_class->dispose = e_data_book_dispose;
+	object_class->dispose = data_book_dispose;
 	object_class->finalize = data_book_finalize;
 
-	if (!op_pool) {
-		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);
-	}
+	if (!ops_pool)
+		ops_pool = e_operation_pool_new (10, operation_thread, NULL);
 }
 
 EDataBook *
diff --git a/addressbook/libedata-book/e-data-book.h b/addressbook/libedata-book/e-data-book.h
index 5ea18a0..5f5d879 100644
--- a/addressbook/libedata-book/e-data-book.h
+++ b/addressbook/libedata-book/e-data-book.h
@@ -20,12 +20,15 @@
  * Author: Ross Burton <ross linux intel com>
  */
 
-#ifndef __E_DATA_BOOK_H__
-#define __E_DATA_BOOK_H__
+#ifndef E_DATA_BOOK_H
+#define E_DATA_BOOK_H
 
 #include <glib-object.h>
 #include <gio/gio.h>
+
+#include <libedataserver/e-credentials.h>
 #include <libedataserver/e-source.h>
+
 #include "e-book-backend.h"
 #include "e-data-book-types.h"
 
@@ -101,69 +104,54 @@ const gchar *e_data_book_status_to_string (EDataBookStatus status);
 		}								\
 	} G_STMT_END
 
-EDataBook		*e_data_book_new                    (EBookBackend *backend, ESource *source);
-
-guint			e_data_book_register_gdbus_object (EDataBook *cal, GDBusConnection *connection, const gchar *object_path, GError **error);
-
-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,
-							    GError *error);
-void                    e_data_book_respond_remove         (EDataBook *book,
-							    guint32 opid,
-							    GError *error);
-void                    e_data_book_respond_create         (EDataBook *book,
-							    guint32 opid,
-							    GError *error,
-							    EContact *contact);
-void                    e_data_book_respond_remove_contacts (EDataBook *book,
-							     guint32 opid,
-							     GError *error,
-							     GList *ids);
-void                    e_data_book_respond_modify         (EDataBook *book,
-							    guint32 opid,
-							    GError *error,
-							    EContact *contact);
-void                    e_data_book_respond_authenticate_user (EDataBook *book,
-							       guint32 opid,
-							       GError *error);
-void                    e_data_book_respond_get_supported_fields (EDataBook *book,
-								  guint32 opid,
-								  GError *error,
-								  GList *fields);
-void                    e_data_book_respond_get_required_fields (EDataBook *book,
-								  guint32 opid,
-								  GError *error,
-								  GList *fields);
-void                    e_data_book_respond_get_supported_auth_methods (EDataBook *book,
-									guint32 opid,
-									GError *error,
-									GList *fields);
-
-void                    e_data_book_respond_get_contact (EDataBook *book,
-							    guint32 opid,
-							    GError *error,
-							    const gchar *vcard);
-void                    e_data_book_respond_get_contact_list (EDataBook *book,
-							      guint32 opid,
-							      GError *error,
-							      GList *cards);
-void                    e_data_book_respond_get_changes    (EDataBook *book,
-							    guint32 opid,
-							    GError *error,
-							    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);
+/**
+ * e_return_data_book_error_if_fail:
+ *
+ * Same as e_return_data_book_error_if_fail(), only returns FALSE on a failure
+ *
+ * Since: 3.2
+ **/
+#define e_return_data_book_error_val_if_fail(expr, _code)			\
+	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__, G_STRFUNC, #expr);		\
+			g_set_error (error, E_DATA_BOOK_ERROR, (_code),		\
+				"file %s: line %d (%s): assertion `%s' failed",	\
+				__FILE__, __LINE__, G_STRFUNC, #expr);		\
+			return FALSE;						\
+		}								\
+	} G_STMT_END
+
+GType		e_data_book_get_type				(void);
+EDataBook *	e_data_book_new					(EBookBackend *backend, ESource *source);
+EBookBackend *	e_data_book_get_backend				(EDataBook *book);
+ESource *	e_data_book_get_source				(EDataBook *book);
+
+guint		e_data_book_register_gdbus_object		(EDataBook *cal, GDBusConnection *connection, const gchar *object_path, GError **error);
+
+void		e_data_book_respond_open			(EDataBook *book, guint32 opid, GError *error);
+void		e_data_book_respond_remove			(EDataBook *book, guint32 opid, GError *error);
+void		e_data_book_respond_refresh			(EDataBook *book, guint32 opid, GError *error);
+void		e_data_book_respond_get_backend_property	(EDataBook *book, guint32 opid, GError *error, const gchar *prop_value);
+void		e_data_book_respond_set_backend_property	(EDataBook *book, guint32 opid, GError *error);
+void		e_data_book_respond_create			(EDataBook *book, guint32 opid, GError *error, const EContact *contact);
+void		e_data_book_respond_remove_contacts		(EDataBook *book, guint32 opid, GError *error, const GSList *ids);
+void		e_data_book_respond_modify			(EDataBook *book, guint32 opid, GError *error, const EContact *contact);
+void		e_data_book_respond_get_contact			(EDataBook *book, guint32 opid, GError *error, const gchar *vcard);
+void		e_data_book_respond_get_contact_list		(EDataBook *book, guint32 opid, GError *error, const GSList *cards);
+
+void		e_data_book_report_error			(EDataBook *book, const gchar *message);
+void		e_data_book_report_readonly			(EDataBook *book, gboolean readonly);
+void		e_data_book_report_online			(EDataBook *book, gboolean is_online);
+void		e_data_book_report_auth_required		(EDataBook *book, const ECredentials *credentials);
+void		e_data_book_report_opened			(EDataBook *book, const GError *error);
+
+gchar *		e_data_book_string_slist_to_comma_string	(const GSList *strings);
 
 G_END_DECLS
 
-#endif /* __E_DATA_BOOK_H__ */
+#endif /* E_DATA_BOOK_H */
diff --git a/addressbook/libegdbus/Makefile.am b/addressbook/libegdbus/Makefile.am
index 41644a3..f564535 100644
--- a/addressbook/libegdbus/Makefile.am
+++ b/addressbook/libegdbus/Makefile.am
@@ -1,13 +1,3 @@
-GDBUS_XML_FILES =					\
-	../libedata-book/e-data-book-factory.xml	\
-	../libedata-book/e-data-book-view.xml		\
-	../libedata-book/e-data-book.xml
-
-gdbus-files: $(GDBUS_XML_FILES)
-	gdbus-codegen --namespace=EGdbus --strip-prefix=org.gnome.evolution.dataserver.addressbook --output-prefix=e-gdbus $(GDBUS_XML_FILES)
-	rm e-gdbus-bindings.h
-	rm e-gdbus-bindings.stamp
-
 # The library
 noinst_LTLIBRARIES = libegdbus-book.la
 
@@ -19,21 +9,17 @@ libegdbus_book_la_CPPFLAGS =			\
 	$(E_DATA_SERVER_CFLAGS)
 
 libegdbus_book_la_SOURCES =			\
-	e-gdbus-egdbusbook.h			\
-	e-gdbus-egdbusbook.c			\
-	e-gdbus-egdbusbookfactory.h		\
-	e-gdbus-egdbusbookfactory.c		\
-	e-gdbus-egdbusbookview.h		\
-	e-gdbus-egdbusbookview.c		\
-	e-gdbus-marshallers.h			\
-	e-gdbus-marshallers.c			\
-	e-gdbus-typemappers.h
+	e-gdbus-book.h				\
+	e-gdbus-book.c				\
+	e-gdbus-book-factory.h			\
+	e-gdbus-book-factory.c			\
+	e-gdbus-book-view.h			\
+	e-gdbus-book-view.c
 
 libegdbus_book_la_LIBADD =			\
+	$(top_builddir)/libedataserver/libedataserver-1.2.la	\
 	$(E_DATA_SERVER_LIBS)
 
 libegdbus_book_la_LDFLAGS = $(NO_UNDEFINED)
 
-EXTRA_DIST = e-gdbus-marshallers.list
-
 -include $(top_srcdir)/git.mk
diff --git a/addressbook/libegdbus/e-gdbus-book-factory.c b/addressbook/libegdbus/e-gdbus-book-factory.c
new file mode 100644
index 0000000..3536f59
--- /dev/null
+++ b/addressbook/libegdbus/e-gdbus-book-factory.c
@@ -0,0 +1,551 @@
+/*
+ * e-gdbus-book-factory.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 2011 Red Hat, Inc. (www.redhat.com)
+ *
+ */
+
+#include <stdio.h>
+#include <gio/gio.h>
+
+#include <libedataserver/e-data-server-util.h>
+#include <libedataserver/e-gdbus-marshallers.h>
+
+#include "e-gdbus-book-factory.h"
+
+#define GDBUS_BOOK_FACTORY_INTERFACE_NAME "org.gnome.evolution.dataserver.AddressBookFactory"
+
+typedef EGdbusBookFactoryIface EGdbusBookFactoryInterface;
+G_DEFINE_INTERFACE (EGdbusBookFactory, e_gdbus_book_factory, G_TYPE_OBJECT);
+
+enum
+{
+	_0_SIGNAL,
+	__GET_BOOK_METHOD,
+	__LAST_SIGNAL
+};
+
+static guint signals[__LAST_SIGNAL] = {0};
+
+/* ------------------------------------------------------------------------- */
+
+/* Various lookup tables */
+
+static GHashTable *_method_name_to_id = NULL;
+static GHashTable *_method_name_to_type = NULL;
+
+static guint
+lookup_method_id_from_method_name (const gchar *method_name)
+{
+	return GPOINTER_TO_UINT (g_hash_table_lookup (_method_name_to_id, method_name));
+}
+
+static guint
+lookup_method_type_from_method_name (const gchar *method_name)
+{
+	return GPOINTER_TO_UINT (g_hash_table_lookup (_method_name_to_type, method_name));
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void
+e_gdbus_book_factory_default_init (EGdbusBookFactoryIface *iface)
+{
+	/* Build lookup structures */
+	_method_name_to_id = g_hash_table_new (g_str_hash, g_str_equal);
+	_method_name_to_type = g_hash_table_new (g_str_hash, g_str_equal);
+
+	E_INIT_GDBUS_METHOD_STRING (EGdbusBookFactoryIface, "getBook", get_book, __GET_BOOK_METHOD)
+}
+
+void
+e_gdbus_book_factory_call_get_book (GDBusProxy *proxy, const gchar *in_source, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_method_call_string ("getBook", proxy, in_source, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_book_factory_call_get_book_finish (GDBusProxy *proxy, GAsyncResult *result, gchar **out_path, GError **error)
+{
+	return e_gdbus_proxy_method_call_finish_string (proxy, result, out_path, error);
+}
+
+gboolean
+e_gdbus_book_factory_call_get_book_sync (GDBusProxy *proxy, const gchar *in_source, gchar **out_path, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_method_call_sync_string__string ("getBook", proxy, in_source, out_path, cancellable, error);
+}
+
+void
+e_gdbus_book_factory_complete_get_book (EGdbusBookFactory *object, GDBusMethodInvocation *invocation, const gchar *out_path, const GError *error)
+{
+	e_gdbus_complete_sync_method_string (object, invocation, out_path, error);
+}
+
+E_DECLARE_GDBUS_SYNC_METHOD_1_WITH_RETURN (book_factory, getBook, source, "s", path, "s")
+
+static const GDBusMethodInfo * const e_gdbus_book_factory_method_info_pointers[] =
+{
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book_factory, getBook),
+	NULL
+};
+
+static const GDBusInterfaceInfo _e_gdbus_book_factory_interface_info =
+{
+	-1,
+	(gchar *) GDBUS_BOOK_FACTORY_INTERFACE_NAME,
+	(GDBusMethodInfo **) &e_gdbus_book_factory_method_info_pointers,
+	(GDBusSignalInfo **) NULL,
+	(GDBusPropertyInfo **) NULL
+};
+
+static void
+handle_method_call (GDBusConnection       *connection,
+                    const gchar           *sender,
+                    const gchar           *object_path,
+                    const gchar           *interface_name,
+                    const gchar           *method_name,
+                    GVariant              *parameters,
+                    GDBusMethodInvocation *invocation,
+                    gpointer               user_data)
+{
+	guint method_id, method_type;
+
+	method_id = lookup_method_id_from_method_name (method_name);
+	method_type = lookup_method_type_from_method_name (method_name);
+
+	g_return_if_fail (method_id != 0);
+	g_return_if_fail (method_type != 0);
+
+	e_gdbus_stub_handle_method_call (user_data, invocation, parameters, method_name, signals[method_id], method_type);
+}
+
+static GVariant *
+get_property (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *property_name, GError **error, gpointer user_data)
+{
+	g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "This implementation does not support property `%s'", property_name);
+	return NULL;
+}
+
+static gboolean
+set_property (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *property_name, GVariant *value, GError **error, gpointer user_data)
+{
+	g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "This implementation does not support property `%s'", property_name);
+	return FALSE;
+}
+
+static const GDBusInterfaceVTable e_gdbus_book_factory_interface_vtable =
+{
+	handle_method_call,
+	get_property,
+	set_property
+};
+
+static gboolean
+emit_notifications_in_idle (gpointer user_data)
+{
+	GObject *object = G_OBJECT (user_data);
+	GDBusConnection *connection;
+	const gchar *path;
+	GHashTable *notification_queue;
+	GHashTableIter iter;
+	const gchar *property_name;
+	GVariant *value;
+	GVariantBuilder *builder;
+	GVariantBuilder *invalidated_builder;
+	GHashTable *pvc;
+	gboolean has_changes;
+
+	notification_queue = g_object_get_data (object, "gdbus-codegen-notification-queue");
+	path = g_object_get_data (object, "gdbus-codegen-path");
+	connection = g_object_get_data (object, "gdbus-codegen-connection");
+	pvc = g_object_get_data (object, "gdbus-codegen-pvc");
+	g_assert (notification_queue != NULL && path != NULL && connection != NULL && pvc != NULL);
+
+	builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
+	invalidated_builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
+	g_hash_table_iter_init (&iter, notification_queue);
+	has_changes = FALSE;
+	while (g_hash_table_iter_next (&iter, (gpointer) &property_name, (gpointer) &value)) {
+		GVariant *cached_value;
+		cached_value = g_hash_table_lookup (pvc, property_name);
+		if (cached_value == NULL || !g_variant_equal (cached_value, value)) {
+			g_hash_table_insert (pvc, (gpointer) property_name, (gpointer) g_variant_ref (value));
+			g_variant_builder_add (builder, "{sv}", property_name, value);
+			has_changes = TRUE;
+		}
+	}
+
+	if (has_changes) {
+		g_dbus_connection_emit_signal (connection,
+						NULL,
+						path,
+						"org.freedesktop.DBus.Properties",
+						"PropertiesChanged",
+						g_variant_new ("(sa{sv}as)",
+							GDBUS_BOOK_FACTORY_INTERFACE_NAME,
+							builder,
+							invalidated_builder),
+						NULL);
+	} else {
+		g_variant_builder_unref (builder);
+		g_variant_builder_unref (invalidated_builder);
+	}
+
+	g_hash_table_remove_all (notification_queue);
+	g_object_set_data (object, "gdbus-codegen-notification-idle-id", GUINT_TO_POINTER (0));
+	return FALSE;
+}
+
+/**
+ * e_gdbus_book_factory_drain_notify:
+ * @object: A #EGdbusBookFactory that is exported.
+ *
+ * If @object has queued notifications, empty the queue forcing
+ * the <literal>PropertiesChanged</literal> signal to be emitted.
+ * See <xref linkend="EGdbusBookFactory.description"/> for more background information.
+ */
+void
+e_gdbus_book_factory_drain_notify (EGdbusBookFactory *object)
+{
+	gint idle_id;
+	idle_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (object), "gdbus-codegen-notification-idle-id"));
+	if (idle_id > 0) {
+		emit_notifications_in_idle (object);
+		g_source_remove (idle_id);
+	}
+}
+
+static void
+on_object_unregistered (GObject *object)
+{
+	gint idle_id;
+	idle_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (object), "gdbus-codegen-notification-idle-id"));
+	if (idle_id > 0) {
+		g_source_remove (idle_id);
+	}
+	g_object_set_data (G_OBJECT (object), "gdbus-codegen-path", NULL);
+	g_object_set_data (G_OBJECT (object), "gdbus-codegen-connection", NULL);
+}
+
+/**
+ * e_gdbus_book_factory_register_object:
+ * @object: An instance of a #GObject<!-- -->-derived type implementing the #EGdbusBookFactory interface.
+ * @connection: A #GDBusConnection.
+ * @object_path: The object to register the object at.
+ * @error: Return location for error or %NULL.
+ *
+ * Registers @object at @object_path on @connection.
+ *
+ * See <xref linkend="EGdbusBookFactory.description"/>
+ * for how properties, methods and signals are handled.
+ *
+ * Returns: 0 if @error is set, otherwise a registration id (never 0) that can be used with g_dbus_connection_unregister_object().
+ */
+guint
+e_gdbus_book_factory_register_object (EGdbusBookFactory *object, GDBusConnection *connection, const gchar *object_path, GError **error)
+{
+	GHashTable *pvc;
+
+	pvc = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) g_variant_unref);
+
+	g_object_set_data_full (G_OBJECT (object), "gdbus-codegen-path", (gpointer) g_strdup (object_path), g_free);
+	g_object_set_data (G_OBJECT (object), "gdbus-codegen-connection", (gpointer) connection);
+	g_object_set_data_full (G_OBJECT (object), "gdbus-codegen-pvc", (gpointer) pvc, (GDestroyNotify) g_hash_table_unref);
+
+	return g_dbus_connection_register_object (connection,
+			object_path,
+			(GDBusInterfaceInfo *) &_e_gdbus_book_factory_interface_info,
+			&e_gdbus_book_factory_interface_vtable,
+			object,
+			(GDestroyNotify) on_object_unregistered,
+			error);
+}
+
+/**
+ * e_gdbus_book_factory_interface_info:
+ *
+ * Gets interface description for the <literal>org.gnome.evolution.dataserver.AddressBookFactory</literal> D-Bus interface.
+ *
+ * Returns: A #GDBusInterfaceInfo. Do not free, the object is statically allocated.
+ */
+const GDBusInterfaceInfo *
+e_gdbus_book_factory_interface_info (void)
+{
+	return &_e_gdbus_book_factory_interface_info;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void proxy_iface_init (EGdbusBookFactoryIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (EGdbusBookFactoryProxy, e_gdbus_book_factory_proxy, G_TYPE_DBUS_PROXY,
+                         G_IMPLEMENT_INTERFACE (E_TYPE_GDBUS_BOOK_FACTORY, proxy_iface_init));
+
+static void
+e_gdbus_book_factory_proxy_init (EGdbusBookFactoryProxy *proxy)
+{
+	g_dbus_proxy_set_interface_info (G_DBUS_PROXY (proxy), (GDBusInterfaceInfo *) &_e_gdbus_book_factory_interface_info);
+}
+
+static void
+g_signal (GDBusProxy *proxy, const gchar *sender_name, const gchar *signal_name, GVariant *parameters)
+{
+	/*
+	guint signal_id, signal_type;
+
+	signal_id = lookup_signal_id_from_signal_name (signal_name);
+	signal_type = lookup_signal_type_from_signal_name (signal_name);
+
+	g_return_if_fail (signal_id != 0);
+	g_return_if_fail (signal_type != 0);
+
+	e_gdbus_proxy_emit_signal (proxy, parameters, signals[signal_id], signal_type);
+	*/
+}
+
+static void
+e_gdbus_book_factory_proxy_class_init (EGdbusBookFactoryProxyClass *klass)
+{
+	GDBusProxyClass *proxy_class;
+
+	proxy_class = G_DBUS_PROXY_CLASS (klass);
+	proxy_class->g_signal = g_signal;
+}
+
+static void
+proxy_iface_init (EGdbusBookFactoryIface *iface)
+{
+}
+
+/**
+ * e_gdbus_book_factory_proxy_new:
+ * @connection: A #GDBusConnection.
+ * @flags: Flags used when constructing the proxy.
+ * @name: A bus name (well-known or unique) or %NULL if @connection is not a message bus connection.
+ * @object_path: An object path.
+ * @cancellable: A #GCancellable or %NULL.
+ * @callback: Callback function to invoke when the proxy is ready.
+ * @user_data: User data to pass to @callback.
+ *
+ * Like g_dbus_proxy_new() but returns a #EGdbusBookFactoryProxy.
+ *
+ * This is a failable asynchronous constructor - when the proxy is ready, callback will be invoked and you can use e_gdbus_book_factory_proxy_new_finish() to get the result.
+ */
+void
+e_gdbus_book_factory_proxy_new (GDBusConnection *connection, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	g_async_initable_new_async (E_TYPE_GDBUS_BOOK_FACTORY_PROXY,
+				G_PRIORITY_DEFAULT,
+				cancellable,
+				callback,
+				user_data,
+				"g-flags", flags,
+				"g-name", name,
+				"g-connection", connection,
+				"g-object-path", object_path,
+				"g-interface-name", GDBUS_BOOK_FACTORY_INTERFACE_NAME,
+				NULL);
+}
+
+/**
+ * e_gdbus_book_factory_proxy_new_finish:
+ * @result: A #GAsyncResult obtained from the #GAsyncReadyCallback function passed to e_gdbus_book_factory_proxy_new().
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes creating a #EGdbusBookFactoryProxy.
+ *
+ * Returns: A #EGdbusBookFactoryProxy or %NULL if @error is set. Free with g_object_unref().
+ */
+EGdbusBookFactory *
+e_gdbus_book_factory_proxy_new_finish (GAsyncResult  *result, GError **error)
+{
+	GObject *object;
+	GObject *source_object;
+	source_object = g_async_result_get_source_object (result);
+	g_assert (source_object != NULL);
+	object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), result, error);
+	g_object_unref (source_object);
+	if (object != NULL)
+		return E_GDBUS_BOOK_FACTORY (object);
+	else
+		return NULL;
+}
+
+/**
+ * e_gdbus_book_factory_proxy_new_sync:
+ * @connection: A #GDBusConnection.
+ * @flags: Flags used when constructing the proxy.
+ * @name: A bus name (well-known or unique) or %NULL if @connection is not a message bus connection.
+ * @object_path: An object path.
+ * @cancellable: A #GCancellable or %NULL.
+ * @error: Return location for error or %NULL.
+ *
+ * Like g_dbus_proxy_new_sync() but returns a #EGdbusBookFactoryProxy.
+ *
+ * This is a synchronous failable constructor. See e_gdbus_book_factory_proxy_new() and e_gdbus_book_factory_proxy_new_finish() for the asynchronous version.
+ *
+ * Returns: A #EGdbusBookFactoryProxy or %NULL if error is set. Free with g_object_unref().
+ */
+EGdbusBookFactory *
+e_gdbus_book_factory_proxy_new_sync (GDBusConnection *connection, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GError **error)
+{
+	GInitable *initable;
+	initable = g_initable_new (E_TYPE_GDBUS_BOOK_FACTORY_PROXY,
+				cancellable,
+				error,
+				"g-flags", flags,
+				"g-name", name,
+				"g-connection", connection,
+				"g-object-path", object_path,
+				"g-interface-name", GDBUS_BOOK_FACTORY_INTERFACE_NAME,
+				NULL);
+	if (initable != NULL)
+		return E_GDBUS_BOOK_FACTORY (initable);
+	else
+		return NULL;
+}
+
+/**
+ * e_gdbus_book_factory_proxy_new_for_bus:
+ * @bus_type: A #GBusType.
+ * @flags: Flags used when constructing the proxy.
+ * @name: A bus name (well-known or unique).
+ * @object_path: An object path.
+ * @cancellable: A #GCancellable or %NULL.
+ * @callback: Callback function to invoke when the proxy is ready.
+ * @user_data: User data to pass to @callback.
+ *
+ * Like g_dbus_proxy_new_for_bus() but returns a #EGdbusBookFactoryProxy.
+ *
+ * This is a failable asynchronous constructor - when the proxy is ready, callback will be invoked and you can use e_gdbus_book_factory_proxy_new_for_bus_finish() to get the result.
+ */
+void
+e_gdbus_book_factory_proxy_new_for_bus (GBusType bus_type, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	g_async_initable_new_async (E_TYPE_GDBUS_BOOK_FACTORY_PROXY,
+				G_PRIORITY_DEFAULT,
+				cancellable,
+				callback,
+				user_data,
+				"g-flags", flags,
+				"g-name", name,
+				"g-bus-type", bus_type,
+				"g-object-path", object_path,
+				"g-interface-name", GDBUS_BOOK_FACTORY_INTERFACE_NAME,
+				NULL);
+}
+
+/**
+ * e_gdbus_book_factory_proxy_new_for_bus_finish:
+ * @result: A #GAsyncResult obtained from the #GAsyncReadyCallback function passed to e_gdbus_book_factory_proxy_new_for_bus().
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes creating a #EGdbusBookFactoryProxy.
+ *
+ * Returns: A #EGdbusBookFactoryProxy or %NULL if @error is set. Free with g_object_unref().
+ */
+EGdbusBookFactory *
+e_gdbus_book_factory_proxy_new_for_bus_finish (GAsyncResult *result, GError **error)
+{
+	GObject *object;
+	GObject *source_object;
+	source_object = g_async_result_get_source_object (result);
+	g_assert (source_object != NULL);
+	object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), result, error);
+	g_object_unref (source_object);
+	if (object != NULL)
+		return E_GDBUS_BOOK_FACTORY (object);
+	else
+		return NULL;
+}
+
+/**
+ * e_gdbus_book_factory_proxy_new_for_bus_sync:
+ * @bus_type: A #GBusType.
+ * @flags: Flags used when constructing the proxy.
+ * @name: A bus name (well-known or unique).
+ * @object_path: An object path.
+ * @cancellable: A #GCancellable or %NULL.
+ * @error: Return location for error or %NULL.
+ *
+ * Like g_dbus_proxy_new_for_bus_sync() but returns a #EGdbusBookFactoryProxy.
+ *
+ * This is a synchronous failable constructor. See e_gdbus_book_factory_proxy_new_for_bus() and e_gdbus_book_factory_proxy_new_for_bus_finish() for the asynchronous version.
+ *
+ * Returns: A #EGdbusBookFactoryProxy or %NULL if error is set. Free with g_object_unref().
+ */
+EGdbusBookFactory *
+e_gdbus_book_factory_proxy_new_for_bus_sync (GBusType bus_type, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GError **error)
+{
+	GInitable *initable;
+	initable = g_initable_new (E_TYPE_GDBUS_BOOK_FACTORY_PROXY,
+				cancellable,
+				error,
+				"g-flags", flags,
+				"g-name", name,
+				"g-bus-type", bus_type,
+				"g-object-path", object_path,
+				"g-interface-name", GDBUS_BOOK_FACTORY_INTERFACE_NAME,
+				NULL);
+	if (initable != NULL)
+		return E_GDBUS_BOOK_FACTORY (initable);
+	else
+		return NULL;
+}
+
+/* ---------------------------------------------------------------------- */
+
+struct _EGdbusBookFactoryStubPrivate
+{
+	gint foo;
+};
+
+static void stub_iface_init (EGdbusBookFactoryIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (EGdbusBookFactoryStub, e_gdbus_book_factory_stub, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (E_TYPE_GDBUS_BOOK_FACTORY, stub_iface_init));
+
+static void
+e_gdbus_book_factory_stub_init (EGdbusBookFactoryStub *stub)
+{
+	stub->priv = G_TYPE_INSTANCE_GET_PRIVATE (stub, E_TYPE_GDBUS_BOOK_FACTORY_STUB, EGdbusBookFactoryStubPrivate);
+}
+
+static void
+e_gdbus_book_factory_stub_class_init (EGdbusBookFactoryStubClass *klass)
+{
+	g_type_class_add_private (klass, sizeof (EGdbusBookFactoryStubPrivate));
+}
+
+static void
+stub_iface_init (EGdbusBookFactoryIface *iface)
+{
+}
+
+/**
+ * e_gdbus_book_factory_stub_new:
+ *
+ * Creates a new stub object that can be exported via e_gdbus_book_factory_register_object().
+ *
+ * Returns: A #EGdbusBookFactoryStub instance. Free with g_object_unref().
+ */
+EGdbusBookFactory *
+e_gdbus_book_factory_stub_new (void)
+{
+	return E_GDBUS_BOOK_FACTORY (g_object_new (E_TYPE_GDBUS_BOOK_FACTORY_STUB, NULL));
+}
diff --git a/addressbook/libegdbus/e-gdbus-book-factory.h b/addressbook/libegdbus/e-gdbus-book-factory.h
new file mode 100644
index 0000000..588de6c
--- /dev/null
+++ b/addressbook/libegdbus/e-gdbus-book-factory.h
@@ -0,0 +1,120 @@
+/*
+ * e-gdbus-book-factory.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 2011 Red Hat, Inc. (www.redhat.com)
+ *
+ */
+
+#ifndef E_GDBUS_BOOK_FACTORY_H
+#define E_GDBUS_BOOK_FACTORY_H
+
+#include <gio/gio.h>
+
+#include <libedataserver/e-gdbus-templates.h>
+
+G_BEGIN_DECLS
+
+#define E_TYPE_GDBUS_BOOK_FACTORY         (e_gdbus_book_factory_get_type ())
+#define E_GDBUS_BOOK_FACTORY(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_GDBUS_BOOK_FACTORY, EGdbusBookFactory))
+#define E_IS_GDBUS_BOOK_FACTORY(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_GDBUS_BOOK_FACTORY))
+#define E_GDBUS_BOOK_FACTORY_GET_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE((o), E_TYPE_GDBUS_BOOK_FACTORY, EGdbusBookFactoryIface))
+
+/**
+ * EGdbusBookFactory:
+ *
+ * Opaque type representing a proxy or an exported object.
+ */
+typedef struct _EGdbusBookFactory EGdbusBookFactory; /* Dummy typedef */
+typedef struct _EGdbusBookFactoryIface EGdbusBookFactoryIface;
+
+GType e_gdbus_book_factory_get_type (void) G_GNUC_CONST;
+
+/* ---------------------------------------------------------------------- */
+
+typedef struct _EGdbusBookFactoryProxy EGdbusBookFactoryProxy;
+typedef struct _EGdbusBookFactoryProxyClass EGdbusBookFactoryProxyClass;
+typedef struct _EGdbusBookFactoryProxyPrivate EGdbusBookFactoryProxyPrivate;
+
+struct _EGdbusBookFactoryProxy
+{
+	GDBusProxy parent_instance;
+	EGdbusBookFactoryProxyPrivate *priv;
+};
+
+struct _EGdbusBookFactoryProxyClass
+{
+	GDBusProxyClass parent_class;
+};
+
+#define E_TYPE_GDBUS_BOOK_FACTORY_PROXY (e_gdbus_book_factory_proxy_get_type ())
+GType e_gdbus_book_factory_proxy_get_type (void) G_GNUC_CONST;
+
+void			e_gdbus_book_factory_proxy_new (GDBusConnection *connection, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+EGdbusBookFactory *	e_gdbus_book_factory_proxy_new_finish (GAsyncResult *result, GError **error);
+EGdbusBookFactory *	e_gdbus_book_factory_proxy_new_sync (GDBusConnection *connection, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GError **error);
+
+void			e_gdbus_book_factory_proxy_new_for_bus (GBusType bus_type, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+EGdbusBookFactory *	e_gdbus_book_factory_proxy_new_for_bus_finish (GAsyncResult *result, GError **error);
+EGdbusBookFactory *	e_gdbus_book_factory_proxy_new_for_bus_sync (GBusType bus_type, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GError **error);
+
+/* ---------------------------------------------------------------------- */
+
+typedef struct _EGdbusBookFactoryStub EGdbusBookFactoryStub;
+typedef struct _EGdbusBookFactoryStubClass EGdbusBookFactoryStubClass;
+typedef struct _EGdbusBookFactoryStubPrivate EGdbusBookFactoryStubPrivate;
+
+struct _EGdbusBookFactoryStub
+{
+	GObject parent_instance;
+	EGdbusBookFactoryStubPrivate *priv;
+};
+
+struct _EGdbusBookFactoryStubClass
+{
+	GObjectClass parent_class;
+};
+
+#define E_TYPE_GDBUS_BOOK_FACTORY_STUB (e_gdbus_book_factory_stub_get_type ())
+GType e_gdbus_book_factory_stub_get_type (void) G_GNUC_CONST;
+
+EGdbusBookFactory *e_gdbus_book_factory_stub_new (void);
+
+guint e_gdbus_book_factory_register_object (EGdbusBookFactory *object, GDBusConnection *connection, const gchar *object_path, GError **error);
+
+void e_gdbus_book_factory_drain_notify (EGdbusBookFactory *object);
+
+const GDBusInterfaceInfo *e_gdbus_book_factory_interface_info (void) G_GNUC_CONST;
+
+struct _EGdbusBookFactoryIface
+{
+	GTypeInterface parent_iface;
+
+	/* Signal handlers for handling D-Bus method calls: */
+	gboolean (*handle_get_book) (EGdbusBookFactory *object, GDBusMethodInvocation *invocation, const gchar *in_source);
+};
+
+/* D-Bus Methods */
+void		e_gdbus_book_factory_call_get_book		(GDBusProxy *proxy, const gchar *in_source, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_book_factory_call_get_book_finish	(GDBusProxy *proxy, GAsyncResult *result, gchar **out_path, GError **error);
+gboolean	e_gdbus_book_factory_call_get_book_sync		(GDBusProxy *proxy, const gchar *in_source, gchar **out_path, GCancellable *cancellable, GError **error);
+
+/* D-Bus Methods Completion Helpers */
+void e_gdbus_book_factory_complete_get_book (EGdbusBookFactory *object, GDBusMethodInvocation *invocation, const gchar *out_path, const GError *error);
+
+G_END_DECLS
+
+#endif /* E_GDBUS_BOOK_FACTORY_H */
diff --git a/addressbook/libegdbus/e-gdbus-book-view.c b/addressbook/libegdbus/e-gdbus-book-view.c
new file mode 100644
index 0000000..d73ae51
--- /dev/null
+++ b/addressbook/libegdbus/e-gdbus-book-view.c
@@ -0,0 +1,690 @@
+/*
+ * e-gdbus-book-view.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 2011 Red Hat, Inc. (www.redhat.com)
+ *
+ */
+
+#include <stdio.h>
+#include <gio/gio.h>
+
+#include <libedataserver/e-data-server-util.h>
+#include <libedataserver/e-gdbus-marshallers.h>
+
+#include "e-gdbus-book-view.h"
+
+#define GDBUS_BOOK_VIEW_INTERFACE_NAME "org.gnome.evolution.dataserver.AddressBookView"
+
+typedef EGdbusBookViewIface EGdbusBookViewInterface;
+G_DEFINE_INTERFACE (EGdbusBookView, e_gdbus_book_view, G_TYPE_OBJECT);
+
+enum
+{
+	_0_SIGNAL,
+	__OBJECTS_ADDED_SIGNAL,
+	__OBJECTS_MODIFIED_SIGNAL,
+	__OBJECTS_REMOVED_SIGNAL,
+	__PROGRESS_SIGNAL,
+	__COMPLETE_SIGNAL,
+	__START_METHOD,
+	__STOP_METHOD,
+	__DISPOSE_METHOD,
+	__SET_FIELDS_OF_INTEREST_METHOD,
+	__LAST_SIGNAL
+};
+
+static guint signals[__LAST_SIGNAL] = {0};
+
+/* ------------------------------------------------------------------------- */
+
+/* Various lookup tables */
+
+static GHashTable *_method_name_to_id = NULL;
+static GHashTable *_method_name_to_type = NULL;
+static GHashTable *_signal_name_to_id = NULL;
+static GHashTable *_signal_name_to_type = NULL;
+
+static guint
+lookup_method_id_from_method_name (const gchar *method_name)
+{
+	return GPOINTER_TO_UINT (g_hash_table_lookup (_method_name_to_id, method_name));
+}
+
+static guint
+lookup_method_type_from_method_name (const gchar *method_name)
+{
+	return GPOINTER_TO_UINT (g_hash_table_lookup (_method_name_to_type, method_name));
+}
+
+static guint
+lookup_signal_id_from_signal_name (const gchar *signal_name)
+{
+	return GPOINTER_TO_UINT (g_hash_table_lookup (_signal_name_to_id, signal_name));
+}
+
+static guint
+lookup_signal_type_from_signal_name (const gchar *signal_name)
+{
+	return GPOINTER_TO_UINT (g_hash_table_lookup (_signal_name_to_type, signal_name));
+}
+
+/* ------------------------------------------------------------------------- */
+
+E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_STRV	 (GDBUS_BOOK_VIEW_INTERFACE_NAME, objects_added)
+E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_STRV	 (GDBUS_BOOK_VIEW_INTERFACE_NAME, objects_modified)
+E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_STRV	 (GDBUS_BOOK_VIEW_INTERFACE_NAME, objects_removed)
+E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_UINT_STRING (GDBUS_BOOK_VIEW_INTERFACE_NAME, progress)
+E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_STRV	 (GDBUS_BOOK_VIEW_INTERFACE_NAME, complete)
+
+static void
+e_gdbus_book_view_default_init (EGdbusBookViewIface *iface)
+{
+	/* Build lookup structures */
+	_method_name_to_id = g_hash_table_new (g_str_hash, g_str_equal);
+	_method_name_to_type = g_hash_table_new (g_str_hash, g_str_equal);
+	_signal_name_to_id = g_hash_table_new (g_str_hash, g_str_equal);
+	_signal_name_to_type = g_hash_table_new (g_str_hash, g_str_equal);
+
+	
+	/* GObject signals definitions for D-Bus signals: */
+	E_INIT_GDBUS_SIGNAL_STRV	(EGdbusBookViewIface, "ObjectsAdded",	objects_added, __OBJECTS_ADDED_SIGNAL)
+	E_INIT_GDBUS_SIGNAL_STRV	(EGdbusBookViewIface, "ObjectsModified",objects_modified, __OBJECTS_MODIFIED_SIGNAL)
+	E_INIT_GDBUS_SIGNAL_STRV	(EGdbusBookViewIface, "ObjectsRemoved",	objects_removed, __OBJECTS_REMOVED_SIGNAL)
+	E_INIT_GDBUS_SIGNAL_UINT_STRING	(EGdbusBookViewIface, "Progress",	progress, __PROGRESS_SIGNAL)
+	E_INIT_GDBUS_SIGNAL_STRV	(EGdbusBookViewIface, "Complete",	complete, __COMPLETE_SIGNAL)
+
+	/* GObject signals definitions for D-Bus methods: */
+	E_INIT_GDBUS_METHOD_VOID	(EGdbusBookViewIface, "start",			start, __START_METHOD)
+	E_INIT_GDBUS_METHOD_VOID	(EGdbusBookViewIface, "stop",			stop, __STOP_METHOD)
+	E_INIT_GDBUS_METHOD_VOID	(EGdbusBookViewIface, "dispose",		dispose, __DISPOSE_METHOD)
+	E_INIT_GDBUS_METHOD_STRV	(EGdbusBookViewIface, "setFieldsOfInterest",	set_fields_of_interest, __SET_FIELDS_OF_INTEREST_METHOD)
+}
+
+void
+e_gdbus_book_view_call_start (GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_method_call_void ("start", proxy, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_book_view_call_start_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_method_call_finish_void (proxy, result, error);
+}
+
+gboolean
+e_gdbus_book_view_call_start_sync (GDBusProxy *proxy, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_method_call_sync_void__void ("start", proxy, cancellable, error);
+}
+
+void
+e_gdbus_book_view_call_stop (GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_method_call_void ("stop", proxy, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_book_view_call_stop_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_method_call_finish_void (proxy, result, error);
+}
+
+gboolean
+e_gdbus_book_view_call_stop_sync (GDBusProxy *proxy, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_method_call_sync_void__void ("stop", proxy, cancellable, error);
+}
+
+void
+e_gdbus_book_view_call_dispose (GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_method_call_void ("dispose", proxy, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_book_view_call_dispose_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_method_call_finish_void (proxy, result, error);
+}
+
+gboolean
+e_gdbus_book_view_call_dispose_sync (GDBusProxy *proxy, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_method_call_sync_void__void ("dispose", proxy, cancellable, error);
+}
+
+void
+e_gdbus_book_view_call_set_fields_of_interest (GDBusProxy *proxy, const gchar * const *in_only_fields, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_method_call_strv ("setFieldsOfInterest", proxy, in_only_fields, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_book_view_call_set_fields_of_interest_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_method_call_finish_void (proxy, result, error);
+}
+
+gboolean
+e_gdbus_book_view_call_set_fields_of_interest_sync (GDBusProxy *proxy, const gchar * const *in_only_fields, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_method_call_sync_strv__void ("setFieldsOfInterest", proxy, in_only_fields, cancellable, error);
+}
+
+void
+e_gdbus_book_view_emit_objects_added (EGdbusBookView *object, const gchar * const *arg_objects)
+{
+	g_signal_emit (object, signals[__OBJECTS_ADDED_SIGNAL], 0, arg_objects);
+}
+
+void
+e_gdbus_book_view_emit_objects_modified (EGdbusBookView *object, const gchar * const *arg_objects)
+{
+	g_signal_emit (object, signals[__OBJECTS_MODIFIED_SIGNAL], 0, arg_objects);
+}
+
+void
+e_gdbus_book_view_emit_objects_removed (EGdbusBookView *object, const gchar * const *arg_uids)
+{
+	g_signal_emit (object, signals[__OBJECTS_REMOVED_SIGNAL], 0, arg_uids);
+}
+
+void
+e_gdbus_book_view_emit_progress (EGdbusBookView *object, guint arg_percent, const gchar *arg_message)
+{
+	g_signal_emit (object, signals[__PROGRESS_SIGNAL], 0, arg_percent, arg_message);
+}
+
+void
+e_gdbus_book_view_emit_complete (EGdbusBookView *object, const gchar * const *arg_error)
+{
+	g_signal_emit (object, signals[__COMPLETE_SIGNAL], 0, arg_error);
+}
+
+E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (book_view, ObjectsAdded, objects, "as")
+E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (book_view, ObjectsModified, objects, "as")
+E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (book_view, ObjectsRemoved, uids, "as")
+E_DECLARE_GDBUS_NOTIFY_SIGNAL_2 (book_view, Progress, percent, "u", message, "s")
+E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (book_view, Complete, error, "as")
+
+E_DECLARE_GDBUS_SYNC_METHOD_0	(book_view, start)
+E_DECLARE_GDBUS_SYNC_METHOD_0	(book_view, stop)
+E_DECLARE_GDBUS_SYNC_METHOD_0	(book_view, dispose)
+E_DECLARE_GDBUS_SYNC_METHOD_1	(book_view, setFieldsOfInterest, fields_of_interest, "as")
+
+static const GDBusMethodInfo * const e_gdbus_book_view_method_info_pointers[] =
+{
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book_view, start),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book_view, stop),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book_view, dispose),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book_view, setFieldsOfInterest),
+	NULL
+};
+
+static const GDBusSignalInfo * const e_gdbus_book_view_signal_info_pointers[] =
+{
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book_view, ObjectsAdded),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book_view, ObjectsModified),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book_view, ObjectsRemoved),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book_view, Progress),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book_view, Complete),
+	NULL
+};
+
+static const GDBusInterfaceInfo _e_gdbus_book_view_interface_info =
+{
+	-1,
+	(gchar *) GDBUS_BOOK_VIEW_INTERFACE_NAME,
+	(GDBusMethodInfo **) &e_gdbus_book_view_method_info_pointers,
+	(GDBusSignalInfo **) &e_gdbus_book_view_signal_info_pointers,
+	(GDBusPropertyInfo **) NULL
+};
+
+static void
+handle_method_call (GDBusConnection       *connection,
+                    const gchar           *sender,
+                    const gchar           *object_path,
+                    const gchar           *interface_name,
+                    const gchar           *method_name,
+                    GVariant              *parameters,
+                    GDBusMethodInvocation *invocation,
+                    gpointer               user_data)
+{
+	guint method_id, method_type;
+
+	method_id = lookup_method_id_from_method_name (method_name);
+	method_type = lookup_method_type_from_method_name (method_name);
+
+	g_return_if_fail (method_id != 0);
+	g_return_if_fail (method_type != 0);
+
+	e_gdbus_stub_handle_method_call (user_data, invocation, parameters, method_name, signals[method_id], method_type);
+}
+
+static GVariant *
+get_property (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *property_name, GError **error, gpointer user_data)
+{
+	g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "This implementation does not support property `%s'", property_name);
+	return NULL;
+}
+
+static gboolean
+set_property (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *property_name, GVariant *value, GError **error, gpointer user_data)
+{
+	g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "This implementation does not support property `%s'", property_name);
+	return FALSE;
+}
+
+static const GDBusInterfaceVTable e_gdbus_book_view_interface_vtable =
+{
+  handle_method_call,
+  get_property,
+  set_property
+};
+
+static gboolean
+emit_notifications_in_idle (gpointer user_data)
+{
+	GObject *object = G_OBJECT (user_data);
+	GDBusConnection *connection;
+	const gchar *path;
+	GHashTable *notification_queue;
+	GHashTableIter iter;
+	const gchar *property_name;
+	GVariant *value;
+	GVariantBuilder *builder;
+	GVariantBuilder *invalidated_builder;
+	GHashTable *pvc;
+	gboolean has_changes;
+
+	notification_queue = g_object_get_data (object, "gdbus-codegen-notification-queue");
+	path = g_object_get_data (object, "gdbus-codegen-path");
+	connection = g_object_get_data (object, "gdbus-codegen-connection");
+	pvc = g_object_get_data (object, "gdbus-codegen-pvc");
+	g_assert (notification_queue != NULL && path != NULL && connection != NULL && pvc != NULL);
+
+	builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
+	invalidated_builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
+	g_hash_table_iter_init (&iter, notification_queue);
+	has_changes = FALSE;
+	while (g_hash_table_iter_next (&iter, (gpointer) &property_name, (gpointer) &value)) {
+		GVariant *cached_value;
+		cached_value = g_hash_table_lookup (pvc, property_name);
+		if (cached_value == NULL || !g_variant_equal (cached_value, value)) {
+			g_hash_table_insert (pvc, (gpointer) property_name, (gpointer) g_variant_ref (value));
+			g_variant_builder_add (builder, "{sv}", property_name, value);
+			has_changes = TRUE;
+		}
+	}
+
+	if (has_changes) {
+		g_dbus_connection_emit_signal (connection,
+					NULL,
+					path,
+					"org.freedesktop.DBus.Properties",
+					"PropertiesChanged",
+					g_variant_new ("(sa{sv}as)",
+							GDBUS_BOOK_VIEW_INTERFACE_NAME,
+							builder,
+							invalidated_builder),
+					NULL);
+	} else {
+		g_variant_builder_unref (builder);
+		g_variant_builder_unref (invalidated_builder);
+	}
+
+	g_hash_table_remove_all (notification_queue);
+	g_object_set_data (object, "gdbus-codegen-notification-idle-id", GUINT_TO_POINTER (0));
+	return FALSE;
+}
+
+/**
+ * e_gdbus_book_view_drain_notify:
+ * @object: A #EGdbusBookView that is exported.
+ *
+ * If @object has queued notifications, empty the queue forcing
+ * the <literal>PropertiesChanged</literal> signal to be emitted.
+ * See <xref linkend="EGdbusBookView.description"/> for more background information.
+ */
+void
+e_gdbus_book_view_drain_notify (EGdbusBookView *object)
+{
+	gint idle_id;
+	idle_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (object), "gdbus-codegen-notification-idle-id"));
+	if (idle_id > 0) {
+		emit_notifications_in_idle (object);
+		g_source_remove (idle_id);
+	}
+}
+
+static void
+on_object_unregistered (GObject *object)
+{
+	gint idle_id;
+	idle_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (object), "gdbus-codegen-notification-idle-id"));
+	if (idle_id > 0) {
+		g_source_remove (idle_id);
+	}
+	g_object_set_data (G_OBJECT (object), "gdbus-codegen-path", NULL);
+	g_object_set_data (G_OBJECT (object), "gdbus-codegen-connection", NULL);
+}
+
+/**
+ * e_gdbus_book_view_register_object:
+ * @object: An instance of a #GObject<!-- -->-derived type implementing the #EGdbusBookView interface.
+ * @connection: A #GDBusConnection.
+ * @object_path: The object to register the object at.
+ * @error: Return location for error or %NULL.
+ *
+ * Registers @object at @object_path on @connection.
+ *
+ * See <xref linkend="EGdbusBookView.description"/>
+ * for how properties, methods and signals are handled.
+ *
+ * Returns: 0 if @error is set, otherwise a registration id (never 0) that can be used with g_dbus_connection_unregister_object().
+ */
+guint
+e_gdbus_book_view_register_object (EGdbusBookView *object, GDBusConnection *connection, const gchar *object_path, GError **error)
+{
+	GHashTable *pvc;
+
+	pvc = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) g_variant_unref);
+
+	g_object_set_data_full (G_OBJECT (object), "gdbus-codegen-path", (gpointer) g_strdup (object_path), g_free);
+	g_object_set_data (G_OBJECT (object), "gdbus-codegen-connection", (gpointer) connection);
+	g_object_set_data_full (G_OBJECT (object), "gdbus-codegen-pvc", (gpointer) pvc, (GDestroyNotify) g_hash_table_unref);
+	return g_dbus_connection_register_object (connection,
+			object_path,
+			(GDBusInterfaceInfo *) &_e_gdbus_book_view_interface_info,
+			&e_gdbus_book_view_interface_vtable,
+			object,
+			(GDestroyNotify) on_object_unregistered,
+			error);
+}
+
+/**
+ * e_gdbus_book_view_interface_info:
+ *
+ * Gets interface description for the <literal>org.gnome.evolution.dataserver.AddressBookView</literal> D-Bus interface.
+ *
+ * Returns: A #GDBusInterfaceInfo. Do not free, the object is statically allocated.
+ */
+const GDBusInterfaceInfo *
+e_gdbus_book_view_interface_info (void)
+{
+	return &_e_gdbus_book_view_interface_info;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void proxy_iface_init (EGdbusBookViewIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (EGdbusBookViewProxy, e_gdbus_book_view_proxy, G_TYPE_DBUS_PROXY,
+                         G_IMPLEMENT_INTERFACE (E_TYPE_GDBUS_BOOK_VIEW, proxy_iface_init));
+
+static void
+e_gdbus_book_view_proxy_init (EGdbusBookViewProxy *proxy)
+{
+	g_dbus_proxy_set_interface_info (G_DBUS_PROXY (proxy), (GDBusInterfaceInfo *) &_e_gdbus_book_view_interface_info);
+}
+
+static void
+g_signal (GDBusProxy *proxy, const gchar *sender_name, const gchar *signal_name, GVariant *parameters)
+{
+	guint signal_id, signal_type;
+
+	signal_id = lookup_signal_id_from_signal_name (signal_name);
+	signal_type = lookup_signal_type_from_signal_name (signal_name);
+
+	g_return_if_fail (signal_id != 0);
+	g_return_if_fail (signal_type != 0);
+
+	e_gdbus_proxy_emit_signal (proxy, parameters, signals[signal_id], signal_type);
+}
+
+static void
+e_gdbus_book_view_proxy_class_init (EGdbusBookViewProxyClass *klass)
+{
+	GDBusProxyClass *proxy_class;
+
+	proxy_class = G_DBUS_PROXY_CLASS (klass);
+	proxy_class->g_signal = g_signal;
+}
+
+static void
+proxy_iface_init (EGdbusBookViewIface *iface)
+{
+}
+
+/**
+ * e_gdbus_book_view_proxy_new:
+ * @connection: A #GDBusConnection.
+ * @flags: Flags used when constructing the proxy.
+ * @name: A bus name (well-known or unique) or %NULL if @connection is not a message bus connection.
+ * @object_path: An object path.
+ * @cancellable: A #GCancellable or %NULL.
+ * @callback: Callback function to invoke when the proxy is ready.
+ * @user_data: User data to pass to @callback.
+ *
+ * Like g_dbus_proxy_new() but returns a #EGdbusBookViewProxy.
+ *
+ * This is a failable asynchronous constructor - when the proxy is ready, callback will be invoked and you can use e_gdbus_book_view_proxy_new_finish() to get the result.
+ */
+void
+e_gdbus_book_view_proxy_new (GDBusConnection *connection, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	g_async_initable_new_async (E_TYPE_GDBUS_BOOK_VIEW_PROXY,
+				G_PRIORITY_DEFAULT,
+				cancellable,
+				callback,
+				user_data,
+				"g-flags", flags,
+				"g-name", name,
+				"g-connection", connection,
+				"g-object-path", object_path,
+				"g-interface-name", GDBUS_BOOK_VIEW_INTERFACE_NAME,
+				NULL);
+}
+
+/**
+ * e_gdbus_book_view_proxy_new_finish:
+ * @result: A #GAsyncResult obtained from the #GAsyncReadyCallback function passed to e_gdbus_book_view_proxy_new().
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes creating a #EGdbusBookViewProxy.
+ *
+ * Returns: A #EGdbusBookViewProxy or %NULL if @error is set. Free with g_object_unref().
+ */
+EGdbusBookView *
+e_gdbus_book_view_proxy_new_finish (GAsyncResult  *result, GError **error)
+{
+	GObject *object;
+	GObject *source_object;
+	source_object = g_async_result_get_source_object (result);
+	g_assert (source_object != NULL);
+	object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), result, error);
+	g_object_unref (source_object);
+	if (object != NULL)
+		return E_GDBUS_BOOK_VIEW (object);
+	else
+		return NULL;
+}
+
+/**
+ * e_gdbus_book_view_proxy_new_sync:
+ * @connection: A #GDBusConnection.
+ * @flags: Flags used when constructing the proxy.
+ * @name: A bus name (well-known or unique) or %NULL if @connection is not a message bus connection.
+ * @object_path: An object path.
+ * @cancellable: A #GCancellable or %NULL.
+ * @error: Return location for error or %NULL.
+ *
+ * Like g_dbus_proxy_new_sync() but returns a #EGdbusBookViewProxy.
+ *
+ * This is a synchronous failable constructor. See e_gdbus_book_view_proxy_new() and e_gdbus_book_view_proxy_new_finish() for the asynchronous version.
+ *
+ * Returns: A #EGdbusBookViewProxy or %NULL if error is set. Free with g_object_unref().
+ */
+EGdbusBookView *
+e_gdbus_book_view_proxy_new_sync (GDBusConnection *connection, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GError **error)
+{
+	GInitable *initable;
+	initable = g_initable_new (E_TYPE_GDBUS_BOOK_VIEW_PROXY,
+				cancellable,
+				error,
+				"g-flags", flags,
+				"g-name", name,
+				"g-connection", connection,
+				"g-object-path", object_path,
+				"g-interface-name", GDBUS_BOOK_VIEW_INTERFACE_NAME,
+				NULL);
+	if (initable != NULL)
+		return E_GDBUS_BOOK_VIEW (initable);
+	else
+		return NULL;
+}
+
+/**
+ * e_gdbus_book_view_proxy_new_for_bus:
+ * @bus_type: A #GBusType.
+ * @flags: Flags used when constructing the proxy.
+ * @name: A bus name (well-known or unique).
+ * @object_path: An object path.
+ * @cancellable: A #GCancellable or %NULL.
+ * @callback: Callback function to invoke when the proxy is ready.
+ * @user_data: User data to pass to @callback.
+ *
+ * Like g_dbus_proxy_new_for_bus() but returns a #EGdbusBookViewProxy.
+ *
+ * This is a failable asynchronous constructor - when the proxy is ready, callback will be invoked and you can use e_gdbus_book_view_proxy_new_for_bus_finish() to get the result.
+ */
+void
+e_gdbus_book_view_proxy_new_for_bus (GBusType bus_type, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	g_async_initable_new_async (E_TYPE_GDBUS_BOOK_VIEW_PROXY,
+				G_PRIORITY_DEFAULT,
+				cancellable,
+				callback,
+				user_data,
+				"g-flags", flags,
+				"g-name", name,
+				"g-bus-type", bus_type,
+				"g-object-path", object_path,
+				"g-interface-name", GDBUS_BOOK_VIEW_INTERFACE_NAME,
+				NULL);
+}
+
+/**
+ * e_gdbus_book_view_proxy_new_for_bus_finish:
+ * @result: A #GAsyncResult obtained from the #GAsyncReadyCallback function passed to e_gdbus_book_view_proxy_new_for_bus().
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes creating a #EGdbusBookViewProxy.
+ *
+ * Returns: A #EGdbusBookViewProxy or %NULL if @error is set. Free with g_object_unref().
+ */
+EGdbusBookView *
+e_gdbus_book_view_proxy_new_for_bus_finish (GAsyncResult *result, GError **error)
+{
+	GObject *object;
+	GObject *source_object;
+	source_object = g_async_result_get_source_object (result);
+	g_assert (source_object != NULL);
+	object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), result, error);
+	g_object_unref (source_object);
+	if (object != NULL)
+		return E_GDBUS_BOOK_VIEW (object);
+	else
+		return NULL;
+}
+
+/**
+ * e_gdbus_book_view_proxy_new_for_bus_sync:
+ * @bus_type: A #GBusType.
+ * @flags: Flags used when constructing the proxy.
+ * @name: A bus name (well-known or unique).
+ * @object_path: An object path.
+ * @cancellable: A #GCancellable or %NULL.
+ * @error: Return location for error or %NULL.
+ *
+ * Like g_dbus_proxy_new_for_bus_sync() but returns a #EGdbusBookViewProxy.
+ *
+ * This is a synchronous failable constructor. See e_gdbus_book_view_proxy_new_for_bus() and e_gdbus_book_view_proxy_new_for_bus_finish() for the asynchronous version.
+ *
+ * Returns: A #EGdbusBookViewProxy or %NULL if error is set. Free with g_object_unref().
+ */
+EGdbusBookView *
+e_gdbus_book_view_proxy_new_for_bus_sync (GBusType bus_type, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GError **error)
+{
+	GInitable *initable;
+	initable = g_initable_new (E_TYPE_GDBUS_BOOK_VIEW_PROXY,
+				cancellable,
+				error,
+				"g-flags", flags,
+				"g-name", name,
+				"g-bus-type", bus_type,
+				"g-object-path", object_path,
+				"g-interface-name", GDBUS_BOOK_VIEW_INTERFACE_NAME,
+				NULL);
+	if (initable != NULL)
+		return E_GDBUS_BOOK_VIEW (initable);
+	else
+		return NULL;
+}
+
+/* ---------------------------------------------------------------------- */
+
+struct _EGdbusBookViewStubPrivate
+{
+	gint foo;
+};
+
+static void stub_iface_init (EGdbusBookViewIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (EGdbusBookViewStub, e_gdbus_book_view_stub, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (E_TYPE_GDBUS_BOOK_VIEW, stub_iface_init));
+
+static void
+e_gdbus_book_view_stub_init (EGdbusBookViewStub *stub)
+{
+	stub->priv = G_TYPE_INSTANCE_GET_PRIVATE (stub, E_TYPE_GDBUS_BOOK_VIEW_STUB, EGdbusBookViewStubPrivate);
+}
+
+static void
+e_gdbus_book_view_stub_class_init (EGdbusBookViewStubClass *klass)
+{
+	g_type_class_add_private (klass, sizeof (EGdbusBookViewStubPrivate));
+}
+
+static void
+stub_iface_init (EGdbusBookViewIface *iface)
+{
+}
+
+/**
+ * e_gdbus_book_view_stub_new:
+ *
+ * Creates a new stub object that can be exported via e_gdbus_book_view_register_object().
+ *
+ * Returns: A #EGdbusBookViewStub instance. Free with g_object_unref().
+ */
+EGdbusBookView *
+e_gdbus_book_view_stub_new (void)
+{
+	return E_GDBUS_BOOK_VIEW (g_object_new (E_TYPE_GDBUS_BOOK_VIEW_STUB, NULL));
+}
diff --git a/addressbook/libegdbus/e-gdbus-book-view.h b/addressbook/libegdbus/e-gdbus-book-view.h
new file mode 100644
index 0000000..3f750da
--- /dev/null
+++ b/addressbook/libegdbus/e-gdbus-book-view.h
@@ -0,0 +1,155 @@
+/*
+ * e-gdbus-book-view.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 2011 Red Hat, Inc. (www.redhat.com)
+ *
+ */
+
+#ifndef E_GDBUS_BOOK_VIEW_H
+#define E_GDBUS_BOOK_VIEW_H
+
+#include <gio/gio.h>
+
+#include <libedataserver/e-gdbus-templates.h>
+
+G_BEGIN_DECLS
+
+#define E_TYPE_GDBUS_BOOK_VIEW         (e_gdbus_book_view_get_type ())
+#define E_GDBUS_BOOK_VIEW(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_GDBUS_BOOK_VIEW, EGdbusBookView))
+#define E_IS_GDBUS_BOOK_VIEW(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_GDBUS_BOOK_VIEW))
+#define E_GDBUS_BOOK_VIEW_GET_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE((o), E_TYPE_GDBUS_BOOK_VIEW, EGdbusBookViewIface))
+
+/**
+ * EGdbusBookView:
+ *
+ * Opaque type representing a proxy or an exported object.
+ */
+typedef struct _EGdbusBookView EGdbusBookView; /* Dummy typedef */
+typedef struct _EGdbusBookViewIface EGdbusBookViewIface;
+
+GType e_gdbus_book_view_get_type (void) G_GNUC_CONST;
+
+/* ---------------------------------------------------------------------- */
+
+typedef struct _EGdbusBookViewProxy EGdbusBookViewProxy;
+typedef struct _EGdbusBookViewProxyClass EGdbusBookViewProxyClass;
+typedef struct _EGdbusBookViewProxyPrivate EGdbusBookViewProxyPrivate;
+
+struct _EGdbusBookViewProxy
+{
+	GDBusProxy parent_instance;
+	EGdbusBookViewProxyPrivate *priv;
+};
+
+struct _EGdbusBookViewProxyClass
+{
+	GDBusProxyClass parent_class;
+};
+
+#define E_TYPE_GDBUS_BOOK_VIEW_PROXY (e_gdbus_book_view_proxy_get_type ())
+GType e_gdbus_book_view_proxy_get_type (void) G_GNUC_CONST;
+
+void		e_gdbus_book_view_proxy_new (GDBusConnection *connection, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+EGdbusBookView *e_gdbus_book_view_proxy_new_finish (GAsyncResult  *result, GError **error);
+EGdbusBookView *e_gdbus_book_view_proxy_new_sync (GDBusConnection *connection, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_book_view_proxy_new_for_bus (GBusType bus_type, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+EGdbusBookView *e_gdbus_book_view_proxy_new_for_bus_finish (GAsyncResult  *result, GError **error);
+EGdbusBookView *e_gdbus_book_view_proxy_new_for_bus_sync (GBusType bus_type, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GError **error);
+
+/* ---------------------------------------------------------------------- */
+
+typedef struct _EGdbusBookViewStub EGdbusBookViewStub;
+typedef struct _EGdbusBookViewStubClass EGdbusBookViewStubClass;
+typedef struct _EGdbusBookViewStubPrivate EGdbusBookViewStubPrivate;
+
+struct _EGdbusBookViewStub
+{
+	GObject parent_instance;
+	EGdbusBookViewStubPrivate *priv;
+};
+
+struct _EGdbusBookViewStubClass
+{
+	GObjectClass parent_class;
+};
+
+#define E_TYPE_GDBUS_BOOK_VIEW_STUB (e_gdbus_book_view_stub_get_type ())
+GType e_gdbus_book_view_stub_get_type (void) G_GNUC_CONST;
+
+EGdbusBookView *e_gdbus_book_view_stub_new (void);
+
+guint e_gdbus_book_view_register_object (EGdbusBookView *object, GDBusConnection *connection, const gchar *object_path, GError **error);
+
+void e_gdbus_book_view_drain_notify (EGdbusBookView *object);
+
+const GDBusInterfaceInfo *e_gdbus_book_view_interface_info (void) G_GNUC_CONST;
+
+struct _EGdbusBookViewIface
+{
+	GTypeInterface parent_iface;
+
+	/* Signal handlers for receiving D-Bus signals: */
+	void (*objects_added)		(EGdbusBookView *object, const gchar * const *arg_objects);
+	void (*objects_modified)	(EGdbusBookView *object, const gchar * const *arg_objects);
+	void (*objects_removed)		(EGdbusBookView *object, const gchar * const *arg_uids);
+  
+	void (*progress)		(EGdbusBookView *object, guint arg_percent, const gchar *arg_message);
+	void (*complete)		(EGdbusBookView *object, const gchar * const *arg_error);
+
+	/* Signal handlers for handling D-Bus method calls: */
+	gboolean (*handle_start)		(EGdbusBookView *object, GDBusMethodInvocation *invocation);
+	gboolean (*handle_stop)			(EGdbusBookView *object, GDBusMethodInvocation *invocation);
+	gboolean (*handle_dispose)		(EGdbusBookView *object, GDBusMethodInvocation *invocation);
+	gboolean (*handle_set_fields_of_interest)(EGdbusBookView *object, GDBusMethodInvocation *invocation, const gchar * const *in_only_fields);
+};
+
+/* D-Bus Methods */
+void		e_gdbus_book_view_call_start		(GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_book_view_call_start_finish	(GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_book_view_call_start_sync	(GDBusProxy *proxy, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_book_view_call_stop		(GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_book_view_call_stop_finish	(GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_book_view_call_stop_sync	(GDBusProxy *proxy, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_book_view_call_dispose		(GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_book_view_call_dispose_finish	(GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_book_view_call_dispose_sync	(GDBusProxy *proxy, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_book_view_call_set_fields_of_interest		(GDBusProxy *proxy, const gchar * const *in_only_fileds, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_book_view_call_set_fields_of_interest_finish	(GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_book_view_call_set_fields_of_interest_sync	(GDBusProxy *proxy, const gchar * const *in_only_fileds, GCancellable *cancellable, GError **error);
+
+/* D-Bus Methods Completion Helpers */
+#define e_gdbus_book_view_complete_start			e_gdbus_complete_sync_method_void
+#define e_gdbus_book_view_complete_stop				e_gdbus_complete_sync_method_void
+#define e_gdbus_book_view_complete_dispose			e_gdbus_complete_sync_method_void
+#define e_gdbus_book_view_complete_set_fields_of_interest	e_gdbus_complete_sync_method_void
+
+
+/* D-Bus Signal Emission Helpers */
+void	e_gdbus_book_view_emit_objects_added	(EGdbusBookView *object, const gchar * const *arg_objects);
+void	e_gdbus_book_view_emit_objects_modified	(EGdbusBookView *object, const gchar * const *arg_objects);
+void	e_gdbus_book_view_emit_objects_removed	(EGdbusBookView *object, const gchar * const *arg_uids);
+
+void	e_gdbus_book_view_emit_progress		(EGdbusBookView *object, guint arg_percent, const gchar *arg_message);
+void	e_gdbus_book_view_emit_complete		(EGdbusBookView *object, const gchar * const *arg_error);
+
+G_END_DECLS
+
+#endif /* E_GDBUS_BOOK_VIEW_H */
diff --git a/addressbook/libegdbus/e-gdbus-book.c b/addressbook/libegdbus/e-gdbus-book.c
new file mode 100644
index 0000000..c6d2df5
--- /dev/null
+++ b/addressbook/libegdbus/e-gdbus-book.c
@@ -0,0 +1,1126 @@
+/*
+ * e-gdbus-book.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 2011 Red Hat, Inc. (www.redhat.com)
+ *
+ */
+
+#include <stdio.h>
+#include <gio/gio.h>
+
+#include <libedataserver/e-data-server-util.h>
+#include <libedataserver/e-gdbus-marshallers.h>
+
+#include "e-gdbus-book.h"
+
+#define GDBUS_BOOK_INTERFACE_NAME "org.gnome.evolution.dataserver.AddressBook"
+
+typedef EGdbusBookIface EGdbusBookInterface;
+G_DEFINE_INTERFACE (EGdbusBook, e_gdbus_book, G_TYPE_OBJECT);
+
+enum
+{
+	_0_SIGNAL,
+	__BACKEND_ERROR_SIGNAL,
+	__READONLY_SIGNAL,
+	__ONLINE_SIGNAL,
+	__AUTH_REQUIRED_SIGNAL,
+	__OPENED_SIGNAL,
+	__OPEN_METHOD,
+	__OPEN_DONE_SIGNAL,
+	__REMOVE_METHOD,
+	__REMOVE_DONE_SIGNAL,
+	__REFRESH_METHOD,
+	__REFRESH_DONE_SIGNAL,
+	__GET_CONTACT_METHOD,
+	__GET_CONTACT_DONE_SIGNAL,
+	__GET_CONTACT_LIST_METHOD,
+	__GET_CONTACT_LIST_DONE_SIGNAL,
+	__ADD_CONTACT_METHOD,
+	__ADD_CONTACT_DONE_SIGNAL,
+	__REMOVE_CONTACTS_METHOD,
+	__REMOVE_CONTACTS_DONE_SIGNAL,
+	__MODIFY_CONTACT_METHOD,
+	__MODIFY_CONTACT_DONE_SIGNAL,
+	__GET_BACKEND_PROPERTY_METHOD,
+	__GET_BACKEND_PROPERTY_DONE_SIGNAL,
+	__SET_BACKEND_PROPERTY_METHOD,
+	__SET_BACKEND_PROPERTY_DONE_SIGNAL,
+	__GET_VIEW_METHOD,
+	__GET_VIEW_DONE_SIGNAL,
+	__AUTHENTICATE_USER_METHOD,
+	__CANCEL_OPERATION_METHOD,
+	__CANCEL_ALL_METHOD,
+	__CLOSE_METHOD,
+	__LAST_SIGNAL
+};
+
+static guint signals[__LAST_SIGNAL] = {0};
+
+struct _EGdbusBookProxyPrivate
+{
+	GHashTable *pending_ops;
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Various lookup tables */
+
+static GHashTable *_method_name_to_id = NULL;
+static GHashTable *_method_name_to_type = NULL;
+static GHashTable *_signal_name_to_id = NULL;
+static GHashTable *_signal_name_to_type = NULL;
+
+static guint
+lookup_method_id_from_method_name (const gchar *method_name)
+{
+	return GPOINTER_TO_UINT (g_hash_table_lookup (_method_name_to_id, method_name));
+}
+
+static guint
+lookup_method_type_from_method_name (const gchar *method_name)
+{
+	return GPOINTER_TO_UINT (g_hash_table_lookup (_method_name_to_type, method_name));
+}
+
+static guint
+lookup_signal_id_from_signal_name (const gchar *signal_name)
+{
+	return GPOINTER_TO_UINT (g_hash_table_lookup (_signal_name_to_id, signal_name));
+}
+
+static guint
+lookup_signal_type_from_signal_name (const gchar *signal_name)
+{
+	return GPOINTER_TO_UINT (g_hash_table_lookup (_signal_name_to_type, signal_name));
+}
+
+/* ------------------------------------------------------------------------- */
+
+E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_STRING  (GDBUS_BOOK_INTERFACE_NAME, backend_error)
+E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_BOOLEAN (GDBUS_BOOK_INTERFACE_NAME, readonly)
+E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_BOOLEAN (GDBUS_BOOK_INTERFACE_NAME, online)
+E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_STRV    (GDBUS_BOOK_INTERFACE_NAME, auth_required)
+E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_STRV    (GDBUS_BOOK_INTERFACE_NAME, opened)
+
+E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_VOID	(GDBUS_BOOK_INTERFACE_NAME, open)
+E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_VOID	(GDBUS_BOOK_INTERFACE_NAME, remove)
+E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_VOID	(GDBUS_BOOK_INTERFACE_NAME, refresh)
+E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_STRING	(GDBUS_BOOK_INTERFACE_NAME, get_contact)
+E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_STRV	(GDBUS_BOOK_INTERFACE_NAME, get_contact_list)
+E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_STRING	(GDBUS_BOOK_INTERFACE_NAME, add_contact)
+E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_VOID	(GDBUS_BOOK_INTERFACE_NAME, remove_contacts)
+E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_VOID	(GDBUS_BOOK_INTERFACE_NAME, modify_contact)
+E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_STRING	(GDBUS_BOOK_INTERFACE_NAME, get_backend_property)
+E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_VOID	(GDBUS_BOOK_INTERFACE_NAME, set_backend_property)
+E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_STRING	(GDBUS_BOOK_INTERFACE_NAME, get_view)
+
+static void
+e_gdbus_book_default_init (EGdbusBookIface *iface)
+{
+	/* Build lookup structures */
+	_method_name_to_id = g_hash_table_new (g_str_hash, g_str_equal);
+	_method_name_to_type = g_hash_table_new (g_str_hash, g_str_equal);
+	_signal_name_to_id = g_hash_table_new (g_str_hash, g_str_equal);
+	_signal_name_to_type = g_hash_table_new (g_str_hash, g_str_equal);
+
+	/* GObject signals definitions for D-Bus signals: */
+	E_INIT_GDBUS_SIGNAL_STRING		(EGdbusBookIface, "backend_error",	backend_error,	__BACKEND_ERROR_SIGNAL)
+	E_INIT_GDBUS_SIGNAL_BOOLEAN		(EGdbusBookIface, "readonly",		readonly,	__READONLY_SIGNAL)
+	E_INIT_GDBUS_SIGNAL_BOOLEAN		(EGdbusBookIface, "online",		online,		__ONLINE_SIGNAL)
+	E_INIT_GDBUS_SIGNAL_STRV   		(EGdbusBookIface, "auth_required", 	auth_required,	__AUTH_REQUIRED_SIGNAL)
+	E_INIT_GDBUS_SIGNAL_STRV   		(EGdbusBookIface, "opened", 		opened,		__OPENED_SIGNAL)
+
+	/* GObject signals definitions for D-Bus methods: */
+	E_INIT_GDBUS_METHOD_ASYNC_BOOLEAN__VOID	(EGdbusBookIface, "open",			open, __OPEN_METHOD, __OPEN_DONE_SIGNAL)
+	E_INIT_GDBUS_METHOD_ASYNC_VOID__VOID	(EGdbusBookIface, "remove",			remove, __REMOVE_METHOD, __REMOVE_DONE_SIGNAL)
+	E_INIT_GDBUS_METHOD_ASYNC_VOID__VOID	(EGdbusBookIface, "refresh",			refresh, __REFRESH_METHOD, __REFRESH_DONE_SIGNAL)
+	E_INIT_GDBUS_METHOD_ASYNC_STRING__STRING(EGdbusBookIface, "getContact",			get_contact, __GET_CONTACT_METHOD, __GET_CONTACT_DONE_SIGNAL)
+	E_INIT_GDBUS_METHOD_ASYNC_STRING__STRV	(EGdbusBookIface, "getContactList",		get_contact_list, __GET_CONTACT_LIST_METHOD, __GET_CONTACT_LIST_DONE_SIGNAL)
+	E_INIT_GDBUS_METHOD_ASYNC_STRING__STRING(EGdbusBookIface, "addContact",			add_contact, __ADD_CONTACT_METHOD, __ADD_CONTACT_DONE_SIGNAL)
+	E_INIT_GDBUS_METHOD_ASYNC_STRV__VOID	(EGdbusBookIface, "removeContacts",		remove_contacts, __REMOVE_CONTACTS_METHOD, __REMOVE_CONTACTS_DONE_SIGNAL)
+	E_INIT_GDBUS_METHOD_ASYNC_STRING__VOID	(EGdbusBookIface, "modifyContact",		modify_contact, __MODIFY_CONTACT_METHOD, __MODIFY_CONTACT_DONE_SIGNAL)
+	E_INIT_GDBUS_METHOD_ASYNC_STRING__STRING(EGdbusBookIface, "getBackendProperty",		get_backend_property, __GET_BACKEND_PROPERTY_METHOD, __GET_BACKEND_PROPERTY_DONE_SIGNAL)
+	E_INIT_GDBUS_METHOD_ASYNC_STRV__VOID	(EGdbusBookIface, "setBackendProperty",		set_backend_property, __SET_BACKEND_PROPERTY_METHOD, __SET_BACKEND_PROPERTY_DONE_SIGNAL)
+	E_INIT_GDBUS_METHOD_ASYNC_STRING__STRING(EGdbusBookIface, "getView",			get_view, __GET_VIEW_METHOD, __GET_VIEW_DONE_SIGNAL)
+	E_INIT_GDBUS_METHOD_STRV		(EGdbusBookIface, "authenticateUser",		authenticate_user, __AUTHENTICATE_USER_METHOD)
+	E_INIT_GDBUS_METHOD_UINT		(EGdbusBookIface, "cancelOperation",		cancel_operation, __CANCEL_OPERATION_METHOD)
+	E_INIT_GDBUS_METHOD_VOID		(EGdbusBookIface, "cancelAll",			cancel_all, __CANCEL_ALL_METHOD)
+	E_INIT_GDBUS_METHOD_VOID		(EGdbusBookIface, "close",			close, __CLOSE_METHOD)
+}
+
+void
+e_gdbus_book_call_open (GDBusProxy *proxy, gboolean in_only_if_exists, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_call_boolean ("open", e_gdbus_book_call_open, E_GDBUS_ASYNC_OP_KEEPER (proxy), in_only_if_exists, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_book_call_open_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_finish_call_void (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, error, e_gdbus_book_call_open);
+}
+
+gboolean
+e_gdbus_book_call_open_sync (GDBusProxy *proxy, gboolean in_only_if_exists, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_call_sync_boolean__void (proxy, in_only_if_exists, cancellable, error,
+		e_gdbus_book_call_open,
+		e_gdbus_book_call_open_finish);
+}
+
+void
+e_gdbus_book_call_remove (GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_call_void ("remove", e_gdbus_book_call_remove, E_GDBUS_ASYNC_OP_KEEPER (proxy), cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_book_call_remove_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_finish_call_void (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, error, e_gdbus_book_call_remove);
+}
+
+gboolean
+e_gdbus_book_call_remove_sync (GDBusProxy *proxy, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_call_sync_void__void (proxy, cancellable, error,
+		e_gdbus_book_call_remove,
+		e_gdbus_book_call_remove_finish);
+}
+
+void
+e_gdbus_book_call_refresh (GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_call_void ("refresh", e_gdbus_book_call_refresh, E_GDBUS_ASYNC_OP_KEEPER (proxy), cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_book_call_refresh_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_finish_call_void (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, error, e_gdbus_book_call_refresh);
+}
+
+gboolean
+e_gdbus_book_call_refresh_sync (GDBusProxy *proxy, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_call_sync_void__void (proxy, cancellable, error,
+		e_gdbus_book_call_refresh,
+		e_gdbus_book_call_refresh_finish);
+}
+
+void
+e_gdbus_book_call_get_contact (GDBusProxy *proxy, const gchar *in_uid, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_call_string ("getContact", e_gdbus_book_call_get_contact, E_GDBUS_ASYNC_OP_KEEPER (proxy), in_uid, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_book_call_get_contact_finish (GDBusProxy *proxy, GAsyncResult *result, gchar **out_vcard, GError **error)
+{
+	return e_gdbus_proxy_finish_call_string (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, out_vcard, error, e_gdbus_book_call_get_contact);
+}
+
+gboolean
+e_gdbus_book_call_get_contact_sync (GDBusProxy *proxy, const gchar *in_uid, gchar **out_vcard, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_call_sync_string__string (proxy, in_uid, out_vcard, cancellable, error,
+		e_gdbus_book_call_get_contact,
+		e_gdbus_book_call_get_contact_finish);
+}
+
+void
+e_gdbus_book_call_get_contact_list (GDBusProxy *proxy, const gchar *in_query, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_call_string ("getContactList", e_gdbus_book_call_get_contact_list, E_GDBUS_ASYNC_OP_KEEPER (proxy), in_query, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_book_call_get_contact_list_finish (GDBusProxy *proxy, GAsyncResult *result, gchar ***out_vcards, GError **error)
+{
+	return e_gdbus_proxy_finish_call_strv (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, out_vcards, error, e_gdbus_book_call_get_contact_list);
+}
+
+gboolean
+e_gdbus_book_call_get_contact_list_sync (GDBusProxy *proxy, const gchar *in_query, gchar ***out_vcards, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_call_sync_string__strv (proxy, in_query, out_vcards, cancellable, error,
+		e_gdbus_book_call_get_contact_list,
+		e_gdbus_book_call_get_contact_list_finish);
+}
+
+void
+e_gdbus_book_call_add_contact (GDBusProxy *proxy, const gchar *in_vcard, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_call_string ("addContact", e_gdbus_book_call_add_contact, E_GDBUS_ASYNC_OP_KEEPER (proxy), in_vcard, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_book_call_add_contact_finish (GDBusProxy *proxy, GAsyncResult *result, gchar **out_uid, GError **error)
+{
+	return e_gdbus_proxy_finish_call_string (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, out_uid, error, e_gdbus_book_call_add_contact);
+}
+
+gboolean
+e_gdbus_book_call_add_contact_sync (GDBusProxy *proxy, const gchar *in_vcard, gchar **out_uid, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_call_sync_string__string (proxy, in_vcard, out_uid, cancellable, error,
+		e_gdbus_book_call_add_contact,
+		e_gdbus_book_call_add_contact_finish);
+}
+
+void
+e_gdbus_book_call_remove_contacts (GDBusProxy *proxy, const gchar * const *in_list, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_call_strv ("removeContacts", e_gdbus_book_call_remove_contacts, E_GDBUS_ASYNC_OP_KEEPER (proxy), in_list, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_book_call_remove_contacts_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_finish_call_void (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, error, e_gdbus_book_call_remove_contacts);
+}
+
+gboolean
+e_gdbus_book_call_remove_contacts_sync (GDBusProxy *proxy, const gchar * const *in_list, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_call_sync_strv__void (proxy, in_list, cancellable, error,
+		e_gdbus_book_call_remove_contacts,
+		e_gdbus_book_call_remove_contacts_finish);
+}
+
+void
+e_gdbus_book_call_modify_contact (GDBusProxy *proxy, const gchar *in_vcard, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_call_string ("modifyContact", e_gdbus_book_call_modify_contact, E_GDBUS_ASYNC_OP_KEEPER (proxy), in_vcard, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_book_call_modify_contact_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_finish_call_void (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, error, e_gdbus_book_call_modify_contact);
+}
+
+gboolean
+e_gdbus_book_call_modify_contact_sync (GDBusProxy *proxy, const gchar *in_vcard, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_call_sync_string__void (proxy, in_vcard, cancellable, error,
+		e_gdbus_book_call_modify_contact,
+		e_gdbus_book_call_modify_contact_finish);
+}
+
+void
+e_gdbus_book_call_get_backend_property (GDBusProxy *proxy, const gchar *in_prop_name, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_call_string ("getBackendProperty", e_gdbus_book_call_get_backend_property, E_GDBUS_ASYNC_OP_KEEPER (proxy), in_prop_name, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_book_call_get_backend_property_finish (GDBusProxy *proxy, GAsyncResult *result, gchar **out_prop_value, GError **error)
+{
+	return e_gdbus_proxy_finish_call_string (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, out_prop_value, error, e_gdbus_book_call_get_backend_property);
+}
+
+gboolean
+e_gdbus_book_call_get_backend_property_sync (GDBusProxy *proxy, const gchar *in_prop_name, gchar **out_prop_value, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_call_sync_string__string (proxy, in_prop_name, out_prop_value, cancellable, error,
+		e_gdbus_book_call_get_backend_property,
+		e_gdbus_book_call_get_backend_property_finish);
+}
+
+/* free returned pointer with g_strfreev() */
+gchar **
+e_gdbus_book_encode_set_backend_property (const gchar *in_prop_name, const gchar *in_prop_value)
+{
+	gchar **strv;
+
+	strv = g_new0 (gchar *, 3);
+	strv[0] = e_util_utf8_make_valid (in_prop_name ? in_prop_name : "");
+	strv[1] = e_util_utf8_make_valid (in_prop_value ? in_prop_value : "");
+	strv[2] = NULL;
+
+	return strv;
+}
+
+/* free out_prop_name and out_prop_value with g_free() */
+gboolean
+e_gdbus_book_decode_set_backend_property (const gchar * const *in_strv, gchar **out_prop_name, gchar **out_prop_value)
+{
+	g_return_val_if_fail (in_strv != NULL, FALSE);
+	g_return_val_if_fail (in_strv[0] != NULL, FALSE);
+	g_return_val_if_fail (in_strv[1] != NULL, FALSE);
+	g_return_val_if_fail (in_strv[2] == NULL, FALSE);
+	g_return_val_if_fail (out_prop_name != NULL, FALSE);
+	g_return_val_if_fail (out_prop_value != NULL, FALSE);
+
+	*out_prop_name = g_strdup (in_strv[0]);
+	*out_prop_value = g_strdup (in_strv[1]);
+
+	return TRUE;
+}
+
+void
+e_gdbus_book_call_set_backend_property (GDBusProxy *proxy, const gchar * const *in_prop_name_value, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_call_strv ("setBackendProperty", e_gdbus_book_call_set_backend_property, E_GDBUS_ASYNC_OP_KEEPER (proxy), in_prop_name_value, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_book_call_set_backend_property_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_finish_call_void (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, error, e_gdbus_book_call_set_backend_property);
+}
+
+gboolean
+e_gdbus_book_call_set_backend_property_sync (GDBusProxy *proxy, const gchar * const *in_prop_name_value, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_call_sync_strv__void (proxy, in_prop_name_value, cancellable, error,
+		e_gdbus_book_call_set_backend_property,
+		e_gdbus_book_call_set_backend_property_finish);
+}
+
+void
+e_gdbus_book_call_get_view (GDBusProxy *proxy, const gchar *in_query, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_call_string ("getView", e_gdbus_book_call_get_view, E_GDBUS_ASYNC_OP_KEEPER (proxy), in_query, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_book_call_get_view_finish (GDBusProxy *proxy, GAsyncResult *result, gchar **out_view_path, GError **error)
+{
+	return e_gdbus_proxy_finish_call_string (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, out_view_path, error, e_gdbus_book_call_get_view);
+}
+
+gboolean
+e_gdbus_book_call_get_view_sync (GDBusProxy *proxy, const gchar *in_query, gchar **out_view_path, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_call_sync_string__string (proxy, in_query, out_view_path, cancellable, error,
+		e_gdbus_book_call_get_view,
+		e_gdbus_book_call_get_view_finish);
+}
+
+void
+e_gdbus_book_call_authenticate_user (GDBusProxy *proxy, const gchar * const *in_credentials, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_method_call_strv ("authenticateUser", proxy, in_credentials, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_book_call_authenticate_user_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_method_call_finish_void (proxy, result, error);
+}
+
+gboolean
+e_gdbus_book_call_authenticate_user_sync (GDBusProxy *proxy, const gchar * const *in_credentials, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_method_call_sync_strv__void ("authenticateUser", proxy, in_credentials, cancellable, error);
+}
+
+void
+e_gdbus_book_call_cancel_operation (GDBusProxy *proxy, guint in_opid, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_method_call_uint ("cancelOperation", proxy, in_opid, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_book_call_cancel_operation_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_method_call_finish_void (proxy, result, error);
+}
+
+gboolean
+e_gdbus_book_call_cancel_operation_sync (GDBusProxy *proxy, guint in_opid, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_method_call_sync_uint__void ("cancelOperation", proxy, in_opid, cancellable, error);
+}
+
+void
+e_gdbus_book_call_cancel_all (GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_method_call_void ("cancelAll", proxy, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_book_call_cancel_all_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_method_call_finish_void (proxy, result, error);
+}
+
+gboolean
+e_gdbus_book_call_cancel_all_sync (GDBusProxy *proxy, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_method_call_sync_void__void ("cancelAll", proxy, cancellable, error);
+}
+
+void
+e_gdbus_book_call_close (GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_method_call_void ("close", proxy, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_book_call_close_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_method_call_finish_void (proxy, result, error);
+}
+
+gboolean
+e_gdbus_book_call_close_sync (GDBusProxy *proxy, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_method_call_sync_void__void ("close", proxy, cancellable, error);
+}
+
+#define DECLARE_EMIT_DONE_SIGNAL_0(_mname, _sig_id)									\
+void															\
+e_gdbus_book_emit_ ## _mname ## _done (EGdbusBook *object, guint arg_opid, const GError *arg_error)			\
+{															\
+	g_signal_emit (object, signals[_sig_id], 0, arg_opid, arg_error);						\
+}
+
+#define DECLARE_EMIT_DONE_SIGNAL_1(_mname, _sig_id, _par_type)								\
+void															\
+e_gdbus_book_emit_ ## _mname ## _done (EGdbusBook *object, guint arg_opid, const GError *arg_error, _par_type out_par)	\
+{															\
+	g_signal_emit (object, signals[_sig_id], 0, arg_opid, arg_error, out_par);					\
+}
+
+DECLARE_EMIT_DONE_SIGNAL_0 (open,			__OPEN_DONE_SIGNAL)
+DECLARE_EMIT_DONE_SIGNAL_0 (remove,			__REMOVE_DONE_SIGNAL)
+DECLARE_EMIT_DONE_SIGNAL_0 (refresh,			__REFRESH_DONE_SIGNAL)
+DECLARE_EMIT_DONE_SIGNAL_1 (get_contact,		__GET_CONTACT_DONE_SIGNAL, const gchar *)
+DECLARE_EMIT_DONE_SIGNAL_1 (get_contact_list,		__GET_CONTACT_LIST_DONE_SIGNAL, const gchar * const *)
+DECLARE_EMIT_DONE_SIGNAL_1 (add_contact,		__ADD_CONTACT_DONE_SIGNAL, const gchar *)
+DECLARE_EMIT_DONE_SIGNAL_0 (remove_contacts,		__REMOVE_CONTACTS_DONE_SIGNAL)
+DECLARE_EMIT_DONE_SIGNAL_0 (modify_contact,		__MODIFY_CONTACT_DONE_SIGNAL)
+DECLARE_EMIT_DONE_SIGNAL_1 (get_backend_property,	__GET_BACKEND_PROPERTY_DONE_SIGNAL, const gchar *)
+DECLARE_EMIT_DONE_SIGNAL_0 (set_backend_property,	__SET_BACKEND_PROPERTY_DONE_SIGNAL)
+DECLARE_EMIT_DONE_SIGNAL_1 (get_view,			__GET_VIEW_DONE_SIGNAL, const gchar *)
+
+void
+e_gdbus_book_emit_backend_error (EGdbusBook *object, const gchar *arg_message)
+{
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (arg_message != NULL);
+
+	g_signal_emit (object, signals[__BACKEND_ERROR_SIGNAL], 0, arg_message);
+}
+
+void
+e_gdbus_book_emit_readonly (EGdbusBook *object, gboolean arg_is_readonly)
+{
+	g_signal_emit (object, signals[__READONLY_SIGNAL], 0, arg_is_readonly);
+}
+
+void
+e_gdbus_book_emit_online (EGdbusBook *object, gboolean arg_is_online)
+{
+	g_signal_emit (object, signals[__ONLINE_SIGNAL], 0, arg_is_online);
+}
+
+void
+e_gdbus_book_emit_auth_required (EGdbusBook *object, const gchar * const *arg_credentials)
+{
+	g_signal_emit (object, signals[__AUTH_REQUIRED_SIGNAL], 0, arg_credentials);
+}
+
+void
+e_gdbus_book_emit_opened (EGdbusBook *object, const gchar * const *arg_error)
+{
+	g_signal_emit (object, signals[__OPENED_SIGNAL], 0, arg_error);
+}
+
+E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (book, backend_error, message, "s")
+E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (book, readonly, is_readonly, "b")
+E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (book, online, is_online, "b")
+E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (book, auth_required, credentials, "as")
+E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (book, opened, error, "as")
+
+E_DECLARE_GDBUS_ASYNC_METHOD_1			(book, open, only_if_exists, "b")
+E_DECLARE_GDBUS_ASYNC_METHOD_0			(book, remove)
+E_DECLARE_GDBUS_ASYNC_METHOD_0			(book, refresh)
+E_DECLARE_GDBUS_ASYNC_METHOD_1_WITH_RETURN	(book, getContact, uid, "s", vcard, "s")
+E_DECLARE_GDBUS_ASYNC_METHOD_1_WITH_RETURN	(book, getContactList, query, "s", vcards, "as")
+E_DECLARE_GDBUS_ASYNC_METHOD_1_WITH_RETURN	(book, addContact, vcard, "s", uid, "s")
+E_DECLARE_GDBUS_ASYNC_METHOD_1			(book, removeContacts, list, "as")
+E_DECLARE_GDBUS_ASYNC_METHOD_1			(book, modifyContact, vcard, "s")
+E_DECLARE_GDBUS_ASYNC_METHOD_1_WITH_RETURN	(book, getBackendProperty, prop_name, "s", prop_value, "s")
+E_DECLARE_GDBUS_ASYNC_METHOD_1			(book, setBackendProperty, prop_name_value, "as")
+E_DECLARE_GDBUS_ASYNC_METHOD_1_WITH_RETURN	(book, getView, query, "s", view, "s")
+
+E_DECLARE_GDBUS_SYNC_METHOD_1			(book, authenticateUser, credentials, "as")
+E_DECLARE_GDBUS_SYNC_METHOD_1			(book, cancelOperation, opid, "u")
+E_DECLARE_GDBUS_SYNC_METHOD_0			(book, cancelAll)
+E_DECLARE_GDBUS_SYNC_METHOD_0			(book, close)
+
+static const GDBusMethodInfo * const e_gdbus_book_method_info_pointers[] =
+{
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book, open),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book, remove),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book, refresh),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book, getContact),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book, getContactList),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book, addContact),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book, removeContacts),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book, modifyContact),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book, getBackendProperty),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book, setBackendProperty),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book, getView),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book, authenticateUser),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book, cancelOperation),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book, cancelAll),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (book, close),
+	NULL
+};
+
+static const GDBusSignalInfo * const e_gdbus_book_signal_info_pointers[] =
+{
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book, backend_error),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book, readonly),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book, online),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book, auth_required),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book, opened),
+
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book, open_done),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book, remove_done),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book, refresh_done),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book, getContact_done),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book, getContactList_done),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book, addContact_done),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book, removeContacts_done),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book, modifyContact_done),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book, getBackendProperty_done),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book, setBackendProperty_done),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (book, getView_done),
+	NULL
+};
+
+static const GDBusInterfaceInfo _e_gdbus_book_interface_info =
+{
+	-1,
+	(gchar *) GDBUS_BOOK_INTERFACE_NAME,
+	(GDBusMethodInfo **) &e_gdbus_book_method_info_pointers,
+	(GDBusSignalInfo **) &e_gdbus_book_signal_info_pointers,
+	(GDBusPropertyInfo **) NULL
+};
+
+static void
+handle_method_call (GDBusConnection       *connection,
+                    const gchar           *sender,
+                    const gchar           *object_path,
+                    const gchar           *interface_name,
+                    const gchar           *method_name,
+                    GVariant              *parameters,
+                    GDBusMethodInvocation *invocation,
+                    gpointer               user_data)
+{
+	guint method_id, method_type;
+
+	method_id = lookup_method_id_from_method_name (method_name);
+	method_type = lookup_method_type_from_method_name (method_name);
+
+	g_return_if_fail (method_id != 0);
+	g_return_if_fail (method_type != 0);
+
+	e_gdbus_stub_handle_method_call (user_data, invocation, parameters, method_name, signals[method_id], method_type);
+}
+
+static GVariant *
+get_property (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *property_name, GError **error, gpointer user_data)
+{
+	g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "This implementation does not support property `%s'", property_name);
+	return NULL;
+}
+
+static gboolean
+set_property (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *property_name, GVariant *value, GError **error, gpointer user_data)
+{
+	g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "This implementation does not support property `%s'", property_name);
+	return FALSE;
+}
+
+static const GDBusInterfaceVTable e_gdbus_book_interface_vtable =
+{
+	handle_method_call,
+	get_property,
+	set_property
+};
+
+static gboolean
+emit_notifications_in_idle (gpointer user_data)
+{
+	GObject *object = G_OBJECT (user_data);
+	GDBusConnection *connection;
+	const gchar *path;
+	GHashTable *notification_queue;
+	GHashTableIter iter;
+	const gchar *property_name;
+	GVariant *value;
+	GVariantBuilder *builder;
+	GVariantBuilder *invalidated_builder;
+	GHashTable *pvc;
+	gboolean has_changes;
+
+	notification_queue = g_object_get_data (object, "gdbus-codegen-notification-queue");
+	path = g_object_get_data (object, "gdbus-codegen-path");
+	connection = g_object_get_data (object, "gdbus-codegen-connection");
+	pvc = g_object_get_data (object, "gdbus-codegen-pvc");
+	g_assert (notification_queue != NULL && path != NULL && connection != NULL && pvc != NULL);
+
+	builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
+	invalidated_builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
+	g_hash_table_iter_init (&iter, notification_queue);
+	has_changes = FALSE;
+	while (g_hash_table_iter_next (&iter, (gpointer) &property_name, (gpointer) &value)) {
+		GVariant *cached_value;
+		cached_value = g_hash_table_lookup (pvc, property_name);
+		if (cached_value == NULL || !g_variant_equal (cached_value, value)) {
+			g_hash_table_insert (pvc, (gpointer) property_name, (gpointer) g_variant_ref (value));
+			g_variant_builder_add (builder, "{sv}", property_name, value);
+			has_changes = TRUE;
+		}
+	}
+
+	if (has_changes) {
+		g_dbus_connection_emit_signal (connection, NULL, path, "org.freedesktop.DBus.Properties", "PropertiesChanged",
+			g_variant_new ("(sa{sv}as)", GDBUS_BOOK_INTERFACE_NAME, builder, invalidated_builder),
+			NULL);
+	} else {
+		g_variant_builder_unref (builder);
+		g_variant_builder_unref (invalidated_builder);
+	}
+
+	g_hash_table_remove_all (notification_queue);
+	g_object_set_data (object, "gdbus-codegen-notification-idle-id", GUINT_TO_POINTER (0));
+
+	return FALSE;
+}
+
+/**
+ * e_gdbus_book_drain_notify:
+ * @object: A #EGdbusBook that is exported.
+ *
+ * If @object has queued notifications, empty the queue forcing
+ * the <literal>PropertiesChanged</literal> signal to be emitted.
+ * See <xref linkend="EGdbusBook.description"/> for more background information.
+ */
+void
+e_gdbus_book_drain_notify (EGdbusBook *object)
+{
+	gint idle_id;
+	idle_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (object), "gdbus-codegen-notification-idle-id"));
+	if (idle_id > 0) {
+		emit_notifications_in_idle (object);
+		g_source_remove (idle_id);
+	}
+}
+
+static void
+on_object_unregistered (GObject *object)
+{
+	gint idle_id;
+	idle_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (object), "gdbus-codegen-notification-idle-id"));
+	if (idle_id > 0) {
+		g_source_remove (idle_id);
+	}
+	g_object_set_data (G_OBJECT (object), "gdbus-codegen-path", NULL);
+	g_object_set_data (G_OBJECT (object), "gdbus-codegen-connection", NULL);
+}
+
+/**
+ * e_gdbus_book_register_object:
+ * @object: An instance of a #GObject<!-- -->-derived type implementing the #EGdbusBook interface.
+ * @connection: A #GDBusConnection.
+ * @object_path: The object to register the object at.
+ * @error: Return location for error or %NULL.
+ *
+ * Registers @object at @object_path on @connection.
+ *
+ * See <xref linkend="EGdbusBook.description"/>
+ * for how properties, methods and signals are handled.
+ *
+ * Returns: 0 if @error is set, otherwise a registration id (never 0) that can be used with g_dbus_connection_unregister_object().
+ */
+guint
+e_gdbus_book_register_object (EGdbusBook *object, GDBusConnection *connection, const gchar *object_path, GError **error)
+{
+	GHashTable *pvc;
+
+	pvc = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) g_variant_unref);
+
+	g_object_set_data_full (G_OBJECT (object), "gdbus-codegen-path", (gpointer) g_strdup (object_path), g_free);
+	g_object_set_data (G_OBJECT (object), "gdbus-codegen-connection", (gpointer) connection);
+	g_object_set_data_full (G_OBJECT (object), "gdbus-codegen-pvc", (gpointer) pvc, (GDestroyNotify) g_hash_table_unref);
+	
+	return g_dbus_connection_register_object (connection, object_path, (GDBusInterfaceInfo *) &_e_gdbus_book_interface_info,
+			&e_gdbus_book_interface_vtable, object, (GDestroyNotify) on_object_unregistered, error);
+}
+
+/**
+ * e_gdbus_book_interface_info:
+ *
+ * Gets interface description for the <literal>org.gnome.evolution.dataserver.AddressBook</literal> D-Bus interface.
+ *
+ * Returns: A #GDBusInterfaceInfo. Do not free, the object is statically allocated.
+ */
+const GDBusInterfaceInfo *
+e_gdbus_book_interface_info (void)
+{
+	return &_e_gdbus_book_interface_info;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void proxy_iface_init (EGdbusBookIface *iface);
+static void async_op_keeper_iface_init (EGdbusAsyncOpKeeperInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (EGdbusBookProxy, e_gdbus_book_proxy, G_TYPE_DBUS_PROXY,
+                         G_IMPLEMENT_INTERFACE (E_TYPE_GDBUS_BOOK, proxy_iface_init)
+			 G_IMPLEMENT_INTERFACE (E_TYPE_GDBUS_ASYNC_OP_KEEPER, async_op_keeper_iface_init));
+
+static void
+e_gdbus_book_proxy_init (EGdbusBookProxy *proxy)
+{
+	g_dbus_proxy_set_interface_info (G_DBUS_PROXY (proxy), (GDBusInterfaceInfo *) &_e_gdbus_book_interface_info);
+
+	proxy->priv = G_TYPE_INSTANCE_GET_PRIVATE (proxy, E_TYPE_GDBUS_BOOK_PROXY, EGdbusBookProxyPrivate);
+	proxy->priv->pending_ops = e_gdbus_async_op_keeper_create_pending_ops (E_GDBUS_ASYNC_OP_KEEPER (proxy));
+
+	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_VOID   (open);
+	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_VOID   (remove);
+	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_VOID   (refresh);
+	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_STRING (get_contact);
+	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_STRV   (get_contact_list);
+	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_STRING (add_contact);
+	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_VOID   (remove_contacts);
+	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_VOID   (modify_contact);
+	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_STRING (get_backend_property);
+	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_VOID	  (set_backend_property);
+	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_STRING (get_view);
+}
+
+static void
+g_signal (GDBusProxy *proxy, const gchar *sender_name, const gchar *signal_name, GVariant *parameters)
+{
+	guint signal_id, signal_type;
+
+	signal_id = lookup_signal_id_from_signal_name (signal_name);
+	signal_type = lookup_signal_type_from_signal_name (signal_name);
+
+	g_return_if_fail (signal_id != 0);
+	g_return_if_fail (signal_type != 0);
+
+	e_gdbus_proxy_emit_signal (proxy, parameters, signals[signal_id], signal_type);
+}
+
+static void
+gdbus_book_proxy_finalize (GObject *object)
+{
+	EGdbusBookProxy *proxy = E_GDBUS_BOOK_PROXY (object);
+
+	g_return_if_fail (proxy != NULL);
+	g_return_if_fail (proxy->priv != NULL);
+
+	if (g_hash_table_size (proxy->priv->pending_ops))
+		g_debug ("%s: Kept %d items in pending_ops", G_STRFUNC, g_hash_table_size (proxy->priv->pending_ops));
+
+	g_hash_table_destroy (proxy->priv->pending_ops);
+
+	G_OBJECT_CLASS (e_gdbus_book_proxy_parent_class)->finalize (object);
+}
+
+static void
+e_gdbus_book_proxy_class_init (EGdbusBookProxyClass *klass)
+{
+	GObjectClass *object_class;
+	GDBusProxyClass *proxy_class;
+
+	g_type_class_add_private (klass, sizeof (EGdbusBookProxyPrivate));
+
+	object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = gdbus_book_proxy_finalize;
+
+	proxy_class = G_DBUS_PROXY_CLASS (klass);
+	proxy_class->g_signal = g_signal;
+}
+
+static void
+proxy_iface_init (EGdbusBookIface *iface)
+{
+}
+
+static GHashTable *
+gdbus_book_get_pending_ops (EGdbusAsyncOpKeeper *object)
+{
+	EGdbusBookProxy *proxy;
+
+	g_return_val_if_fail (object != NULL, NULL);
+	g_return_val_if_fail (E_IS_GDBUS_BOOK_PROXY (object), NULL);
+
+	proxy = E_GDBUS_BOOK_PROXY (object);
+	g_return_val_if_fail (proxy != NULL, NULL);
+	g_return_val_if_fail (proxy->priv != NULL, NULL);
+
+	return proxy->priv->pending_ops;
+}
+
+static gboolean
+gdbus_book_call_cancel_operation_sync (EGdbusAsyncOpKeeper *object, guint in_opid, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_book_call_cancel_operation_sync (G_DBUS_PROXY (object), in_opid, cancellable, error);
+}
+
+static void
+async_op_keeper_iface_init (EGdbusAsyncOpKeeperInterface *iface)
+{
+	g_return_if_fail (iface != NULL);
+
+	iface->get_pending_ops = gdbus_book_get_pending_ops;
+	iface->cancel_op_sync = gdbus_book_call_cancel_operation_sync;
+}
+
+/**
+ * e_gdbus_book_proxy_new:
+ * @connection: A #GDBusConnection.
+ * @flags: Flags used when constructing the proxy.
+ * @name: A bus name (well-known or unique) or %NULL if @connection is not a message bus connection.
+ * @object_path: An object path.
+ * @cancellable: A #GCancellable or %NULL.
+ * @callback: Callback function to invoke when the proxy is ready.
+ * @user_data: User data to pass to @callback.
+ *
+ * Like g_dbus_proxy_new() but returns a #EGdbusBookProxy.
+ *
+ * This is a failable asynchronous constructor - when the proxy is ready, callback will be invoked and you can use e_gdbus_book_proxy_new_finish() to get the result.
+ */
+void
+e_gdbus_book_proxy_new (GDBusConnection *connection, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	g_async_initable_new_async (E_TYPE_GDBUS_BOOK_PROXY,
+				G_PRIORITY_DEFAULT,
+				cancellable,
+				callback,
+				user_data,
+				"g-flags", flags,
+				"g-name", name,
+				"g-connection", connection,
+				"g-object-path", object_path,
+				"g-interface-name", GDBUS_BOOK_INTERFACE_NAME,
+				NULL);
+}
+
+/**
+ * e_gdbus_book_proxy_new_finish:
+ * @result: A #GAsyncResult obtained from the #GAsyncReadyCallback function passed to e_gdbus_book_proxy_new().
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes creating a #EGdbusBookProxy.
+ *
+ * Returns: A #EGdbusBookProxy or %NULL if @error is set. Free with g_object_unref().
+ */
+EGdbusBook *
+e_gdbus_book_proxy_new_finish (GAsyncResult *result, GError **error)
+{
+	GObject *object;
+	GObject *source_object;
+	source_object = g_async_result_get_source_object (result);
+	g_assert (source_object != NULL);
+	object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), result, error);
+	g_object_unref (source_object);
+
+	if (object != NULL)
+		return E_GDBUS_BOOK (object);
+	else
+		return NULL;
+}
+
+/**
+ * e_gdbus_book_proxy_new_sync:
+ * @connection: A #GDBusConnection.
+ * @flags: Flags used when constructing the proxy.
+ * @name: A bus name (well-known or unique) or %NULL if @connection is not a message bus connection.
+ * @object_path: An object path.
+ * @cancellable: A #GCancellable or %NULL.
+ * @error: Return location for error or %NULL.
+ *
+ * Like g_dbus_proxy_new_sync() but returns a #EGdbusBookProxy.
+ *
+ * This is a synchronous failable constructor. See e_gdbus_book_proxy_new() and e_gdbus_book_proxy_new_finish() for the asynchronous version.
+ *
+ * Returns: A #EGdbusBookProxy or %NULL if error is set. Free with g_object_unref().
+ */
+EGdbusBook *
+e_gdbus_book_proxy_new_sync (GDBusConnection *connection, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GError **error)
+{
+	GInitable *initable;
+	initable = g_initable_new (E_TYPE_GDBUS_BOOK_PROXY,
+				cancellable,
+				error,
+				"g-flags", flags,
+				"g-name", name,
+				"g-connection", connection,
+				"g-object-path", object_path,
+				"g-interface-name", GDBUS_BOOK_INTERFACE_NAME,
+				NULL);
+	if (initable != NULL)
+		return E_GDBUS_BOOK (initable);
+	else
+		return NULL;
+}
+
+/**
+ * e_gdbus_book_proxy_new_for_bus:
+ * @bus_type: A #GBusType.
+ * @flags: Flags used when constructing the proxy.
+ * @name: A bus name (well-known or unique).
+ * @object_path: An object path.
+ * @cancellable: A #GCancellable or %NULL.
+ * @callback: Callback function to invoke when the proxy is ready.
+ * @user_data: User data to pass to @callback.
+ *
+ * Like g_dbus_proxy_new_for_bus() but returns a #EGdbusBookProxy.
+ *
+ * This is a failable asynchronous constructor - when the proxy is ready, callback will be invoked and you can use e_gdbus_book_proxy_new_for_bus_finish() to get the result.
+ */
+void
+e_gdbus_book_proxy_new_for_bus (GBusType bus_type, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	g_async_initable_new_async (E_TYPE_GDBUS_BOOK_PROXY,
+				G_PRIORITY_DEFAULT,
+				cancellable,
+				callback,
+				user_data,
+				"g-flags", flags,
+				"g-name", name,
+				"g-bus-type", bus_type,
+				"g-object-path", object_path,
+				"g-interface-name", GDBUS_BOOK_INTERFACE_NAME,
+				NULL);
+}
+
+/**
+ * e_gdbus_book_proxy_new_for_bus_finish:
+ * @result: A #GAsyncResult obtained from the #GAsyncReadyCallback function passed to e_gdbus_book_proxy_new_for_bus().
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes creating a #EGdbusBookProxy.
+ *
+ * Returns: A #EGdbusBookProxy or %NULL if @error is set. Free with g_object_unref().
+ */
+EGdbusBook *
+e_gdbus_book_proxy_new_for_bus_finish (GAsyncResult *result, GError **error)
+{
+	GObject *object;
+	GObject *source_object;
+	source_object = g_async_result_get_source_object (result);
+	g_assert (source_object != NULL);
+	object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), result, error);
+	g_object_unref (source_object);
+
+	if (object != NULL)
+		return E_GDBUS_BOOK (object);
+	else
+		return NULL;
+}
+
+/**
+ * e_gdbus_book_proxy_new_for_bus_sync:
+ * @bus_type: A #GBusType.
+ * @flags: Flags used when constructing the proxy.
+ * @name: A bus name (well-known or unique).
+ * @object_path: An object path.
+ * @cancellable: A #GCancellable or %NULL.
+ * @error: Return location for error or %NULL.
+ *
+ * Like g_dbus_proxy_new_for_bus_sync() but returns a #EGdbusBookProxy.
+ *
+ * This is a synchronous failable constructor. See e_gdbus_book_proxy_new_for_bus() and e_gdbus_book_proxy_new_for_bus_finish() for the asynchronous version.
+ *
+ * Returns: A #EGdbusBookProxy or %NULL if error is set. Free with g_object_unref().
+ */
+EGdbusBook *
+e_gdbus_book_proxy_new_for_bus_sync (GBusType bus_type, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GError **error)
+{
+	GInitable *initable;
+
+	initable = g_initable_new (E_TYPE_GDBUS_BOOK_PROXY,
+				cancellable,
+				error,
+				"g-flags", flags,
+				"g-name", name,
+				"g-bus-type", bus_type,
+				"g-object-path", object_path,
+				"g-interface-name", GDBUS_BOOK_INTERFACE_NAME,
+				NULL);
+	if (initable != NULL)
+		return E_GDBUS_BOOK (initable);
+	else
+		return NULL;
+}
+
+/* ---------------------------------------------------------------------- */
+
+struct _EGdbusBookStubPrivate
+{
+	gint foo;
+};
+
+static void stub_iface_init (EGdbusBookIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (EGdbusBookStub, e_gdbus_book_stub, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (E_TYPE_GDBUS_BOOK, stub_iface_init));
+
+static void
+e_gdbus_book_stub_init (EGdbusBookStub *stub)
+{
+	stub->priv = G_TYPE_INSTANCE_GET_PRIVATE (stub, E_TYPE_GDBUS_BOOK_STUB, EGdbusBookStubPrivate);
+}
+
+static void
+e_gdbus_book_stub_class_init (EGdbusBookStubClass *klass)
+{
+	g_type_class_add_private (klass, sizeof (EGdbusBookStubPrivate));
+}
+
+static void
+stub_iface_init (EGdbusBookIface *iface)
+{
+}
+
+/**
+ * e_gdbus_book_stub_new:
+ *
+ * Creates a new stub object that can be exported via e_gdbus_book_register_object().
+ *
+ * Returns: A #EGdbusBookStub instance. Free with g_object_unref().
+ */
+EGdbusBook *
+e_gdbus_book_stub_new (void)
+{
+	return E_GDBUS_BOOK (g_object_new (E_TYPE_GDBUS_BOOK_STUB, NULL));
+}
+
+/* Returns GDBus connection associated with the stub object */
+GDBusConnection *
+e_gdbus_book_stub_get_connection (EGdbusBook *stub)
+{
+	g_return_val_if_fail (stub != NULL, NULL);
+	g_return_val_if_fail (E_IS_GDBUS_BOOK_STUB (stub), NULL);
+
+	return g_object_get_data (G_OBJECT (stub), "gdbus-codegen-connection");
+}
diff --git a/addressbook/libegdbus/e-gdbus-book.h b/addressbook/libegdbus/e-gdbus-book.h
new file mode 100644
index 0000000..ae0dd9e
--- /dev/null
+++ b/addressbook/libegdbus/e-gdbus-book.h
@@ -0,0 +1,265 @@
+/*
+ * e-gdbus-book.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 2011 Red Hat, Inc. (www.redhat.com)
+ *
+ */
+
+#ifndef E_GDBUS_BOOK_H
+#define E_GDBUS_BOOK_H
+
+#include <gio/gio.h>
+
+#include <libedataserver/e-gdbus-templates.h>
+
+G_BEGIN_DECLS
+
+#define E_TYPE_GDBUS_BOOK         (e_gdbus_book_get_type ())
+#define E_GDBUS_BOOK(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_GDBUS_BOOK, EGdbusBook))
+#define E_IS_GDBUS_BOOK(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_GDBUS_BOOK))
+#define E_GDBUS_BOOK_GET_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE((o), E_TYPE_GDBUS_BOOK, EGdbusBookIface))
+
+/**
+ * EGdbusBook:
+ *
+ * Opaque type representing a proxy or an exported object.
+ */
+typedef struct _EGdbusBook EGdbusBook; /* Dummy typedef */
+
+typedef struct _EGdbusBookIface EGdbusBookIface;
+
+GType e_gdbus_book_get_type (void) G_GNUC_CONST;
+
+/* ---------------------------------------------------------------------- */
+
+#define E_TYPE_GDBUS_BOOK_PROXY         (e_gdbus_book_proxy_get_type ())
+#define E_GDBUS_BOOK_PROXY(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_GDBUS_BOOK_PROXY, EGdbusBookProxy))
+#define E_IS_GDBUS_BOOK_PROXY(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_GDBUS_BOOK_PROXY))
+
+typedef struct _EGdbusBookProxy EGdbusBookProxy;
+typedef struct _EGdbusBookProxyClass EGdbusBookProxyClass;
+typedef struct _EGdbusBookProxyPrivate EGdbusBookProxyPrivate;
+
+struct _EGdbusBookProxy
+{
+	GDBusProxy parent_instance;
+	EGdbusBookProxyPrivate *priv;
+};
+
+struct _EGdbusBookProxyClass
+{
+	GDBusProxyClass parent_class;
+};
+
+GType e_gdbus_book_proxy_get_type (void) G_GNUC_CONST;
+
+void e_gdbus_book_proxy_new (GDBusConnection *connection, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+EGdbusBook *e_gdbus_book_proxy_new_finish (GAsyncResult *result, GError **error);
+EGdbusBook *e_gdbus_book_proxy_new_sync (GDBusConnection *connection, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GError **error);
+
+void e_gdbus_book_proxy_new_for_bus (GBusType bus_type, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+EGdbusBook *e_gdbus_book_proxy_new_for_bus_finish (GAsyncResult *result, GError **error);
+EGdbusBook *e_gdbus_book_proxy_new_for_bus_sync (GBusType bus_type, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GError **error);
+
+/* ---------------------------------------------------------------------- */
+
+typedef struct _EGdbusBookStub EGdbusBookStub;
+typedef struct _EGdbusBookStubClass EGdbusBookStubClass;
+typedef struct _EGdbusBookStubPrivate EGdbusBookStubPrivate;
+
+struct _EGdbusBookStub
+{
+	GObject parent_instance;
+	EGdbusBookStubPrivate *priv;
+};
+
+struct _EGdbusBookStubClass
+{
+	GObjectClass parent_class;
+};
+
+#define E_TYPE_GDBUS_BOOK_STUB	(e_gdbus_book_stub_get_type ())
+#define E_GDBUS_BOOK_STUB(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_GDBUS_BOOK_STUB, EGdbusBookStub))
+#define E_IS_GDBUS_BOOK_STUB(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_GDBUS_BOOK_STUB))
+
+GType e_gdbus_book_stub_get_type (void) G_GNUC_CONST;
+
+EGdbusBook *e_gdbus_book_stub_new (void);
+GDBusConnection *e_gdbus_book_stub_get_connection (EGdbusBook *stub);
+
+guint e_gdbus_book_register_object (EGdbusBook *object, GDBusConnection *connection, const gchar *object_path, GError **error);
+
+void e_gdbus_book_drain_notify (EGdbusBook *object);
+
+const GDBusInterfaceInfo *e_gdbus_book_interface_info (void) G_GNUC_CONST;
+
+struct _EGdbusBookIface
+{
+	GTypeInterface parent_iface;
+
+	/* Signal handlers for receiving D-Bus signals: */
+	void	(*backend_error)		(EGdbusBook *object, const gchar *arg_message);
+	void	(*readonly)			(EGdbusBook *object, gboolean arg_is_readonly);
+	void	(*online)			(EGdbusBook *object, gboolean arg_is_online);
+	void	(*auth_required)		(EGdbusBook *object, const gchar * const *arg_credentials);
+	void	(*opened)			(EGdbusBook *object, const gchar * const *arg_error);
+
+	/* Signal handlers for handling D-Bus method calls: */
+	gboolean (*handle_open)			(EGdbusBook *object, GDBusMethodInvocation *invocation, gboolean in_only_if_exists);
+	void	 (*open_done)			(EGdbusBook *object, guint arg_opid, const GError *arg_error);
+
+	gboolean (*handle_remove)		(EGdbusBook *object, GDBusMethodInvocation *invocation);
+	void	 (*remove_done)			(EGdbusBook *object, guint arg_opid, const GError *arg_error);
+
+	gboolean (*handle_refresh)		(EGdbusBook *object, GDBusMethodInvocation *invocation);
+	void	 (*refresh_done)		(EGdbusBook *object, guint arg_opid, const GError *arg_error);
+
+	gboolean (*handle_get_contact)		(EGdbusBook *object, GDBusMethodInvocation *invocation, const gchar *in_uid);
+	void	 (*get_contact_done)		(EGdbusBook *object, guint arg_opid, const GError *arg_error, gchar **out_vcard);
+
+	gboolean (*handle_get_contact_list)	(EGdbusBook *object, GDBusMethodInvocation *invocation, const gchar *in_query);
+	void	 (*get_contact_list_done)	(EGdbusBook *object, guint arg_opid, const GError *arg_error, gchar ***out_vcards);
+
+	gboolean (*handle_add_contact)		(EGdbusBook *object, GDBusMethodInvocation *invocation, const gchar *in_vcard);
+	void	 (*add_contact_done)		(EGdbusBook *object, guint arg_opid, const GError *arg_error, gchar **out_uid);
+
+	gboolean (*handle_remove_contacts)	(EGdbusBook *object, GDBusMethodInvocation *invocation, const gchar * const *in_list);
+	void	 (*remove_contacts_done)	(EGdbusBook *object, guint arg_opid, const GError *arg_error);
+
+	gboolean (*handle_modify_contact)	(EGdbusBook *object, GDBusMethodInvocation *invocation, const gchar *in_vcard);
+	void	 (*modify_contact_done)		(EGdbusBook *object, guint arg_opid, const GError *arg_error);
+
+	gboolean (*handle_get_backend_property)	(EGdbusBook *object, GDBusMethodInvocation *invocation, const gchar *in_prop_name);
+	void	 (*get_backend_property_done)	(EGdbusBook *object, guint arg_opid, const GError *arg_error, gchar **out_prop_value);
+
+	gboolean (*handle_set_backend_property)	(EGdbusBook *object, GDBusMethodInvocation *invocation, const gchar *in_prop_name_value);
+	void	 (*set_backend_property_done)	(EGdbusBook *object, guint arg_opid, const GError *arg_error);
+
+	gboolean (*handle_get_view)		(EGdbusBook *object, GDBusMethodInvocation *invocation, const gchar *in_query);
+	void	 (*get_view_done)		(EGdbusBook *object, guint arg_opid, const GError *arg_error, gchar **out_view);
+
+	gboolean (*handle_authenticate_user)	(EGdbusBook *object, GDBusMethodInvocation *invocation, const gchar * const *in_credentials);
+	gboolean (*handle_cancel_operation)	(EGdbusBook *object, GDBusMethodInvocation *invocation, guint in_opid);
+	gboolean (*handle_cancel_all)		(EGdbusBook *object, GDBusMethodInvocation *invocation);
+	gboolean (*handle_close)		(EGdbusBook *object, GDBusMethodInvocation *invocation);
+
+};
+
+/* C Bindings for properties */
+
+/* D-Bus Methods */
+void		e_gdbus_book_call_open (GDBusProxy *proxy, gboolean in_only_if_exists, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_book_call_open_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_book_call_open_sync (GDBusProxy *proxy, gboolean in_only_if_exists, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_book_call_remove (GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_book_call_remove_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_book_call_remove_sync (GDBusProxy *proxy, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_book_call_refresh (GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_book_call_refresh_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_book_call_refresh_sync (GDBusProxy *proxy, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_book_call_get_contact (GDBusProxy *proxy, const gchar *in_uid, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_book_call_get_contact_finish (GDBusProxy *proxy, GAsyncResult *result, gchar **out_vcard, GError **error);
+gboolean	e_gdbus_book_call_get_contact_sync (GDBusProxy *proxy, const gchar *in_uid, gchar **out_vcard, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_book_call_get_contact_list (GDBusProxy *proxy, const gchar *in_query, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_book_call_get_contact_list_finish (GDBusProxy *proxy, GAsyncResult *result, gchar ***out_vcards, GError **error);
+gboolean	e_gdbus_book_call_get_contact_list_sync (GDBusProxy *proxy, const gchar *in_query, gchar ***out_vcards, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_book_call_add_contact (GDBusProxy *proxy, const gchar *in_vcard, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_book_call_add_contact_finish (GDBusProxy *proxy, GAsyncResult *result, gchar **out_uid, GError **error);
+gboolean	e_gdbus_book_call_add_contact_sync (GDBusProxy *proxy, const gchar *in_vcard, gchar **out_uid, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_book_call_remove_contacts (GDBusProxy *proxy, const gchar * const *in_list, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_book_call_remove_contacts_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_book_call_remove_contacts_sync (GDBusProxy *proxy, const gchar * const *in_list, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_book_call_modify_contact (GDBusProxy *proxy, const gchar *in_vcard, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_book_call_modify_contact_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_book_call_modify_contact_sync (GDBusProxy *proxy, const gchar *in_vcard, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_book_call_get_backend_property (GDBusProxy *proxy, const gchar *in_prop_name, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_book_call_get_backend_property_finish (GDBusProxy *proxy, GAsyncResult *result, gchar **out_prop_value, GError **error);
+gboolean	e_gdbus_book_call_get_backend_property_sync (GDBusProxy *proxy, const gchar *prop_name, gchar **out_prop_value, GCancellable *cancellable, GError **error);
+
+gchar **	e_gdbus_book_encode_set_backend_property (const gchar *in_prop_name, const gchar *in_prop_value);
+gboolean	e_gdbus_book_decode_set_backend_property (const gchar * const *in_strv, gchar **out_prop_name, gchar **out_prop_value);
+void		e_gdbus_book_call_set_backend_property (GDBusProxy *proxy, const gchar * const *in_prop_name_value, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_book_call_set_backend_property_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_book_call_set_backend_property_sync (GDBusProxy *proxy, const gchar * const *prop_name_value, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_book_call_get_view (GDBusProxy *proxy, const gchar *in_query, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_book_call_get_view_finish (GDBusProxy *proxy, GAsyncResult *result, gchar **out_view_path, GError **error);
+gboolean	e_gdbus_book_call_get_view_sync (GDBusProxy *proxy, const gchar *in_query, gchar **out_view_path, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_book_call_authenticate_user (GDBusProxy *proxy, const gchar * const *in_credentials, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_book_call_authenticate_user_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_book_call_authenticate_user_sync (GDBusProxy *proxy, const gchar * const *in_credentials, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_book_call_cancel_operation (GDBusProxy *proxy, guint in_opid, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_book_call_cancel_operation_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_book_call_cancel_operation_sync (GDBusProxy *proxy, guint in_opid, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_book_call_cancel_all (GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_book_call_cancel_all_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_book_call_cancel_all_sync (GDBusProxy *proxy, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_book_call_close (GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_book_call_close_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_book_call_close_sync (GDBusProxy *proxy, GCancellable *cancellable, GError **error);
+
+/* D-Bus Methods Completion Helpers */
+#define e_gdbus_book_complete_open				e_gdbus_complete_async_method
+#define e_gdbus_book_complete_remove				e_gdbus_complete_async_method
+#define e_gdbus_book_complete_refresh				e_gdbus_complete_async_method
+#define e_gdbus_book_complete_get_contact			e_gdbus_complete_async_method
+#define e_gdbus_book_complete_get_contact_list			e_gdbus_complete_async_method
+#define e_gdbus_book_complete_add_contact			e_gdbus_complete_async_method
+#define e_gdbus_book_complete_remove_contacts			e_gdbus_complete_async_method
+#define e_gdbus_book_complete_modify_contact			e_gdbus_complete_async_method
+#define e_gdbus_book_complete_get_backend_property		e_gdbus_complete_async_method
+#define e_gdbus_book_complete_set_backend_property		e_gdbus_complete_async_method
+#define e_gdbus_book_complete_get_view				e_gdbus_complete_async_method
+#define e_gdbus_book_complete_authenticate_user			e_gdbus_complete_sync_method_void
+#define e_gdbus_book_complete_cancel_operation			e_gdbus_complete_sync_method_void
+#define e_gdbus_book_complete_cancel_all			e_gdbus_complete_sync_method_void
+#define e_gdbus_book_complete_close				e_gdbus_complete_sync_method_void
+
+void e_gdbus_book_emit_open_done			(EGdbusBook *object, guint arg_opid, const GError *arg_error);
+void e_gdbus_book_emit_remove_done			(EGdbusBook *object, guint arg_opid, const GError *arg_error);
+void e_gdbus_book_emit_refresh_done			(EGdbusBook *object, guint arg_opid, const GError *arg_error);
+void e_gdbus_book_emit_get_contact_done			(EGdbusBook *object, guint arg_opid, const GError *arg_error, const gchar *out_vcard);
+void e_gdbus_book_emit_get_contact_list_done		(EGdbusBook *object, guint arg_opid, const GError *arg_error, const gchar * const *out_vcards);
+void e_gdbus_book_emit_add_contact_done			(EGdbusBook *object, guint arg_opid, const GError *arg_error, const gchar *out_uid);
+void e_gdbus_book_emit_remove_contacts_done		(EGdbusBook *object, guint arg_opid, const GError *arg_error);
+void e_gdbus_book_emit_modify_contact_done		(EGdbusBook *object, guint arg_opid, const GError *arg_error);
+void e_gdbus_book_emit_get_backend_property_done	(EGdbusBook *object, guint arg_opid, const GError *arg_error, const gchar *out_prop_value);
+void e_gdbus_book_emit_set_backend_property_done	(EGdbusBook *object, guint arg_opid, const GError *arg_error);
+void e_gdbus_book_emit_get_view_done			(EGdbusBook *object, guint arg_opid, const GError *arg_error, const gchar *out_view);
+
+/* D-Bus Signal Emission Helpers */
+void e_gdbus_book_emit_backend_error	(EGdbusBook *object, const gchar *arg_message);
+void e_gdbus_book_emit_readonly		(EGdbusBook *object, gboolean arg_is_readonly);
+void e_gdbus_book_emit_online		(EGdbusBook *object, gboolean arg_is_online);
+void e_gdbus_book_emit_auth_required	(EGdbusBook *object, const gchar * const *arg_credentials);
+void e_gdbus_book_emit_opened		(EGdbusBook *object, const gchar * const *arg_error);
+
+G_END_DECLS
+
+#endif /* E_GDBUS_BOOK_H */
diff --git a/calendar/backends/caldav/e-cal-backend-caldav.c b/calendar/backends/caldav/e-cal-backend-caldav.c
index 98afd27..b99491e 100644
--- a/calendar/backends/caldav/e-cal-backend-caldav.c
+++ b/calendar/backends/caldav/e-cal-backend-caldav.c
@@ -74,7 +74,7 @@ typedef enum {
 struct _ECalBackendCalDAVPrivate {
 
 	/* online/offline */
-	CalMode mode;
+	gboolean is_online;
 
 	/* The local disk cache */
 	ECalBackendStore *store;
@@ -113,15 +113,12 @@ struct _ECalBackendCalDAVPrivate {
 	gchar *uri;
 
 	/* Authentication info */
-	gchar *username;
-	gchar *password;
+	ECredentials *credentials;
 	gboolean need_auth;
 
 	/* object cleanup */
 	gboolean disposed;
 
-	icaltimezone *default_zone;
-
 	/* support for 'getctag' extension */
 	gboolean ctag_supported;
 	gchar *ctag_to_store;
@@ -302,7 +299,6 @@ put_component_to_store (ECalBackendCalDAV *cbdav,
 
 static ECalBackendSyncClass *parent_class = NULL;
 
-static icaltimezone *caldav_internal_get_default_timezone (ECalBackend *backend);
 static icaltimezone *caldav_internal_get_timezone (ECalBackend *backend, const gchar *tzid);
 static void caldav_source_changed_cb (ESource *source, ECalBackendCalDAV *cbdav);
 
@@ -571,7 +567,7 @@ check_state (ECalBackendCalDAV *cbdav, gboolean *online, GError **perror)
 		return FALSE;
 	}
 
-	if (priv->mode == CAL_MODE_LOCAL) {
+	if (!priv->is_online) {
 
 		if (!priv->do_offline) {
 			g_propagate_error (perror, EDC_ERROR (RepositoryOffline));
@@ -906,8 +902,10 @@ soup_authenticate (SoupSession  *session,
 	priv = cbdav->priv;
 
 	/* do not send same password twice, but keep it for later use */
-	if (!retrying)
-		soup_auth_authenticate (auth, priv->username, priv->password);
+	if (!retrying && priv->credentials && e_credentials_has_key (priv->credentials, E_CREDENTIALS_KEY_USERNAME)) {
+		soup_auth_authenticate (auth, e_credentials_peek (priv->credentials, E_CREDENTIALS_KEY_USERNAME), e_credentials_peek (priv->credentials, E_CREDENTIALS_KEY_PASSWORD));
+		e_credentials_clear_peek (priv->credentials);
+	}
 }
 
 /* ************************************************************************* */
@@ -2106,6 +2104,7 @@ caldav_synch_slave_loop (gpointer data)
 			}
 
 			e_cal_backend_notify_readonly (E_CAL_BACKEND (cbdav), priv->read_only);
+			e_cal_backend_notify_online (E_CAL_BACKEND (cbdav), priv->is_online);
 		}
 
 		if (priv->opened) {
@@ -2187,8 +2186,8 @@ get_usermail (ECalBackend *backend)
 	cbdav = E_CAL_BACKEND_CALDAV (backend);
 	priv  = cbdav->priv;
 
-	if (priv && priv->is_google && priv->username) {
-		res = maybe_append_email_domain (priv->username, "@gmail.com");
+	if (priv && priv->is_google && priv->credentials) {
+		res = maybe_append_email_domain (e_credentials_peek (priv->credentials, E_CREDENTIALS_KEY_USERNAME), "@gmail.com");
 	}
 
 	return res;
@@ -2197,82 +2196,69 @@ get_usermail (ECalBackend *backend)
 /* ************************************************************************* */
 /* ********** ECalBackendSync virtual function implementation *************  */
 
-static void
-caldav_is_read_only (ECalBackendSync *backend,
-		     EDataCal        *cal,
-		     gboolean        *read_only,
-		     GError         **perror)
+static gboolean
+caldav_get_backend_property (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *prop_name, gchar **prop_value, GError **perror)
 {
-	ECalBackendCalDAV        *cbdav;
-	ECalBackendCalDAVPrivate *priv;
+	gboolean processed = TRUE;
 
-	cbdav = E_CAL_BACKEND_CALDAV (backend);
-	priv  = cbdav->priv;
+	g_return_val_if_fail (prop_name != NULL, FALSE);
+	g_return_val_if_fail (prop_value != NULL, FALSE);
 
-	/* no write support in offline mode yet! */
-	if (priv->mode == CAL_MODE_LOCAL) {
-		*read_only = TRUE;
-	} else {
-		*read_only = priv->read_only;
-	}
-}
+	if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
+		ESource *source;
+		GString *caps;
+		gchar *usermail;
 
-static void
-caldav_get_cal_address (ECalBackendSync  *backend,
-			EDataCal         *cal,
-			gchar           **address,
-			GError          **perror)
-{
-	*address = get_usermail (E_CAL_BACKEND (backend));
-}
+		caps = g_string_new (CAL_STATIC_CAPABILITY_NO_THISANDFUTURE ","
+				     CAL_STATIC_CAPABILITY_NO_THISANDPRIOR ","
+				     CAL_STATIC_CAPABILITY_REFRESH_SUPPORTED);
 
-static void
-caldav_get_alarm_email_address (ECalBackendSync  *backend,
-				EDataCal         *cal,
-				gchar           **address,
-				GError          **perror)
-{
-	*address = get_usermail (E_CAL_BACKEND (backend));
-}
+		usermail = get_usermail (E_CAL_BACKEND (backend));
+		if (!usermail || !*usermail)
+			g_string_append (caps, "," CAL_STATIC_CAPABILITY_NO_EMAIL_ALARMS);
+		g_free (usermail);
 
-static void
-caldav_get_ldap_attribute (ECalBackendSync  *backend,
-			   EDataCal         *cal,
-			   gchar           **attribute,
-			   GError          **perror)
-{
-	*attribute = NULL;
-}
+		source = e_cal_backend_get_source (E_CAL_BACKEND (backend));
+		if (source) {
+			const gchar *prop = e_source_get_property (source, "autoschedule");
 
-static void
-caldav_get_static_capabilities (ECalBackendSync  *backend,
-				EDataCal         *cal,
-				gchar           **capabilities,
-				GError          **perror)
-{
-	ESource *source;
-	GString *caps;
-	gchar *usermail;
+			if (prop && g_str_equal (prop, "1"))
+				g_string_append (caps, "," CAL_STATIC_CAPABILITY_CREATE_MESSAGES
+						       "," CAL_STATIC_CAPABILITY_SAVE_SCHEDULES);
+		}
 
-	caps = g_string_new (CAL_STATIC_CAPABILITY_NO_THISANDFUTURE ","
-			     CAL_STATIC_CAPABILITY_NO_THISANDPRIOR ","
-			     CAL_STATIC_CAPABILITY_REFRESH_SUPPORTED);
+		*prop_value = g_string_free (caps, FALSE);
+	} else if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS) ||
+		   g_str_equal (prop_name, CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS)) {
+		*prop_value = get_usermail (E_CAL_BACKEND (backend));
+	} else if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_DEFAULT_OBJECT)) {
+		ECalComponent *comp;
 
-	usermail = get_usermail (E_CAL_BACKEND (backend));
-	if (!usermail || !*usermail)
-		g_string_append (caps, "," CAL_STATIC_CAPABILITY_NO_EMAIL_ALARMS);
-	g_free (usermail);
+		comp = e_cal_component_new ();
 
-	source = e_cal_backend_get_source (E_CAL_BACKEND (backend));
-	if (source) {
-		const gchar *prop = e_source_get_property (source, "autoschedule");
+		switch (e_cal_backend_get_kind (E_CAL_BACKEND (backend))) {
+		case ICAL_VEVENT_COMPONENT:
+			e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_EVENT);
+			break;
+		case ICAL_VTODO_COMPONENT:
+			e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_TODO);
+			break;
+		case ICAL_VJOURNAL_COMPONENT:
+			e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_JOURNAL);
+			break;
+		default:
+			g_object_unref (comp);
+			g_propagate_error (perror, EDC_ERROR (ObjectNotFound));
+			return TRUE;
+		}
 
-		if (prop && g_str_equal (prop, "1"))
-			g_string_append (caps, "," CAL_STATIC_CAPABILITY_CREATE_MESSAGES
-					       "," CAL_STATIC_CAPABILITY_SAVE_SCHEDULES);
+		*prop_value = e_cal_component_get_as_string (comp);
+		g_object_unref (comp);
+	} else {
+		processed = FALSE;
 	}
 
-	*capabilities = g_string_free (caps, FALSE);
+	return processed;
 }
 
 static gboolean
@@ -2431,12 +2417,40 @@ proxy_settings_changed (EProxy *proxy, gpointer user_data)
 }
 
 static void
-caldav_do_open (ECalBackendSync *backend,
-		EDataCal        *cal,
-		gboolean         only_if_exists,
-		const gchar      *username,
-		const gchar      *password,
-		GError          **perror)
+open_calendar (ECalBackendCalDAV *cbdav, GError **error)
+{
+	gboolean server_unreachable = FALSE;
+	ECalBackendCalDAVPrivate *priv;
+	GError *local_error = NULL;
+
+	g_return_if_fail (cbdav != NULL);
+
+	priv  = cbdav->priv;
+
+	/* set forward proxy */
+	proxy_settings_changed (priv->proxy, priv);
+
+	if (caldav_server_open_calendar (cbdav, &server_unreachable, &local_error)) {
+		priv->slave_cmd = SLAVE_SHOULD_WORK;
+		g_cond_signal (priv->cond);
+
+		priv->is_google = is_google_uri (priv->uri);
+	} else if (server_unreachable) {
+		priv->opened = FALSE;
+		priv->read_only = TRUE;
+		if (local_error) {
+			gchar *msg = g_strdup_printf (_("Server is unreachable, calendar is opened in read-only mode.\nError message: %s"), local_error->message);
+			e_cal_backend_notify_error (E_CAL_BACKEND (cbdav), msg);
+			g_free (msg);
+			g_clear_error (&local_error);
+		}
+	} else if (local_error) {
+		g_propagate_error (error, local_error);
+	}
+}
+
+static void
+caldav_do_open (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, gboolean only_if_exists, GError **perror)
 {
 	ECalBackendCalDAV        *cbdav;
 	ECalBackendCalDAVPrivate *priv;
@@ -2454,20 +2468,7 @@ caldav_do_open (ECalBackendSync *backend,
 		return;
 	}
 
-	if (priv->need_auth) {
-		if ((username == NULL || password == NULL)) {
-			g_mutex_unlock (priv->busy_lock);
-			g_propagate_error (perror, EDC_ERROR (AuthenticationRequired));
-			return;
-		}
-
-		g_free (priv->username);
-		priv->username = g_strdup (username);
-		g_free (priv->password);
-		priv->password = g_strdup (password);
-	}
-
-	if (!priv->do_offline && priv->mode == CAL_MODE_LOCAL) {
+	if (!priv->do_offline && !priv->is_online) {
 		g_mutex_unlock (priv->busy_lock);
 		g_propagate_error (perror, EDC_ERROR (RepositoryOffline));
 		return;
@@ -2477,39 +2478,60 @@ caldav_do_open (ECalBackendSync *backend,
 	priv->opened = TRUE;
 	priv->is_google = FALSE;
 
-	if (priv->mode == CAL_MODE_REMOTE) {
-		gboolean server_unreachable = FALSE;
+	if (priv->is_online) {
 		GError *local_error = NULL;
 
-		/* set forward proxy */
-		proxy_settings_changed (priv->proxy, priv);
+		open_calendar (cbdav, &local_error);
 
-		if (caldav_server_open_calendar (cbdav, &server_unreachable, &local_error)) {
-			priv->slave_cmd = SLAVE_SHOULD_WORK;
-			g_cond_signal (priv->cond);
-
-			priv->is_google = is_google_uri (priv->uri);
-		} else if (server_unreachable) {
-			priv->opened = FALSE;
-			priv->read_only = TRUE;
-			if (local_error) {
-				gchar *msg = g_strdup_printf (_("Server is unreachable, calendar is opened in read-only mode.\nError message: %s"), local_error->message);
-				e_cal_backend_notify_error (E_CAL_BACKEND (backend), msg);
-				g_free (msg);
-				g_clear_error (&local_error);
-			}
+		if (g_error_matches (local_error, E_DATA_CAL_ERROR, AuthenticationRequired) || g_error_matches (local_error, E_DATA_CAL_ERROR, AuthenticationFailed)) {
+			g_clear_error (&local_error);
+			e_cal_backend_notify_auth_required (E_CAL_BACKEND (cbdav), TRUE, priv->credentials);
 		} else {
-			g_propagate_error (perror, local_error);
+			e_cal_backend_notify_opened (E_CAL_BACKEND (backend), NULL);
 		}
+
+		if (local_error)
+			g_propagate_error (perror, local_error);
 	} else {
 		priv->read_only = TRUE;
+		e_cal_backend_notify_opened (E_CAL_BACKEND (backend), NULL);
+	}
+
+	e_cal_backend_notify_readonly (E_CAL_BACKEND (backend), priv->read_only);
+	e_cal_backend_notify_online (E_CAL_BACKEND (backend), priv->is_online);
+
+	g_mutex_unlock (priv->busy_lock);
+}
+
+static void
+caldav_authenticate_user (ECalBackendSync *backend, GCancellable *cancellable, ECredentials *credentials, GError **error)
+{
+	ECalBackendCalDAV        *cbdav;
+	ECalBackendCalDAVPrivate *priv;
+
+	cbdav = E_CAL_BACKEND_CALDAV (backend);
+	priv  = cbdav->priv;
+
+	g_mutex_lock (priv->busy_lock);
+
+	e_credentials_free (priv->credentials);
+	priv->credentials = NULL;
+
+	if (!credentials || !e_credentials_has_key (credentials, E_CREDENTIALS_KEY_USERNAME)) {
+		g_mutex_unlock (priv->busy_lock);
+		g_propagate_error (error, EDC_ERROR (AuthenticationRequired));
+		return;
 	}
 
+	priv->credentials = e_credentials_new_clone (credentials);
+
+	open_calendar (cbdav, error);
+
 	g_mutex_unlock (priv->busy_lock);
 }
 
 static void
-caldav_refresh (ECalBackendSync *backend, EDataCal *cal, GError **perror)
+caldav_refresh (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, GError **perror)
 {
 	ECalBackendCalDAV        *cbdav;
 	ECalBackendCalDAVPrivate *priv;
@@ -2536,9 +2558,7 @@ caldav_refresh (ECalBackendSync *backend, EDataCal *cal, GError **perror)
 }
 
 static void
-caldav_remove (ECalBackendSync *backend,
-	       EDataCal        *cal,
-	       GError         **perror)
+caldav_remove (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, GError **perror)
 {
 	ECalBackendCalDAV        *cbdav;
 	ECalBackendCalDAVPrivate *priv;
@@ -3133,7 +3153,7 @@ static void
 sanitize_component (ECalBackend *cb, ECalComponent *comp)
 {
 	ECalComponentDateTime dt;
-	icaltimezone *zone, *default_zone;
+	icaltimezone *zone;
 
 	/* Check dtstart, dtend and due's timezone, and convert it to local
 	 * default timezone if the timezone is not in our builtin timezone
@@ -3142,9 +3162,8 @@ sanitize_component (ECalBackend *cb, ECalComponent *comp)
 	if (dt.value && dt.tzid) {
 		zone = caldav_internal_get_timezone (cb, dt.tzid);
 		if (!zone) {
-			default_zone = caldav_internal_get_default_timezone (cb);
 			g_free ((gchar *) dt.tzid);
-			dt.tzid = g_strdup (icaltimezone_get_tzid (default_zone));
+			dt.tzid = g_strdup ("UTC");
 			e_cal_component_set_dtstart (comp, &dt);
 		}
 	}
@@ -3154,9 +3173,8 @@ sanitize_component (ECalBackend *cb, ECalComponent *comp)
 	if (dt.value && dt.tzid) {
 		zone = caldav_internal_get_timezone (cb, dt.tzid);
 		if (!zone) {
-			default_zone = caldav_internal_get_default_timezone (cb);
 			g_free ((gchar *) dt.tzid);
-			dt.tzid = g_strdup (icaltimezone_get_tzid (default_zone));
+			dt.tzid = g_strdup ("UTC");
 			e_cal_component_set_dtend (comp, &dt);
 		}
 	}
@@ -3166,9 +3184,8 @@ sanitize_component (ECalBackend *cb, ECalComponent *comp)
 	if (dt.value && dt.tzid) {
 		zone = caldav_internal_get_timezone (cb, dt.tzid);
 		if (!zone) {
-			default_zone = caldav_internal_get_default_timezone (cb);
 			g_free ((gchar *) dt.tzid);
-			dt.tzid = g_strdup (icaltimezone_get_tzid (default_zone));
+			dt.tzid = g_strdup ("UTC");
 			e_cal_component_set_due (comp, &dt);
 		}
 	}
@@ -3312,7 +3329,7 @@ replace_master (ECalBackendCalDAV *cbdav, icalcomponent *old_comp, icalcomponent
 
 /* a busy_lock is supposed to be locked already, when calling this function */
 static void
-do_create_object (ECalBackendCalDAV *cbdav, gchar **calobj, gchar **uid, GError **perror)
+do_create_object (ECalBackendCalDAV *cbdav, const gchar *in_calobj, gchar **uid, gchar **new_calobj, GError **perror)
 {
 	ECalComponent            *comp;
 	gboolean                  online, did_put = FALSE;
@@ -3323,7 +3340,7 @@ do_create_object (ECalBackendCalDAV *cbdav, gchar **calobj, gchar **uid, GError
 	if (!check_state (cbdav, &online, perror))
 		return;
 
-	comp = e_cal_component_new_from_string (*calobj);
+	comp = e_cal_component_new_from_string (in_calobj);
 
 	if (comp == NULL) {
 		g_propagate_error (perror, EDC_ERROR (InvalidObject));
@@ -3394,13 +3411,13 @@ do_create_object (ECalBackendCalDAV *cbdav, gchar **calobj, gchar **uid, GError
 			icalcomponent *master = get_master_comp (cbdav, icalcomp);
 
 			if (!master)
-				*calobj = e_cal_component_get_as_string (comp);
+				*new_calobj = e_cal_component_get_as_string (comp);
 			else
-				*calobj = icalcomponent_as_ical_string_r (master);
+				*new_calobj = icalcomponent_as_ical_string_r (master);
 
 			icalcomponent_free (icalcomp);
 		} else {
-			*calobj = e_cal_component_get_as_string (comp);
+			*new_calobj = e_cal_component_get_as_string (comp);
 		}
 	}
 
@@ -3677,7 +3694,7 @@ do_remove_object (ECalBackendCalDAV *cbdav, const gchar *uid, const gchar *rid,
 static void
 extract_objects (icalcomponent       *icomp,
 		 icalcomponent_kind   ekind,
-		 GList              **objects,
+		 GSList             **objects,
 		 GError             **error)
 {
 	icalcomponent         *scomp;
@@ -3689,7 +3706,7 @@ extract_objects (icalcomponent       *icomp,
 	kind = icalcomponent_isa (icomp);
 
 	if (kind == ekind) {
-		*objects = g_list_prepend (NULL, icomp);
+		*objects = g_slist_prepend (NULL, icomp);
 		return;
 	}
 
@@ -3704,7 +3721,7 @@ extract_objects (icalcomponent       *icomp,
 
 	while (scomp) {
 		/* Remove components from toplevel here */
-		*objects = g_list_prepend (*objects, scomp);
+		*objects = g_slist_prepend (*objects, scomp);
 		icalcomponent_remove_component (icomp, scomp);
 
 		scomp = icalcomponent_get_next_component (icomp, ekind);
@@ -3715,7 +3732,7 @@ static gboolean
 extract_timezones (ECalBackendCalDAV *cbdav, icalcomponent *icomp)
 {
 	ECalBackendCalDAVPrivate *priv;
-	GList *timezones = NULL, *iter;
+	GSList *timezones = NULL, *iter;
 	icaltimezone *zone;
 	GError *err = NULL;
 
@@ -3740,7 +3757,7 @@ extract_timezones (ECalBackendCalDAV *cbdav, icalcomponent *icomp)
 	}
 
 	icaltimezone_free (zone, TRUE);
-	g_list_free (timezones);
+	g_slist_free (timezones);
 
 	return TRUE;
 }
@@ -3812,7 +3829,7 @@ process_object (ECalBackendCalDAV   *cbdav,
 		} else if (!is_declined) {
 			gchar *new_object = new_obj_str;
 
-			do_create_object (cbdav, &new_object, NULL, &err);
+			do_create_object (cbdav, new_object, NULL, &new_object, &err);
 			if (!err) {
 				e_cal_backend_notify_object_created (backend, new_object);
 			}
@@ -3854,15 +3871,14 @@ process_object (ECalBackendCalDAV   *cbdav,
 }
 
 static void
-do_receive_objects (ECalBackendSync *backend, EDataCal *cal, const gchar *calobj, GError **perror)
+do_receive_objects (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, GError **perror)
 {
 	ECalBackendCalDAV        *cbdav;
 	icalcomponent            *icomp;
 	icalcomponent_kind        kind;
 	icalproperty_method       tmethod;
 	gboolean                  online;
-	GList                    *objects;
-	GList                    *iter;
+	GSList                   *objects, *iter;
 	GError *err = NULL;
 
 	cbdav = E_CAL_BACKEND_CALDAV (backend);
@@ -3913,7 +3929,7 @@ do_receive_objects (ECalBackendSync *backend, EDataCal *cal, const gchar *calobj
 		g_object_unref (ecomp);
 	}
 
-	g_list_free (objects);
+	g_slist_free (objects);
 
 	icalcomponent_free (icomp);
 
@@ -3954,62 +3970,30 @@ _func_name _params							\
 }
 
 caldav_busy_stub (
-	caldav_create_object, (ECalBackendSync *backend, EDataCal *cal, gchar **calobj, gchar **uid, GError **perror),
-	do_create_object, (cbdav, calobj, uid, perror))
+	caldav_create_object, (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *in_calobj, gchar **uid, gchar **new_calobj, GError **perror),
+	do_create_object, (cbdav, in_calobj, uid, new_calobj, perror))
 
 caldav_busy_stub (
-	caldav_modify_object, (ECalBackendSync *backend, EDataCal *cal, const gchar *calobj, CalObjModType mod, gchar **old_object, gchar **new_object, GError **perror),
+	caldav_modify_object, (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, CalObjModType mod, gchar **old_object, gchar **new_object, GError **perror),
 	do_modify_object, (cbdav, calobj, mod, old_object, new_object, perror))
 
 caldav_busy_stub (
-	caldav_remove_object, (ECalBackendSync *backend, EDataCal *cal, const gchar *uid, const gchar *rid, CalObjModType mod, gchar **old_object, gchar **object, GError **perror),
+	caldav_remove_object, (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *uid, const gchar *rid, CalObjModType mod, gchar **old_object, gchar **object, GError **perror),
 	do_remove_object, (cbdav, uid, rid, mod, old_object, object, perror))
 
 caldav_busy_stub (
-	caldav_receive_objects, (ECalBackendSync *backend, EDataCal *cal, const gchar *calobj, GError **perror),
-	do_receive_objects, (backend, cal, calobj, perror))
-
-static void
-caldav_discard_alarm (ECalBackendSync *backend, EDataCal *cal, const gchar *uid, const gchar *auid, GError **perror)
-{
-}
+	caldav_receive_objects, (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, GError **perror),
+	do_receive_objects, (backend, cal, cancellable, calobj, perror))
 
 static void
-caldav_send_objects (ECalBackendSync *backend, EDataCal *cal, const gchar *calobj, GList **users, gchar **modified_calobj, GError **perror)
+caldav_send_objects (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, GSList **users, gchar **modified_calobj, GError **perror)
 {
 	*users = NULL;
 	*modified_calobj = g_strdup (calobj);
 }
 
 static void
-caldav_get_default_object (ECalBackendSync *backend, EDataCal *cal, gchar **object, GError **perror)
-{
-	ECalComponent *comp;
-
-	comp = e_cal_component_new ();
-
-	switch (e_cal_backend_get_kind (E_CAL_BACKEND (backend))) {
-	case ICAL_VEVENT_COMPONENT:
-		e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_EVENT);
-		break;
-	case ICAL_VTODO_COMPONENT:
-		e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_TODO);
-		break;
-	case ICAL_VJOURNAL_COMPONENT:
-		e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_JOURNAL);
-		break;
-	default:
-		g_object_unref (comp);
-		g_propagate_error (perror, EDC_ERROR (ObjectNotFound));
-		return;
-	}
-
-	*object = e_cal_component_get_as_string (comp);
-	g_object_unref (comp);
-}
-
-static void
-caldav_get_object (ECalBackendSync *backend, EDataCal *cal, const gchar *uid, const gchar *rid, gchar **object, GError **perror)
+caldav_get_object (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *uid, const gchar *rid, gchar **object, GError **perror)
 {
 	ECalBackendCalDAV        *cbdav;
 	icalcomponent            *icalcomp;
@@ -4029,10 +4013,7 @@ caldav_get_object (ECalBackendSync *backend, EDataCal *cal, const gchar *uid, co
 }
 
 static void
-caldav_add_timezone (ECalBackendSync *backend,
-		     EDataCal        *cal,
-		     const gchar      *tzobj,
-		     GError **error)
+caldav_add_timezone (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *tzobj, GError **error)
 {
 	icalcomponent *tz_comp;
 	ECalBackendCalDAV *cbdav;
@@ -4066,44 +4047,7 @@ caldav_add_timezone (ECalBackendSync *backend,
 }
 
 static void
-caldav_set_default_zone (ECalBackendSync *backend,
-			     EDataCal        *cal,
-			     const gchar      *tzobj,
-			     GError **error)
-{
-	icalcomponent *tz_comp;
-	ECalBackendCalDAV *cbdav;
-	ECalBackendCalDAVPrivate *priv;
-	icaltimezone *zone;
-
-	e_return_data_cal_error_if_fail (E_IS_CAL_BACKEND_CALDAV (backend), InvalidArg);
-	e_return_data_cal_error_if_fail (tzobj != NULL, InvalidArg);
-
-	cbdav = E_CAL_BACKEND_CALDAV (backend);
-	priv  = cbdav->priv;
-
-	tz_comp = icalparser_parse_string (tzobj);
-	if (!tz_comp) {
-		g_propagate_error (error, EDC_ERROR (InvalidObject));
-		return;
-	}
-
-	zone = icaltimezone_new ();
-	icaltimezone_set_component (zone, tz_comp);
-
-	if (priv->default_zone != icaltimezone_get_utc_timezone ())
-		icaltimezone_free (priv->default_zone, 1);
-
-	/* Set the default timezone to it. */
-	priv->default_zone = zone;
-}
-
-static void
-caldav_get_object_list (ECalBackendSync  *backend,
-			EDataCal         *cal,
-			const gchar       *sexp_string,
-			GList           **objects,
-			GError **perror)
+caldav_get_object_list (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *sexp_string, GSList **objects, GError **perror)
 {
 	ECalBackendCalDAV        *cbdav;
 	ECalBackendCalDAVPrivate *priv;
@@ -4132,9 +4076,7 @@ caldav_get_object_list (ECalBackendSync  *backend,
 
 	*objects = NULL;
 
-	prunning_by_time = e_cal_backend_sexp_evaluate_occur_times (sexp,
-									    &occur_start,
-									    &occur_end);
+	prunning_by_time = e_cal_backend_sexp_evaluate_occur_times (sexp, &occur_start, &occur_end);
 
 	bkend = E_CAL_BACKEND (backend);
 
@@ -4149,7 +4091,7 @@ caldav_get_object_list (ECalBackendSync  *backend,
 
 		if (!do_search ||
 		    e_cal_backend_sexp_match_comp (sexp, comp, bkend)) {
-			*objects = g_list_prepend (*objects, e_cal_component_get_as_string (comp));
+			*objects = g_slist_prepend (*objects, e_cal_component_get_as_string (comp));
 		}
 
 		g_object_unref (comp);
@@ -4160,8 +4102,7 @@ caldav_get_object_list (ECalBackendSync  *backend,
 }
 
 static void
-caldav_start_query (ECalBackend  *backend,
-		    EDataCalView *query)
+caldav_start_view (ECalBackend *backend, EDataCalView *query)
 {
 	ECalBackendCalDAV        *cbdav;
 	ECalBackendCalDAVPrivate *priv;
@@ -4211,17 +4152,11 @@ caldav_start_query (ECalBackend  *backend,
 	g_object_unref (sexp);
 	g_slist_free (list);
 
-	e_data_cal_view_notify_done (query, NULL /* Success */);
+	e_data_cal_view_notify_complete (query, NULL /* Success */);
 }
 
 static void
-caldav_get_free_busy (ECalBackendSync  *backend,
-		      EDataCal         *cal,
-		      GList            *users,
-		      time_t            start,
-		      time_t            end,
-		      GList           **freebusy,
-		      GError **error)
+caldav_get_free_busy (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const GSList *users, time_t start, time_t end, GSList **freebusy, GError **error)
 {
 	ECalBackendCalDAV *cbdav;
 	ECalBackendCalDAVPrivate *priv;
@@ -4231,7 +4166,7 @@ caldav_get_free_busy (ECalBackendSync  *backend,
 	struct icaltimetype dtvalue;
 	icaltimezone *utc;
 	gchar *str, *usermail;
-	GList *u;
+	const GSList *u;
 	GSList *attendees = NULL, *to_free = NULL;
 	GError *err = NULL;
 
@@ -4283,10 +4218,10 @@ caldav_get_free_busy (ECalBackendSync  *backend,
 		usermail = NULL;
 	}
 
-	if (priv->username || usermail) {
+	if ((priv->credentials && e_credentials_has_key (priv->credentials, E_CREDENTIALS_KEY_USERNAME)) || usermail) {
 		ECalComponentOrganizer organizer = {NULL};
 
-		organizer.value = usermail ? usermail : priv->username;
+		organizer.value = usermail ? usermail : e_credentials_peek (priv->credentials, E_CREDENTIALS_KEY_USERNAME);
 		organizer.value = g_strconcat ("mailto:";, organizer.value, NULL);
 
 		e_cal_component_set_organizer (comp, &organizer);
@@ -4361,7 +4296,7 @@ caldav_get_free_busy (ECalBackendSync  *backend,
 
 					tmp = xp_object_get_string (xpath_eval (xpctx, "string(/C:schedule-response/C:response[%d]/C:calendar-data)", i + 1));
 					if (tmp && *tmp) {
-						GList *objects = NULL, *o;
+						GSList *objects = NULL, *o;
 
 						icalcomp = icalparser_parse_string (tmp);
 						if (icalcomp)
@@ -4371,14 +4306,14 @@ caldav_get_free_busy (ECalBackendSync  *backend,
 								gchar *obj_str = icalcomponent_as_ical_string_r (o->data);
 
 								if (obj_str && *obj_str)
-									*freebusy = g_list_append (*freebusy, obj_str);
+									*freebusy = g_slist_append (*freebusy, obj_str);
 								else
 									g_free (obj_str);
 							}
 						}
 
-						g_list_foreach (objects, (GFunc) icalcomponent_free, NULL);
-						g_list_free (objects);
+						g_slist_foreach (objects, (GFunc) icalcomponent_free, NULL);
+						g_slist_free (objects);
 
 						if (icalcomp)
 							icalcomponent_free (icalcomp);
@@ -4405,44 +4340,7 @@ caldav_get_free_busy (ECalBackendSync  *backend,
 }
 
 static void
-caldav_get_changes (ECalBackendSync  *backend,
-		    EDataCal         *cal,
-		    const gchar       *change_id,
-		    GList           **adds,
-		    GList           **modifies,
-		    GList **deletes,
-		    GError **perror)
-{
-	/* FIXME: implement me! */
-	g_propagate_error (perror, EDC_ERROR (NotSupported));
-}
-
-static gboolean
-caldav_is_loaded (ECalBackend *backend)
-{
-	ECalBackendCalDAV        *cbdav;
-	ECalBackendCalDAVPrivate *priv;
-
-	cbdav = E_CAL_BACKEND_CALDAV (backend);
-	priv  = cbdav->priv;
-
-	return priv->loaded;
-}
-
-static CalMode
-caldav_get_mode (ECalBackend *backend)
-{
-	ECalBackendCalDAV        *cbdav;
-	ECalBackendCalDAVPrivate *priv;
-
-	cbdav = E_CAL_BACKEND_CALDAV (backend);
-	priv  = cbdav->priv;
-
-	return priv->mode;
-}
-
-static void
-caldav_set_mode (ECalBackend *backend, CalMode mode)
+caldav_set_online (ECalBackend *backend, gboolean is_online)
 {
 	ECalBackendCalDAV        *cbdav;
 	ECalBackendCalDAVPrivate *priv;
@@ -4452,28 +4350,16 @@ caldav_set_mode (ECalBackend *backend, CalMode mode)
 
 	/*g_mutex_lock (priv->busy_lock);*/
 
-	/* We only support online and offline */
-	if (mode != CAL_MODE_REMOTE &&
-	    mode != CAL_MODE_LOCAL) {
-		e_cal_backend_notify_mode (backend,
-					   ModeNotSupported,
-					   cal_mode_to_corba (mode));
-		/*g_mutex_unlock (priv->busy_lock);*/
-		return;
-	}
-
-	if (priv->mode == mode || !priv->loaded) {
-		priv->mode = mode;
-		e_cal_backend_notify_mode (backend,
-					   ModeSet,
-					   cal_mode_to_corba (mode));
+	if ((priv->is_online ? 1: 0) == (is_online ? 1 : 0) || !priv->loaded) {
+		priv->is_online = is_online;
+		e_cal_backend_notify_online (backend, is_online);
 		/*g_mutex_unlock (priv->busy_lock);*/
 		return;
 	}
 
-	priv->mode = mode;
+	priv->is_online = is_online;
 
-	if (mode == CAL_MODE_REMOTE) {
+	if (is_online) {
 		/* Wake up the slave thread */
 		priv->slave_cmd = SLAVE_SHOULD_WORK;
 		g_cond_signal (priv->cond);
@@ -4482,30 +4368,12 @@ caldav_set_mode (ECalBackend *backend, CalMode mode)
 		priv->slave_cmd = SLAVE_SHOULD_SLEEP;
 	}
 
-	e_cal_backend_notify_mode (backend,
-				   ModeSet,
-				   cal_mode_to_corba (mode));
+	e_cal_backend_notify_online (backend, is_online);
 
 	/*g_mutex_unlock (priv->busy_lock);*/
 }
 
 static icaltimezone *
-caldav_internal_get_default_timezone (ECalBackend *backend)
-{
-	ECalBackendCalDAV *cbdav;
-	ECalBackendCalDAVPrivate *priv;
-
-	g_return_val_if_fail (E_IS_CAL_BACKEND_CALDAV (backend), NULL);
-
-	cbdav = E_CAL_BACKEND_CALDAV (backend);
-	priv  = cbdav->priv;
-
-	g_return_val_if_fail (priv->default_zone != NULL, NULL);
-
-	return priv->default_zone;
-}
-
-static icaltimezone *
 caldav_internal_get_timezone (ECalBackend *backend,
 			      const gchar *tzid)
 {
@@ -4598,8 +4466,9 @@ e_cal_backend_caldav_dispose (GObject *object)
 	g_object_unref (priv->session);
 	g_object_unref (priv->proxy);
 
-	g_free (priv->username);
-	g_free (priv->password);
+	e_credentials_free (priv->credentials);
+	priv->credentials = NULL;
+
 	g_free (priv->uri);
 	g_free (priv->schedule_outbox_url);
 
@@ -4627,11 +4496,6 @@ e_cal_backend_caldav_finalize (GObject *object)
 	g_cond_free (priv->cond);
 	g_cond_free (priv->slave_gone_cond);
 
-	if (priv->default_zone && priv->default_zone != icaltimezone_get_utc_timezone ()) {
-		icaltimezone_free (priv->default_zone, 1);
-	}
-	priv->default_zone = NULL;
-
 	/* Chain up to parent's finalize() method. */
 	G_OBJECT_CLASS (parent_class)->finalize (object);
 }
@@ -4652,8 +4516,6 @@ e_cal_backend_caldav_init (ECalBackendCalDAV *cbdav)
 	if (G_UNLIKELY (caldav_debug_show (DEBUG_MESSAGE)))
 		caldav_debug_setup (cbdav->priv->session);
 
-	cbdav->priv->default_zone = icaltimezone_get_utc_timezone ();
-
 	cbdav->priv->disposed = FALSE;
 	cbdav->priv->loaded   = FALSE;
 	cbdav->priv->opened = FALSE;
@@ -4701,36 +4563,26 @@ e_cal_backend_caldav_class_init (ECalBackendCalDAVClass *class)
 	object_class->dispose  = e_cal_backend_caldav_dispose;
 	object_class->finalize = e_cal_backend_caldav_finalize;
 
-	sync_class->is_read_only_sync            = caldav_is_read_only;
-	sync_class->get_cal_address_sync         = caldav_get_cal_address;
-	sync_class->get_alarm_email_address_sync = caldav_get_alarm_email_address;
-	sync_class->get_ldap_attribute_sync      = caldav_get_ldap_attribute;
-	sync_class->get_static_capabilities_sync = caldav_get_static_capabilities;
-
-	sync_class->open_sync                    = caldav_do_open;
-	sync_class->refresh_sync                 = caldav_refresh;
-	sync_class->remove_sync                  = caldav_remove;
-
-	sync_class->create_object_sync = caldav_create_object;
-	sync_class->modify_object_sync = caldav_modify_object;
-	sync_class->remove_object_sync = caldav_remove_object;
-
-	sync_class->discard_alarm_sync        = caldav_discard_alarm;
-	sync_class->receive_objects_sync      = caldav_receive_objects;
-	sync_class->send_objects_sync         = caldav_send_objects;
-	sync_class->get_default_object_sync   = caldav_get_default_object;
-	sync_class->get_object_sync           = caldav_get_object;
-	sync_class->get_object_list_sync      = caldav_get_object_list;
-	sync_class->add_timezone_sync         = caldav_add_timezone;
-	sync_class->set_default_zone_sync = caldav_set_default_zone;
-	sync_class->get_freebusy_sync         = caldav_get_free_busy;
-	sync_class->get_changes_sync          = caldav_get_changes;
-
-	backend_class->is_loaded   = caldav_is_loaded;
-	backend_class->start_query = caldav_start_query;
-	backend_class->get_mode    = caldav_get_mode;
-	backend_class->set_mode    = caldav_set_mode;
-
-	backend_class->internal_get_default_timezone = caldav_internal_get_default_timezone;
-	backend_class->internal_get_timezone         = caldav_internal_get_timezone;
+	sync_class->get_backend_property_sync	= caldav_get_backend_property;
+
+	sync_class->open_sync			= caldav_do_open;
+	sync_class->authenticate_user_sync	= caldav_authenticate_user;
+	sync_class->refresh_sync		= caldav_refresh;
+	sync_class->remove_sync			= caldav_remove;
+
+	sync_class->create_object_sync		= caldav_create_object;
+	sync_class->modify_object_sync		= caldav_modify_object;
+	sync_class->remove_object_sync		= caldav_remove_object;
+
+	sync_class->receive_objects_sync	= caldav_receive_objects;
+	sync_class->send_objects_sync		= caldav_send_objects;
+	sync_class->get_object_sync		= caldav_get_object;
+	sync_class->get_object_list_sync	= caldav_get_object_list;
+	sync_class->add_timezone_sync		= caldav_add_timezone;
+	sync_class->get_free_busy_sync		= caldav_get_free_busy;
+
+	backend_class->start_view		= caldav_start_view;
+	backend_class->set_online		= caldav_set_online;
+
+	backend_class->internal_get_timezone	= caldav_internal_get_timezone;
 }
diff --git a/calendar/backends/contacts/e-cal-backend-contacts.c b/calendar/backends/contacts/e-cal-backend-contacts.c
index 7d9866f..89f7bfb 100644
--- a/calendar/backends/contacts/e-cal-backend-contacts.c
+++ b/calendar/backends/contacts/e-cal-backend-contacts.c
@@ -67,7 +67,6 @@ struct _ECalBackendContactsPrivate {
         GHashTable   *tracked_contacts;   /* UID -> ContactRecord */
 
 	GHashTable *zones;
-	icaltimezone *default_zone;
 
 	EFlag   *init_done_flag; /* is set, when the init thread gone */
 
@@ -106,7 +105,7 @@ static ECalComponent * create_anniversary (ECalBackendContacts *cbc, EContact *c
 static void contacts_changed_cb (EBookView *book_view, const GList *contacts, gpointer user_data);
 static void contacts_added_cb   (EBookView *book_view, const GList *contacts, gpointer user_data);
 static void contacts_removed_cb (EBookView *book_view, const GList *contact_ids, gpointer user_data);
-static void e_cal_backend_contacts_add_timezone (ECalBackendSync *backend, EDataCal *cal, const gchar *tzobj, GError **perror);
+static void e_cal_backend_contacts_add_timezone (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *tzobj, GError **perror);
 static void setup_alarm (ECalBackendContacts *cbc, ECalComponent *comp);
 
 /* BookRecord methods */
@@ -258,7 +257,7 @@ contact_record_free (ContactRecord *cr)
 typedef struct _ContactRecordCB {
         ECalBackendContacts *cbc;
         ECalBackendSExp     *sexp;
-        GList               *result;
+        GSList              *result;
 } ContactRecordCB;
 
 static ContactRecordCB *
@@ -276,8 +275,8 @@ contact_record_cb_new (ECalBackendContacts *cbc, ECalBackendSExp *sexp)
 static void
 contact_record_cb_free (ContactRecordCB *cb_data)
 {
-	g_list_foreach (cb_data->result, (GFunc) g_free, NULL);
-	g_list_free (cb_data->result);
+	g_slist_foreach (cb_data->result, (GFunc) g_free, NULL);
+	g_slist_free (cb_data->result);
 
 	g_free (cb_data);
 }
@@ -290,12 +289,12 @@ contact_record_cb (gpointer key, gpointer value, gpointer user_data)
 
 	if (record->comp_birthday && e_cal_backend_sexp_match_comp (cb_data->sexp, record->comp_birthday, E_CAL_BACKEND (cb_data->cbc))) {
 		gchar * comp_str = e_cal_component_get_as_string (record->comp_birthday);
-		cb_data->result = g_list_append (cb_data->result, comp_str);
+		cb_data->result = g_slist_append (cb_data->result, comp_str);
 	}
 
 	if (record->comp_anniversary && e_cal_backend_sexp_match_comp (cb_data->sexp, record->comp_anniversary, E_CAL_BACKEND (cb_data->cbc))) {
 		gchar * comp_str = e_cal_component_get_as_string (record->comp_anniversary);
-		cb_data->result = g_list_append (cb_data->result, comp_str);
+		cb_data->result = g_slist_append (cb_data->result, comp_str);
 	}
 }
 
@@ -791,56 +790,40 @@ create_anniversary (ECalBackendContacts *cbc, EContact *contact)
 
 /* First the empty stubs */
 
-static void
-e_cal_backend_contacts_get_cal_address (ECalBackendSync *backend, EDataCal *cal,
-					gchar **address, GError **perror)
-{
-	/* A contact backend has no particular email address associated
-	 * with it (although that would be a useful feature some day).
-	 */
-	*address = NULL;
-}
-
-static void
-e_cal_backend_contacts_get_ldap_attribute (ECalBackendSync *backend, EDataCal *cal,
-					   gchar **attribute, GError **perror)
-{
-	*attribute = NULL;
-}
-
-static void
-e_cal_backend_contacts_get_alarm_email_address (ECalBackendSync *backend, EDataCal *cal,
-						gchar **address, GError **perror)
+static gboolean
+e_cal_backend_contacts_get_backend_property (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *prop_name, gchar **prop_value, GError **perror)
 {
-	/* A contact backend has no particular email address associated
-	 * with it (although that would be a useful feature some day).
-	 */
-	*address = NULL;
-}
+	gboolean processed = TRUE;
+
+	g_return_val_if_fail (prop_name != NULL, FALSE);
+	g_return_val_if_fail (prop_value != NULL, FALSE);
+
+	if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
+		*prop_value = NULL;
+	} else if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS) ||
+		   g_str_equal (prop_name, CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS)) {
+		/* A contact backend has no particular email address associated
+		 * with it (although that would be a useful feature some day).
+		 */
+		*prop_value = NULL;
+	} else if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_DEFAULT_OBJECT)) {
+		g_propagate_error (perror, EDC_ERROR (UnsupportedMethod));
+	} else {
+		processed = FALSE;
+	}
 
-static void
-e_cal_backend_contacts_get_static_capabilities (ECalBackendSync *backend, EDataCal *cal,
-						gchar **capabilities, GError **perror)
-{
-	*capabilities = NULL;
+	return processed;
 }
 
 static void
-e_cal_backend_contacts_remove (ECalBackendSync *backend, EDataCal *cal, GError **perror)
+e_cal_backend_contacts_remove (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, GError **perror)
 {
 	/* WRITE ME */
 	g_propagate_error (perror, EDC_ERROR (PermissionDenied));
 }
 
 static void
-e_cal_backend_contacts_get_default_object (ECalBackendSync *backend, EDataCal *cal,
-					   gchar **object, GError **perror)
-{
-	g_propagate_error (perror, EDC_ERROR (UnsupportedMethod));
-}
-
-static void
-e_cal_backend_contacts_get_object (ECalBackendSync *backend, EDataCal *cal,
+e_cal_backend_contacts_get_object (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable,
 				   const gchar *uid, const gchar *rid,
 				   gchar **object, GError **perror)
 {
@@ -889,9 +872,9 @@ e_cal_backend_contacts_get_object (ECalBackendSync *backend, EDataCal *cal,
 }
 
 static void
-e_cal_backend_contacts_get_free_busy (ECalBackendSync *backend, EDataCal *cal,
-				      GList *users, time_t start, time_t end,
-				      GList **freebusy, GError **perror)
+e_cal_backend_contacts_get_free_busy (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, 
+				      const GSList *users, time_t start, time_t end,
+				      GSList **freebusy, GError **perror)
 {
 	/* Birthdays/anniversaries don't count as busy time */
 
@@ -916,7 +899,7 @@ e_cal_backend_contacts_get_free_busy (ECalBackendSync *backend, EDataCal *cal,
 	icalcomponent_set_dtend (vfb, icaltime_from_timet_with_zone (end, FALSE, utc_zone));
 
 	calobj = icalcomponent_as_ical_string_r (vfb);
-	*freebusy = g_list_append (NULL, calobj);
+	*freebusy = g_slist_append (NULL, calobj);
 	icalcomponent_free (vfb);
 
 	/* WRITE ME */
@@ -924,30 +907,15 @@ e_cal_backend_contacts_get_free_busy (ECalBackendSync *backend, EDataCal *cal,
 }
 
 static void
-e_cal_backend_contacts_get_changes (ECalBackendSync *backend, EDataCal *cal,
-				    const gchar *change_id,
-				    GList **adds, GList **modifies, GList **deletes, GError **perror)
-{
-	/* WRITE ME */
-}
-
-static void
-e_cal_backend_contacts_discard_alarm (ECalBackendSync *backend, EDataCal *cal,
-				      const gchar *uid, const gchar *auid, GError **perror)
-{
-	/* WRITE ME */
-}
-
-static void
-e_cal_backend_contacts_receive_objects (ECalBackendSync *backend, EDataCal *cal,
+e_cal_backend_contacts_receive_objects (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable,
 					const gchar *calobj, GError **perror)
 {
 	g_propagate_error (perror, EDC_ERROR (PermissionDenied));
 }
 
 static void
-e_cal_backend_contacts_send_objects (ECalBackendSync *backend, EDataCal *cal,
-				     const gchar *calobj, GList **users, gchar **modified_calobj, GError **perror)
+e_cal_backend_contacts_send_objects (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable,
+				     const gchar *calobj, GSList **users, gchar **modified_calobj, GError **perror)
 {
 	*users = NULL;
 	*modified_calobj = NULL;
@@ -957,23 +925,11 @@ e_cal_backend_contacts_send_objects (ECalBackendSync *backend, EDataCal *cal,
 
 /* Then the real implementations */
 
-static CalMode
-e_cal_backend_contacts_get_mode (ECalBackend *backend)
-{
-	return CAL_MODE_LOCAL;
-}
-
-static void
-e_cal_backend_contacts_set_mode (ECalBackend *backend, CalMode mode)
-{
-	e_cal_backend_notify_mode (backend, ModeNotSupported, Local);
-}
-
 static void
-e_cal_backend_contacts_is_read_only (ECalBackendSync *backend, EDataCal *cal,
-				     gboolean *read_only, GError **perror)
+e_cal_backend_contacts_set_online (ECalBackend *backend, gboolean is_online)
 {
-	*read_only = TRUE;
+	e_cal_backend_notify_online (backend, is_online);
+	e_cal_backend_notify_readonly (backend, TRUE);
 }
 
 static gpointer
@@ -1004,9 +960,8 @@ init_sources_cb (ECalBackendContacts *cbc)
 }
 
 static void
-e_cal_backend_contacts_open (ECalBackendSync *backend, EDataCal *cal,
-			     gboolean only_if_exists,
-			     const gchar *username, const gchar *password, GError **perror)
+e_cal_backend_contacts_open (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable,
+			     gboolean only_if_exists, GError **perror)
 {
 	ECalBackendContacts *cbc = E_CAL_BACKEND_CONTACTS (backend);
 	ECalBackendContactsPrivate *priv = cbc->priv;
@@ -1015,15 +970,6 @@ e_cal_backend_contacts_open (ECalBackendSync *backend, EDataCal *cal,
 	if (priv->addressbook_loaded)
 		return;
 
-	if (priv->default_zone && priv->default_zone != icaltimezone_get_utc_timezone ()) {
-		icalcomponent *icalcomp = icaltimezone_get_component (priv->default_zone);
-		icaltimezone *zone = icaltimezone_new ();
-
-		icaltimezone_set_component (zone, icalcomponent_new_clone (icalcomp));
-
-		g_hash_table_insert (priv->zones, g_strdup (icaltimezone_get_tzid (zone)), zone);
-	}
-
 	/* initialize addressbook sources in new thread to make this function quick as much as possible */
 	if (!g_thread_create ((GThreadFunc) init_sources_cb, cbc, FALSE, &error)) {
 		e_flag_set (priv->init_done_flag);
@@ -1032,24 +978,19 @@ e_cal_backend_contacts_open (ECalBackendSync *backend, EDataCal *cal,
 			g_error_free (error);
 
 		g_propagate_error (perror, EDC_ERROR (OtherError));
+		e_cal_backend_notify_opened (E_CAL_BACKEND (backend), EDC_ERROR (OtherError));
 		return;
 	}
 
 	priv->addressbook_loaded = TRUE;
-}
-
-static gboolean
-e_cal_backend_contacts_is_loaded (ECalBackend *backend)
-{
-	ECalBackendContacts *cbc = E_CAL_BACKEND_CONTACTS (backend);
-	ECalBackendContactsPrivate *priv = cbc->priv;
-
-	return priv->addressbook_loaded;
+	e_cal_backend_notify_readonly (E_CAL_BACKEND (backend), TRUE);
+	e_cal_backend_notify_online (E_CAL_BACKEND (backend), TRUE);
+	e_cal_backend_notify_opened (E_CAL_BACKEND (backend), NULL);
 }
 
 /* Add_timezone handler for the file backend */
 static void
-e_cal_backend_contacts_add_timezone (ECalBackendSync *backend, EDataCal *cal, const gchar *tzobj, GError **error)
+e_cal_backend_contacts_add_timezone (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *tzobj, GError **error)
 {
 	ECalBackendContacts *cbcontacts;
 	ECalBackendContactsPrivate *priv;
@@ -1087,39 +1028,8 @@ e_cal_backend_contacts_add_timezone (ECalBackendSync *backend, EDataCal *cal, co
 }
 
 static void
-e_cal_backend_contacts_set_default_zone (ECalBackendSync *backend, EDataCal *cal, const gchar *tzobj, GError **error)
-{
-	icalcomponent *tz_comp;
-	ECalBackendContacts *cbcontacts;
-	ECalBackendContactsPrivate *priv;
-	icaltimezone *zone;
-
-	cbcontacts = (ECalBackendContacts *) backend;
-
-	e_return_data_cal_error_if_fail (E_IS_CAL_BACKEND_CONTACTS (cbcontacts), InvalidArg);
-	e_return_data_cal_error_if_fail (tzobj != NULL, InvalidArg);
-
-	priv = cbcontacts->priv;
-
-	tz_comp = icalparser_parse_string (tzobj);
-	if (!tz_comp) {
-		g_propagate_error (error, EDC_ERROR (InvalidObject));
-		return;
-	}
-
-	zone = icaltimezone_new ();
-	icaltimezone_set_component (zone, tz_comp);
-
-	if (priv->default_zone && priv->default_zone != icaltimezone_get_utc_timezone ())
-		icaltimezone_free (priv->default_zone, 1);
-
-	/* Set the default timezone to it. */
-	priv->default_zone = zone;
-}
-
-static void
-e_cal_backend_contacts_get_object_list (ECalBackendSync *backend, EDataCal *cal,
-					const gchar *sexp_string, GList **objects, GError **perror)
+e_cal_backend_contacts_get_object_list (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable,
+					const gchar *sexp_string, GSList **objects, GError **perror)
 {
 	ECalBackendContacts *cbc = E_CAL_BACKEND_CONTACTS (backend);
 	ECalBackendContactsPrivate *priv = cbc->priv;
@@ -1141,7 +1051,7 @@ e_cal_backend_contacts_get_object_list (ECalBackendSync *backend, EDataCal *cal,
 }
 
 static void
-e_cal_backend_contacts_start_query (ECalBackend *backend, EDataCalView *query)
+e_cal_backend_contacts_start_view (ECalBackend *backend, EDataCalView *query)
 {
 	ECalBackendContacts *cbc = E_CAL_BACKEND_CONTACTS (backend);
 	ECalBackendContactsPrivate *priv = cbc->priv;
@@ -1151,7 +1061,7 @@ e_cal_backend_contacts_start_query (ECalBackend *backend, EDataCalView *query)
 	sexp = e_data_cal_view_get_object_sexp (query);
 	if (!sexp) {
 		GError *error = EDC_ERROR (InvalidQuery);
-		e_data_cal_view_notify_done (query, error);
+		e_data_cal_view_notify_complete (query, error);
 		g_error_free (error);
 		return;
 	}
@@ -1163,15 +1073,7 @@ e_cal_backend_contacts_start_query (ECalBackend *backend, EDataCalView *query)
 
 	contact_record_cb_free (cb_data);
 
-	e_data_cal_view_notify_done (query, NULL /* Success */);
-}
-
-static icaltimezone *
-e_cal_backend_contacts_internal_get_default_timezone (ECalBackend *backend)
-{
-	ECalBackendContacts *cbc = E_CAL_BACKEND_CONTACTS (backend);
-
-	return cbc->priv->default_zone;
+	e_data_cal_view_notify_complete (query, NULL /* Success */);
 }
 
 static icaltimezone *
@@ -1179,7 +1081,7 @@ e_cal_backend_contacts_internal_get_timezone (ECalBackend *backend, const gchar
 {
 	ECalBackendContacts *cbc = E_CAL_BACKEND_CONTACTS (backend);
 
-	return cbc->priv->default_zone;
+	return g_hash_table_lookup (cbc->priv->zones, tzid ? tzid : "");
 }
 
 /***********************************************************************************
@@ -1215,11 +1117,6 @@ e_cal_backend_contacts_finalize (GObject *object)
 		priv->update_alarms_id = 0;
 	}
 
-	if (priv->default_zone && priv->default_zone != icaltimezone_get_utc_timezone ()) {
-		icaltimezone_free (priv->default_zone, 1);
-	}
-
-	priv->default_zone = NULL;
 	g_object_unref (priv->addressbook_sources);
 	g_hash_table_destroy (priv->addressbooks);
 	g_hash_table_destroy (priv->tracked_contacts);
@@ -1256,7 +1153,6 @@ e_cal_backend_contacts_init (ECalBackendContacts *cbc)
 							g_free, (GDestroyNotify) contact_record_free);
 
 	priv->zones = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, free_zone);
-	priv->default_zone = icaltimezone_get_utc_timezone ();
 	priv->init_done_flag = e_flag_new ();
 	priv->conf_client = gconf_client_get_default ();
 	priv->notifyid1 = 0;
@@ -1273,7 +1169,7 @@ e_cal_backend_contacts_init (ECalBackendContacts *cbc)
 }
 
 static void
-e_cal_backend_contacts_create_object (ECalBackendSync *backend, EDataCal *cal, gchar **calobj, gchar **uid, GError **perror)
+e_cal_backend_contacts_create_object (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, gchar **uid, gchar **new_calobj, GError **perror)
 {
 	g_propagate_error (perror, EDC_ERROR (PermissionDenied));
 }
@@ -1294,29 +1190,18 @@ e_cal_backend_contacts_class_init (ECalBackendContactsClass *class)
 
 	object_class->finalize = e_cal_backend_contacts_finalize;
 
-	sync_class->is_read_only_sync = e_cal_backend_contacts_is_read_only;
-	sync_class->get_cal_address_sync = e_cal_backend_contacts_get_cal_address;
-	sync_class->get_alarm_email_address_sync = e_cal_backend_contacts_get_alarm_email_address;
-	sync_class->get_ldap_attribute_sync = e_cal_backend_contacts_get_ldap_attribute;
-	sync_class->get_static_capabilities_sync = e_cal_backend_contacts_get_static_capabilities;
-	sync_class->open_sync = e_cal_backend_contacts_open;
-	sync_class->remove_sync = e_cal_backend_contacts_remove;
-	sync_class->create_object_sync = e_cal_backend_contacts_create_object;
-	sync_class->discard_alarm_sync = e_cal_backend_contacts_discard_alarm;
-	sync_class->receive_objects_sync = e_cal_backend_contacts_receive_objects;
-	sync_class->send_objects_sync = e_cal_backend_contacts_send_objects;
-	sync_class->get_default_object_sync = e_cal_backend_contacts_get_default_object;
-	sync_class->get_object_sync = e_cal_backend_contacts_get_object;
-	sync_class->get_object_list_sync = e_cal_backend_contacts_get_object_list;
-	sync_class->add_timezone_sync = e_cal_backend_contacts_add_timezone;
-	sync_class->set_default_zone_sync = e_cal_backend_contacts_set_default_zone;
-	sync_class->get_freebusy_sync = e_cal_backend_contacts_get_free_busy;
-	sync_class->get_changes_sync = e_cal_backend_contacts_get_changes;
-	backend_class->is_loaded = e_cal_backend_contacts_is_loaded;
-	backend_class->start_query = e_cal_backend_contacts_start_query;
-	backend_class->get_mode = e_cal_backend_contacts_get_mode;
-	backend_class->set_mode = e_cal_backend_contacts_set_mode;
-
-	backend_class->internal_get_default_timezone = e_cal_backend_contacts_internal_get_default_timezone;
-	backend_class->internal_get_timezone = e_cal_backend_contacts_internal_get_timezone;
+	sync_class->get_backend_property_sync	= e_cal_backend_contacts_get_backend_property;
+	sync_class->open_sync			= e_cal_backend_contacts_open;
+	sync_class->remove_sync			= e_cal_backend_contacts_remove;
+	sync_class->create_object_sync		= e_cal_backend_contacts_create_object;
+	sync_class->receive_objects_sync	= e_cal_backend_contacts_receive_objects;
+	sync_class->send_objects_sync		= e_cal_backend_contacts_send_objects;
+	sync_class->get_object_sync		= e_cal_backend_contacts_get_object;
+	sync_class->get_object_list_sync	= e_cal_backend_contacts_get_object_list;
+	sync_class->add_timezone_sync		= e_cal_backend_contacts_add_timezone;
+	sync_class->get_free_busy_sync		= e_cal_backend_contacts_get_free_busy;
+
+	backend_class->start_view		= e_cal_backend_contacts_start_view;
+	backend_class->set_online		= e_cal_backend_contacts_set_online;
+	backend_class->internal_get_timezone	= e_cal_backend_contacts_internal_get_timezone;
 }
diff --git a/calendar/backends/file/e-cal-backend-file.c b/calendar/backends/file/e-cal-backend-file.c
index 0bbd4aa..e7c1958 100644
--- a/calendar/backends/file/e-cal-backend-file.c
+++ b/calendar/backends/file/e-cal-backend-file.c
@@ -93,10 +93,6 @@ struct _ECalBackendFilePrivate {
 
 	GList *comp;
 
-	/* The calendar's default timezone, used for resolving DATE and
-	   floating DATE-TIME values. */
-	icaltimezone *default_zone;
-
 	/* a custom filename opened */
 	gchar *custom_file;
 
@@ -127,17 +123,11 @@ static void e_cal_backend_file_finalize (GObject *object);
 
 static ECalBackendSyncClass *parent_class;
 
-static void
-e_cal_backend_file_add_timezone (ECalBackendSync *backend, EDataCal *cal, const gchar *tzobj, GError **perror);
-
 static void free_refresh_data (ECalBackendFile *cbfile);
 
 static icaltimezone *
 e_cal_backend_file_internal_get_timezone (ECalBackend *backend, const gchar *tzid);
 
-static icaltimezone *
-e_cal_backend_file_internal_get_default_timezone (ECalBackend *backend);
-
 /* g_hash_table_foreach() callback to destroy a ECalBackendFileObject */
 static void
 free_object_data (gpointer data)
@@ -371,11 +361,6 @@ e_cal_backend_file_finalize (GObject *object)
 	g_free (priv->custom_file);
 	priv->custom_file = NULL;
 
-	if (priv->default_zone && priv->default_zone != icaltimezone_get_utc_timezone ()) {
-		icaltimezone_free (priv->default_zone, 1);
-	}
-	priv->default_zone = NULL;
-
 	if (priv->file_name) {
 		g_free (priv->file_name);
 		priv->file_name = NULL;
@@ -406,47 +391,54 @@ lookup_component (ECalBackendFile *cbfile, const gchar *uid)
 
 /* Calendar backend methods */
 
-/* Is_read_only handler for the file backend */
-static void
-e_cal_backend_file_is_read_only (ECalBackendSync *backend, EDataCal *cal, gboolean *read_only, GError **perror)
-{
-	ECalBackendFile *cbfile = (ECalBackendFile *) backend;
-
-	*read_only = cbfile->priv->read_only;
-}
-
 /* Get_email_address handler for the file backend */
-static void
-e_cal_backend_file_get_cal_address (ECalBackendSync *backend, EDataCal *cal, gchar **address, GError **perror)
-{
-	/* A file backend has no particular email address associated
-	 * with it (although that would be a useful feature some day).
-	 */
-	*address = NULL;
-}
+static gboolean
+e_cal_backend_file_get_backend_property (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *prop_name, gchar **prop_value, GError **perror)
+{
+	gboolean processed = TRUE;
+
+	g_return_val_if_fail (prop_name != NULL, FALSE);
+	g_return_val_if_fail (prop_value != NULL, FALSE);
+
+	if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
+		*prop_value = g_strdup (CAL_STATIC_CAPABILITY_NO_EMAIL_ALARMS ","
+					CAL_STATIC_CAPABILITY_NO_THISANDFUTURE ","
+					CAL_STATIC_CAPABILITY_DELEGATE_SUPPORTED ","
+					CAL_STATIC_CAPABILITY_NO_THISANDPRIOR);
+	} else if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS) ||
+		   g_str_equal (prop_name, CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS)) {
+		/* A file backend has no particular email address associated
+		 * with it (although that would be a useful feature some day).
+		 */
+		*prop_value = NULL;
+	} else if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_DEFAULT_OBJECT)) {
+		ECalComponent *comp;
 
-static void
-e_cal_backend_file_get_ldap_attribute (ECalBackendSync *backend, EDataCal *cal, gchar **attribute, GError **perror)
-{
-	*attribute = NULL;
-}
+		comp = e_cal_component_new ();
 
-static void
-e_cal_backend_file_get_alarm_email_address (ECalBackendSync *backend, EDataCal *cal, gchar **address, GError **perror)
-{
-	/* A file backend has no particular email address associated
-	 * with it (although that would be a useful feature some day).
-	 */
-	*address = NULL;
-}
+		switch (e_cal_backend_get_kind (E_CAL_BACKEND (backend))) {
+		case ICAL_VEVENT_COMPONENT:
+			e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_EVENT);
+			break;
+		case ICAL_VTODO_COMPONENT:
+			e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_TODO);
+			break;
+		case ICAL_VJOURNAL_COMPONENT:
+			e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_JOURNAL);
+			break;
+		default:
+			g_object_unref (comp);
+			g_propagate_error (perror, EDC_ERROR (ObjectNotFound));
+			return TRUE;
+		}
 
-static void
-e_cal_backend_file_get_static_capabilities (ECalBackendSync *backend, EDataCal *cal, gchar **capabilities, GError **perror)
-{
-	*capabilities = g_strdup (CAL_STATIC_CAPABILITY_NO_EMAIL_ALARMS ","
-				  CAL_STATIC_CAPABILITY_NO_THISANDFUTURE ","
-				  CAL_STATIC_CAPABILITY_DELEGATE_SUPPORTED ","
-				  CAL_STATIC_CAPABILITY_NO_THISANDPRIOR);
+		*prop_value = e_cal_component_get_as_string (comp);
+		g_object_unref (comp);
+	} else {
+		processed = FALSE;
+	}
+
+	return processed;
 }
 
 /* function to resolve timezones */
@@ -533,7 +525,7 @@ add_component_to_intervaltree (ECalBackendFile *cbfile, ECalComponent *comp)
 	priv = cbfile->priv;
 
 	e_cal_util_get_component_occur_times (comp, &time_start, &time_end,
-				   resolve_tzid, priv->icalcomp, priv->default_zone,
+				   resolve_tzid, priv->icalcomp, icaltimezone_get_utc_timezone (),
 				   e_cal_backend_get_kind (E_CAL_BACKEND (cbfile)));
 
 	if (time_end != -1 && time_start > time_end)
@@ -1197,104 +1189,6 @@ get_uri_string (ECalBackend *backend)
 	return full_uri;
 }
 
-static gboolean
-add_timezone (icalcomponent *icalcomp, icaltimezone *tzone)
-{
-	GSList *to_remove = NULL, *r;
-	icalcomponent *subcomp;
-	icaltimezone *zone;
-	gboolean add = TRUE, have_same = FALSE;
-	const gchar *tzid;
-	gchar *cmp;
-
-	g_return_val_if_fail (icalcomp != NULL, FALSE);
-
-	/* it's fine to have passed in NULL tzcomp; for example UTC timezone does this */
-	if (!tzone || !icaltimezone_get_component (tzone))
-		return FALSE;
-
-	tzid = icaltimezone_get_tzid (tzone);
-	if (!tzid)
-		return FALSE;
-
-	cmp = icalcomponent_as_ical_string_r (icaltimezone_get_component (tzone));
-	zone = icaltimezone_new ();
-
-	for (subcomp = icalcomponent_get_first_component (icalcomp, ICAL_VTIMEZONE_COMPONENT);
-	     subcomp;
-	     subcomp = icalcomponent_get_next_component (icalcomp, ICAL_VTIMEZONE_COMPONENT)) {
-		if (!icaltimezone_set_component (zone, icalcomponent_new_clone (subcomp))) {
-			to_remove = g_slist_prepend (to_remove, subcomp);
-		} else if (icaltimezone_get_tzid (zone) && g_str_equal (tzid, icaltimezone_get_tzid (zone))) {
-			/* there is a timezone component with the same tzid already */
-			if (have_same) {
-				to_remove = g_slist_prepend (to_remove, subcomp);
-			} else {
-				gchar *str = icalcomponent_as_ical_string_r (subcomp);
-
-				/* not the best way how to compare two components, but don't have better */
-				if (str && g_str_equal (cmp, str)) {
-					have_same = TRUE;
-					add = FALSE;
-				} else {
-					to_remove = g_slist_prepend (to_remove, subcomp);
-				}
-
-				g_free (str);
-			}
-		}
-	}
-
-	g_free (cmp);
-
-	for (r = to_remove; r; r = r->next) {
-		icalcomponent_remove_component (icalcomp, r->data);
-	}
-
-	if (g_slist_length (to_remove) > 1) {
-		/* there were more than once tzid as this,
-		   thus check for duplicities for all of timezones there */
-		GHashTable *known = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
-		GSList *rem2 = NULL;
-
-		for (subcomp = icalcomponent_get_first_component (icalcomp, ICAL_VTIMEZONE_COMPONENT);
-		     subcomp;
-		     subcomp = icalcomponent_get_next_component (icalcomp, ICAL_VTIMEZONE_COMPONENT)) {
-			if (!icaltimezone_set_component (zone, icalcomponent_new_clone (subcomp))) {
-				rem2 = g_slist_prepend (rem2, subcomp);
-			} else {
-				const gchar *tzid2 = icaltimezone_get_tzid (zone);
-
-				/* check all but not the one which was checked above */
-				if (tzid2 && !g_str_equal (tzid, tzid2)) {
-					if (g_hash_table_lookup (known, tzid2) == NULL) {
-						/* the first component of this tzid, keep it */
-						g_hash_table_insert (known, g_strdup (tzid2), GINT_TO_POINTER (1));
-					} else {
-						/* it's there already, remove it */
-						rem2 = g_slist_prepend (rem2, subcomp);
-					}
-				}
-			}
-		}
-
-		for (r = rem2; r; r = r->next) {
-			icalcomponent_remove_component (icalcomp, r->data);
-		}
-
-		g_slist_free (rem2);
-		g_hash_table_unref (known);
-	}
-
-	icaltimezone_free (zone, TRUE);
-	g_slist_free (to_remove);
-
-	if (add)
-		icalcomponent_add_component (icalcomp, icalcomponent_new_clone (icaltimezone_get_component (tzone)));
-
-	return add || to_remove != NULL;
-}
-
 static void
 source_changed_cb (ESource *source, ECalBackend *backend)
 {
@@ -1334,8 +1228,7 @@ source_changed_cb (ESource *source, ECalBackend *backend)
 
 /* Open handler for the file backend */
 static void
-e_cal_backend_file_open (ECalBackendSync *backend, EDataCal *cal, gboolean only_if_exists,
-			 const gchar *username, const gchar *password, GError **perror)
+e_cal_backend_file_open (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, gboolean only_if_exists, GError **perror)
 {
 	ECalBackendFile *cbfile;
 	ECalBackendFilePrivate *priv;
@@ -1381,23 +1274,23 @@ e_cal_backend_file_open (ECalBackendSync *backend, EDataCal *cal, gboolean only_
 					priv->read_only = TRUE;
 			}
 		}
-
-		if (priv->default_zone && add_timezone (priv->icalcomp, priv->default_zone)) {
-			save (cbfile);
-		}
 	}
 
 	g_free (str_uri);
 
   done:
 	g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
+	e_cal_backend_notify_readonly (E_CAL_BACKEND (backend), priv->read_only);
+	e_cal_backend_notify_online (E_CAL_BACKEND (backend), TRUE);
 
 	if (err)
-		g_propagate_error (perror, err);
+		g_propagate_error (perror, g_error_copy (err));
+
+	e_cal_backend_notify_opened (E_CAL_BACKEND (backend), err);
 }
 
 static void
-e_cal_backend_file_remove (ECalBackendSync *backend, EDataCal *cal, GError **perror)
+e_cal_backend_file_remove (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, GError **perror)
 {
 	ECalBackendFile *cbfile;
 	ECalBackendFilePrivate *priv;
@@ -1441,6 +1334,11 @@ e_cal_backend_file_remove (ECalBackendSync *backend, EDataCal *cal, GError **per
 		full_path = NULL;
 	}
 
+	if (dir) {
+		g_dir_close (dir);
+		dir = NULL;
+	}
+
 	/* remove the directory itself */
 	if (g_rmdir (dirname) != 0) {
 		err = EDC_ERROR (OtherError);
@@ -1448,77 +1346,31 @@ e_cal_backend_file_remove (ECalBackendSync *backend, EDataCal *cal, GError **per
 
   done:
 	if (dir) {
-	    g_dir_close (dir);
+		g_dir_close (dir);
+		dir = NULL;
 	}
-	g_free (str_uri);
-	g_free (dirname);
-	g_free (full_path);
-
-	g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
 
 	/* lie here a bit, but otherwise the calendar will not be removed, even it should */
 	if (err) {
-		g_print (G_STRLOC ": %s", err->message);
+		g_print (G_STRLOC ": %s on dir '%s' from uri '%s'\n", err->message, dirname, str_uri);
 		g_error_free (err);
 	}
 
-	if (error)
-		g_error_free (error);
-}
-
-/* is_loaded handler for the file backend */
-static gboolean
-e_cal_backend_file_is_loaded (ECalBackend *backend)
-{
-	ECalBackendFile *cbfile;
-	ECalBackendFilePrivate *priv;
-
-	cbfile = E_CAL_BACKEND_FILE (backend);
-	priv = cbfile->priv;
+	g_free (str_uri);
+	g_free (dirname);
+	g_free (full_path);
 
-	return (priv->icalcomp != NULL);
-}
+	g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
 
-/* is_remote handler for the file backend */
-static CalMode
-e_cal_backend_file_get_mode (ECalBackend *backend)
-{
-	return CAL_MODE_LOCAL;
+	if (error)
+		g_error_free (error);
 }
 
 /* Set_mode handler for the file backend */
 static void
-e_cal_backend_file_set_mode (ECalBackend *backend, CalMode mode)
-{
-	e_cal_backend_notify_mode (backend, ModeNotSupported, Local);
-
-}
-
-static void
-e_cal_backend_file_get_default_object (ECalBackendSync *backend, EDataCal *cal, gchar **object, GError **perror)
+e_cal_backend_file_set_online (ECalBackend *backend, gboolean is_online)
 {
-	ECalComponent *comp;
-
-	comp = e_cal_component_new ();
-
-	switch (e_cal_backend_get_kind (E_CAL_BACKEND (backend))) {
-	case ICAL_VEVENT_COMPONENT:
-		e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_EVENT);
-		break;
-	case ICAL_VTODO_COMPONENT:
-		e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_TODO);
-		break;
-	case ICAL_VJOURNAL_COMPONENT:
-		e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_JOURNAL);
-		break;
-	default:
-		g_object_unref (comp);
-		g_propagate_error (perror, EDC_ERROR (ObjectNotFound));
-		return;
-	}
-
-	*object = e_cal_component_get_as_string (comp);
-	g_object_unref (comp);
+	e_cal_backend_notify_online (backend, TRUE);
 }
 
 static void
@@ -1534,7 +1386,7 @@ add_detached_recur_to_vcalendar (gpointer key, gpointer value, gpointer user_dat
 
 /* Get_object_component handler for the file backend */
 static void
-e_cal_backend_file_get_object (ECalBackendSync *backend, EDataCal *cal, const gchar *uid, const gchar *rid, gchar **object, GError **error)
+e_cal_backend_file_get_object (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *uid, const gchar *rid, gchar **object, GError **error)
 {
 	ECalBackendFile *cbfile;
 	ECalBackendFilePrivate *priv;
@@ -1614,7 +1466,7 @@ e_cal_backend_file_get_object (ECalBackendSync *backend, EDataCal *cal, const gc
 
 /* Add_timezone handler for the file backend */
 static void
-e_cal_backend_file_add_timezone (ECalBackendSync *backend, EDataCal *cal, const gchar *tzobj, GError **error)
+e_cal_backend_file_add_timezone (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *tzobj, GError **error)
 {
 	icalcomponent *tz_comp;
 	ECalBackendFile *cbfile;
@@ -1651,46 +1503,12 @@ e_cal_backend_file_add_timezone (ECalBackendSync *backend, EDataCal *cal, const
 	}
 }
 
-static void
-e_cal_backend_file_set_default_zone (ECalBackendSync *backend, EDataCal *cal, const gchar *tzobj, GError **error)
-{
-	icalcomponent *tz_comp;
-	ECalBackendFile *cbfile;
-	ECalBackendFilePrivate *priv;
-	icaltimezone *zone;
-
-	cbfile = (ECalBackendFile *) backend;
-
-	e_return_data_cal_error_if_fail (E_IS_CAL_BACKEND_FILE (cbfile), InvalidArg);
-	e_return_data_cal_error_if_fail (tzobj != NULL, InvalidArg);
-
-	priv = cbfile->priv;
-
-	tz_comp = icalparser_parse_string (tzobj);
-	if (!tz_comp) {
-		g_propagate_error (error, EDC_ERROR (InvalidObject));
-		return;
-	}
-
-	zone = icaltimezone_new ();
-	icaltimezone_set_component (zone, tz_comp);
-
-	g_static_rec_mutex_lock (&priv->idle_save_rmutex);
-	if (priv->default_zone != icaltimezone_get_utc_timezone ())
-		icaltimezone_free (priv->default_zone, 1);
-
-	/* Set the default timezone to it. */
-	priv->default_zone = zone;
-	g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
-}
-
 typedef struct {
-	GList *obj_list;
+	GSList *obj_list;
 	gboolean search_needed;
 	const gchar *query;
 	ECalBackendSExp *obj_sexp;
 	ECalBackend *backend;
-	icaltimezone *default_zone;
 } MatchObjectData;
 
 static void
@@ -1715,8 +1533,7 @@ match_object_sexp_to_component (gpointer value, gpointer data)
 
 	if ((!match_data->search_needed) ||
 	    (e_cal_backend_sexp_match_comp (match_data->obj_sexp, comp, match_data->backend))) {
-		match_data->obj_list = g_list_append (match_data->obj_list,
-						      e_cal_component_get_as_string (comp));
+		match_data->obj_list = g_slist_append (match_data->obj_list, e_cal_component_get_as_string (comp));
 	}
 }
 
@@ -1728,8 +1545,7 @@ match_recurrence_sexp (gpointer key, gpointer value, gpointer data)
 
 	if ((!match_data->search_needed) ||
 	    (e_cal_backend_sexp_match_comp (match_data->obj_sexp, comp, match_data->backend))) {
-		match_data->obj_list = g_list_append (match_data->obj_list,
-						      e_cal_component_get_as_string (comp));
+		match_data->obj_list = g_slist_append (match_data->obj_list, e_cal_component_get_as_string (comp));
 	}
 }
 
@@ -1742,8 +1558,7 @@ match_object_sexp (gpointer key, gpointer value, gpointer data)
 	if (obj_data->full_object) {
 		if ((!match_data->search_needed) ||
 		    (e_cal_backend_sexp_match_comp (match_data->obj_sexp, obj_data->full_object, match_data->backend))) {
-			match_data->obj_list = g_list_append (match_data->obj_list,
-							      e_cal_component_get_as_string (obj_data->full_object));
+			match_data->obj_list = g_slist_append (match_data->obj_list, e_cal_component_get_as_string (obj_data->full_object));
 		}
 	}
 
@@ -1755,7 +1570,7 @@ match_object_sexp (gpointer key, gpointer value, gpointer data)
 
 /* Get_objects_in_range handler for the file backend */
 static void
-e_cal_backend_file_get_object_list (ECalBackendSync *backend, EDataCal *cal, const gchar *sexp, GList **objects, GError **perror)
+e_cal_backend_file_get_object_list (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *sexp, GSList **objects, GError **perror)
 {
 	ECalBackendFile *cbfile;
 	ECalBackendFilePrivate *priv;
@@ -1772,7 +1587,6 @@ e_cal_backend_file_get_object_list (ECalBackendSync *backend, EDataCal *cal, con
 	match_data.query = sexp;
 	match_data.obj_list = NULL;
 	match_data.backend = E_CAL_BACKEND (backend);
-	match_data.default_zone = priv->default_zone;
 
 	if (!strcmp (sexp, "#t"))
 		match_data.search_needed = FALSE;
@@ -1814,17 +1628,124 @@ e_cal_backend_file_get_object_list (ECalBackendSync *backend, EDataCal *cal, con
 	g_object_unref (match_data.obj_sexp);
 }
 
+static void
+add_attach_uris (GSList **attachment_uris, icalcomponent *icalcomp)
+{
+	icalproperty *prop;
+
+	g_return_if_fail (attachment_uris != NULL);
+	g_return_if_fail (icalcomp != NULL);
+
+	for (prop = icalcomponent_get_first_property (icalcomp, ICAL_ATTACH_PROPERTY);
+	     prop;
+	     prop = icalcomponent_get_next_property (icalcomp, ICAL_ATTACH_PROPERTY)) {
+		icalattach *attach = icalproperty_get_attach (prop);
+
+		if (attach && icalattach_get_is_url (attach)) {
+			const gchar *url;
+
+			url = icalattach_get_url (attach);
+			if (url) {
+				gsize buf_size;
+				gchar *buf;
+
+				buf_size = strlen (url);
+				buf = g_malloc0 (buf_size + 1);
+
+				icalvalue_decode_ical_string (url, buf, buf_size);
+
+				*attachment_uris = g_slist_prepend (*attachment_uris, g_strdup (buf));
+
+				g_free (buf);
+			}
+		}
+	}
+}
+
+static void
+add_detached_recur_attach_uris (gpointer key, gpointer value, gpointer user_data)
+{
+	ECalComponent *recurrence = value;
+	GSList **attachment_uris = user_data;
+
+	add_attach_uris (attachment_uris, e_cal_component_get_icalcomponent (recurrence));
+}
+
 /* Gets the list of attachments */
 static void
-e_cal_backend_file_get_attachment_list (ECalBackendSync *backend, EDataCal *cal, const gchar *uid, const gchar *rid, GSList **list, GError **perror)
+e_cal_backend_file_get_attachment_uris (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *uid, const gchar *rid, GSList **attachment_uris, GError **error)
 {
+	ECalBackendFile *cbfile;
+	ECalBackendFilePrivate *priv;
+	ECalBackendFileObject *obj_data;
+
+	cbfile = E_CAL_BACKEND_FILE (backend);
+	priv = cbfile->priv;
+
+	e_return_data_cal_error_if_fail (priv->icalcomp != NULL, InvalidObject);
+	e_return_data_cal_error_if_fail (uid != NULL, ObjectNotFound);
+	e_return_data_cal_error_if_fail (attachment_uris != NULL, InvalidArg);
+	g_assert (priv->comp_uid_hash != NULL);
+
+	g_static_rec_mutex_lock (&priv->idle_save_rmutex);
+
+	obj_data = g_hash_table_lookup (priv->comp_uid_hash, uid);
+	if (!obj_data) {
+		g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
+		g_propagate_error (error, EDC_ERROR (ObjectNotFound));
+		return;
+	}
+
+	if (rid && *rid) {
+		ECalComponent *comp;
+
+		comp = g_hash_table_lookup (obj_data->recurrences, rid);
+		if (comp) {
+			add_attach_uris (attachment_uris, e_cal_component_get_icalcomponent (comp));
+		} else {
+			icalcomponent *icalcomp;
+			struct icaltimetype itt;
+
+			if (!obj_data->full_object) {
+				g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
+				g_propagate_error (error, EDC_ERROR (ObjectNotFound));
+				return;
+			}
+
+			itt = icaltime_from_string (rid);
+			icalcomp = e_cal_util_construct_instance (
+				e_cal_component_get_icalcomponent (obj_data->full_object),
+				itt);
+			if (!icalcomp) {
+				g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
+				g_propagate_error (error, EDC_ERROR (ObjectNotFound));
+				return;
+			}
+
+			add_attach_uris (attachment_uris, icalcomp);
 
-	/* TODO implement the function */
+			icalcomponent_free (icalcomp);
+		}
+	} else {
+		if (g_hash_table_size (obj_data->recurrences) > 0) {
+			/* detached recurrences don't have full_object */
+			if (obj_data->full_object)
+				add_attach_uris (attachment_uris, e_cal_component_get_icalcomponent (obj_data->full_object));
+
+			/* add all detached recurrences */
+			g_hash_table_foreach (obj_data->recurrences, add_detached_recur_attach_uris, attachment_uris);
+		} else if (obj_data->full_object)
+			add_attach_uris (attachment_uris, e_cal_component_get_icalcomponent (obj_data->full_object));
+	}
+
+	*attachment_uris = g_slist_reverse (*attachment_uris);
+
+	g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
 }
 
 /* get_query handler for the file backend */
 static void
-e_cal_backend_file_start_query (ECalBackend *backend, EDataCalView *query)
+e_cal_backend_file_start_view (ECalBackend *backend, EDataCalView *query)
 {
 	ECalBackendFile *cbfile;
 	ECalBackendFilePrivate *priv;
@@ -1842,7 +1763,6 @@ e_cal_backend_file_start_query (ECalBackend *backend, EDataCalView *query)
 	match_data.query = e_data_cal_view_get_text (query);
 	match_data.obj_list = NULL;
 	match_data.backend = backend;
-	match_data.default_zone = priv->default_zone;
 	match_data.obj_sexp = e_data_cal_view_get_object_sexp (query);
 
 	if (!strcmp (match_data.query, "#t"))
@@ -1850,7 +1770,7 @@ e_cal_backend_file_start_query (ECalBackend *backend, EDataCalView *query)
 
 	if (!match_data.obj_sexp) {
 		GError *error = EDC_ERROR (InvalidQuery);
-		e_data_cal_view_notify_done (query, error);
+		e_data_cal_view_notify_complete (query, error);
 		g_error_free (error);
 		return;
 	}
@@ -1887,11 +1807,11 @@ e_cal_backend_file_start_query (ECalBackend *backend, EDataCalView *query)
 
 	/* notify listeners of all objects */
 	if (match_data.obj_list) {
-		e_data_cal_view_notify_objects_added (query, (const GList *) match_data.obj_list);
+		e_data_cal_view_notify_objects_added (query, match_data.obj_list);
 
 		/* free memory */
-		g_list_foreach (match_data.obj_list, (GFunc) g_free, NULL);
-		g_list_free (match_data.obj_list);
+		g_slist_foreach (match_data.obj_list, (GFunc) g_free, NULL);
+		g_slist_free (match_data.obj_list);
 	}
 
 	if (objs_occuring_in_tw) {
@@ -1900,7 +1820,7 @@ e_cal_backend_file_start_query (ECalBackend *backend, EDataCalView *query)
 	}
 	g_object_unref (match_data.obj_sexp);
 
-	e_data_cal_view_notify_done (query, NULL /* Success */);
+	e_data_cal_view_notify_complete (query, NULL /* Success */);
 }
 
 static gboolean
@@ -2005,7 +1925,7 @@ create_user_free_busy (ECalBackendFile *cbfile, const gchar *address, const gcha
 						vfb,
 						resolve_tzid,
 						vcalendar_comp,
-						priv->default_zone);
+						icaltimezone_get_utc_timezone ());
 	}
 	g_object_unref (obj_sexp);
 
@@ -2014,15 +1934,15 @@ create_user_free_busy (ECalBackendFile *cbfile, const gchar *address, const gcha
 
 /* Get_free_busy handler for the file backend */
 static void
-e_cal_backend_file_get_free_busy (ECalBackendSync *backend, EDataCal *cal, GList *users,
-				time_t start, time_t end, GList **freebusy, GError **error)
+e_cal_backend_file_get_free_busy (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const GSList *users,
+				time_t start, time_t end, GSList **freebusy, GError **error)
 {
 	ECalBackendFile *cbfile;
 	ECalBackendFilePrivate *priv;
 	gchar *address, *name;
 	icalcomponent *vfb;
 	gchar *calobj;
-	GList *l;
+	const GSList *l;
 
 	cbfile = E_CAL_BACKEND_FILE (backend);
 	priv = cbfile->priv;
@@ -2039,7 +1959,7 @@ e_cal_backend_file_get_free_busy (ECalBackendSync *backend, EDataCal *cal, GList
 		if (e_cal_backend_mail_account_get_default (&address, &name)) {
 			vfb = create_user_free_busy (cbfile, address, name, start, end);
 			calobj = icalcomponent_as_ical_string_r (vfb);
-			*freebusy = g_list_append (*freebusy, calobj);
+			*freebusy = g_slist_append (*freebusy, calobj);
 			icalcomponent_free (vfb);
 			g_free (address);
 			g_free (name);
@@ -2050,7 +1970,7 @@ e_cal_backend_file_get_free_busy (ECalBackendSync *backend, EDataCal *cal, GList
 			if (e_cal_backend_mail_account_is_valid (address, &name)) {
 				vfb = create_user_free_busy (cbfile, address, name, start, end);
 				calobj = icalcomponent_as_ical_string_r (vfb);
-				*freebusy = g_list_append (*freebusy, calobj);
+				*freebusy = g_slist_append (*freebusy, calobj);
 				icalcomponent_free (vfb);
 				g_free (name);
 			}
@@ -2060,145 +1980,6 @@ e_cal_backend_file_get_free_busy (ECalBackendSync *backend, EDataCal *cal, GList
 	g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
 }
 
-typedef struct
-{
-	ECalBackendFile *backend;
-	icalcomponent_kind kind;
-	GList *deletes;
-	EXmlHash *ehash;
-} ECalBackendFileComputeChangesData;
-
-static gboolean
-e_cal_backend_file_compute_changes_foreach_key (const gchar *key, gpointer value, gpointer data)
-{
-	ECalBackendFileComputeChangesData *be_data = data;
-
-	if (!lookup_component (be_data->backend, key)) {
-		ECalComponent *comp;
-
-		comp = e_cal_component_new ();
-		if (be_data->kind == ICAL_VTODO_COMPONENT)
-			e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_TODO);
-		else
-			e_cal_component_set_new_vtype (comp, E_CAL_COMPONENT_EVENT);
-
-		e_cal_component_set_uid (comp, key);
-		be_data->deletes = g_list_prepend (be_data->deletes, e_cal_component_get_as_string (comp));
-
-		g_object_unref (comp);
-		return TRUE;
-	}
-	return FALSE;
-}
-
-static void
-e_cal_backend_file_compute_changes (ECalBackendFile *cbfile, const gchar *change_id,
-				    GList **adds, GList **modifies, GList **deletes, GError **perror)
-{
-	ECalBackendFilePrivate *priv;
-	gchar    *filename;
-	EXmlHash *ehash;
-	ECalBackendFileComputeChangesData be_data;
-	GList *i;
-	gchar *unescaped_uri;
-
-	priv = cbfile->priv;
-
-	/* FIXME Will this always work? */
-	unescaped_uri = g_uri_unescape_string (priv->path, "");
-	filename = g_strdup_printf ("%s-%s.db", unescaped_uri, change_id);
-	g_free (unescaped_uri);
-	if (!(ehash = e_xmlhash_new (filename))) {
-		g_free (filename);
-		g_propagate_error (perror, EDC_ERROR (OtherError));
-		return;
-	}
-
-	g_free (filename);
-
-	g_static_rec_mutex_lock (&priv->idle_save_rmutex);
-
-	/* Calculate adds and modifies */
-	for (i = priv->comp; i != NULL; i = i->next) {
-		const gchar *uid;
-		gchar *calobj;
-
-		e_cal_component_get_uid (i->data, &uid);
-		calobj = e_cal_component_get_as_string (i->data);
-
-		g_assert (calobj != NULL);
-
-		/* check what type of change has occurred, if any */
-		switch (e_xmlhash_compare (ehash, uid, calobj)) {
-		case E_XMLHASH_STATUS_SAME:
-			break;
-		case E_XMLHASH_STATUS_NOT_FOUND:
-			*adds = g_list_prepend (*adds, g_strdup (calobj));
-			e_xmlhash_add (ehash, uid, calobj);
-			break;
-		case E_XMLHASH_STATUS_DIFFERENT:
-			*modifies = g_list_prepend (*modifies, g_strdup (calobj));
-			e_xmlhash_add (ehash, uid, calobj);
-			break;
-		}
-
-		g_free (calobj);
-	}
-
-	/* Calculate deletions */
-	be_data.backend = cbfile;
-	be_data.kind = e_cal_backend_get_kind (E_CAL_BACKEND (cbfile));
-	be_data.deletes = NULL;
-	be_data.ehash = ehash;
-
-	e_xmlhash_foreach_key_remove (ehash, (EXmlHashRemoveFunc) e_cal_backend_file_compute_changes_foreach_key, &be_data);
-
-	*deletes = be_data.deletes;
-
-	e_xmlhash_write (ehash);
-	e_xmlhash_destroy (ehash);
-
-	g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
-}
-
-/* Get_changes handler for the file backend */
-static void
-e_cal_backend_file_get_changes (ECalBackendSync *backend, EDataCal *cal, const gchar *change_id,
-			      GList **adds, GList **modifies, GList **deletes, GError **error)
-{
-	ECalBackendFile *cbfile;
-	ECalBackendFilePrivate *priv;
-
-	cbfile = E_CAL_BACKEND_FILE (backend);
-	priv = cbfile->priv;
-
-	e_return_data_cal_error_if_fail (priv->icalcomp != NULL, NoSuchCal);
-	e_return_data_cal_error_if_fail (change_id != NULL, ObjectNotFound);
-
-	e_cal_backend_file_compute_changes (cbfile, change_id, adds, modifies, deletes, error);
-}
-
-/* Discard_alarm handler for the file backend */
-static void
-e_cal_backend_file_discard_alarm (ECalBackendSync *backend, EDataCal *cal, const gchar *uid, const gchar *auid, GError **perror)
-{
-	/* we just do nothing with the alarm */
-}
-
-static icaltimezone *
-e_cal_backend_file_internal_get_default_timezone (ECalBackend *backend)
-{
-	ECalBackendFile *cbfile;
-	ECalBackendFilePrivate *priv;
-
-	cbfile = E_CAL_BACKEND_FILE (backend);
-	priv = cbfile->priv;
-
-	g_return_val_if_fail (priv->icalcomp != NULL, NULL);
-
-	return priv->default_zone;
-}
-
 static icaltimezone *
 e_cal_backend_file_internal_get_timezone (ECalBackend *backend, const gchar *tzid)
 {
@@ -2230,7 +2011,7 @@ static void
 sanitize_component (ECalBackendFile *cbfile, ECalComponent *comp)
 {
 	ECalComponentDateTime dt;
-	icaltimezone *zone, *default_zone;
+	icaltimezone *zone;
 
 	/* Check dtstart, dtend and due's timezone, and convert it to local
 	 * default timezone if the timezone is not in our builtin timezone
@@ -2239,9 +2020,8 @@ sanitize_component (ECalBackendFile *cbfile, ECalComponent *comp)
 	if (dt.value && dt.tzid) {
 		zone = e_cal_backend_file_internal_get_timezone ((ECalBackend *) cbfile, dt.tzid);
 		if (!zone) {
-			default_zone = e_cal_backend_file_internal_get_default_timezone ((ECalBackend *) cbfile);
 			g_free ((gchar *) dt.tzid);
-			dt.tzid = g_strdup (icaltimezone_get_tzid (default_zone));
+			dt.tzid = g_strdup ("UTC");
 			e_cal_component_set_dtstart (comp, &dt);
 		}
 	}
@@ -2251,9 +2031,8 @@ sanitize_component (ECalBackendFile *cbfile, ECalComponent *comp)
 	if (dt.value && dt.tzid) {
 		zone = e_cal_backend_file_internal_get_timezone ((ECalBackend *) cbfile, dt.tzid);
 		if (!zone) {
-			default_zone = e_cal_backend_file_internal_get_default_timezone ((ECalBackend *) cbfile);
 			g_free ((gchar *) dt.tzid);
-			dt.tzid = g_strdup (icaltimezone_get_tzid (default_zone));
+			dt.tzid = g_strdup ("UTC");
 			e_cal_component_set_dtend (comp, &dt);
 		}
 	}
@@ -2263,9 +2042,8 @@ sanitize_component (ECalBackendFile *cbfile, ECalComponent *comp)
 	if (dt.value && dt.tzid) {
 		zone = e_cal_backend_file_internal_get_timezone ((ECalBackend *) cbfile, dt.tzid);
 		if (!zone) {
-			default_zone = e_cal_backend_file_internal_get_default_timezone ((ECalBackend *) cbfile);
 			g_free ((gchar *) dt.tzid);
-			dt.tzid = g_strdup (icaltimezone_get_tzid (default_zone));
+			dt.tzid = g_strdup ("UTC");
 			e_cal_component_set_due (comp, &dt);
 		}
 	}
@@ -2275,7 +2053,7 @@ sanitize_component (ECalBackendFile *cbfile, ECalComponent *comp)
 }
 
 static void
-e_cal_backend_file_create_object (ECalBackendSync *backend, EDataCal *cal, gchar **calobj, gchar **uid, GError **error)
+e_cal_backend_file_create_object (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *in_calobj, gchar **uid, gchar **new_object, GError **error)
 {
 	ECalBackendFile *cbfile;
 	ECalBackendFilePrivate *priv;
@@ -2288,10 +2066,11 @@ e_cal_backend_file_create_object (ECalBackendSync *backend, EDataCal *cal, gchar
 	priv = cbfile->priv;
 
 	e_return_data_cal_error_if_fail (priv->icalcomp != NULL, NoSuchCal);
-	e_return_data_cal_error_if_fail (*calobj != NULL, ObjectNotFound);
+	e_return_data_cal_error_if_fail (in_calobj != NULL, ObjectNotFound);
+	e_return_data_cal_error_if_fail (new_object != NULL, ObjectNotFound);
 
 	/* Parse the icalendar text */
-	icalcomp = icalparser_parse_string (*calobj);
+	icalcomp = icalparser_parse_string (in_calobj);
 	if (!icalcomp) {
 		g_propagate_error (error, EDC_ERROR (InvalidObject));
 		return;
@@ -2354,7 +2133,7 @@ e_cal_backend_file_create_object (ECalBackendSync *backend, EDataCal *cal, gchar
 	/* Return the UID and the modified component */
 	if (uid)
 		*uid = g_strdup (comp_uid);
-	*calobj = e_cal_component_get_as_string (comp);
+	*new_object = e_cal_component_get_as_string (comp);
 
 	g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
 }
@@ -2394,7 +2173,7 @@ remove_object_instance_cb (gpointer key, gpointer value, gpointer user_data)
 }
 
 static void
-e_cal_backend_file_modify_object (ECalBackendSync *backend, EDataCal *cal, const gchar *calobj,
+e_cal_backend_file_modify_object (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj,
 				  CalObjModType mod, gchar **old_object, gchar **new_object, GError **error)
 {
 	RemoveRecurrenceData rrdata;
@@ -2692,7 +2471,7 @@ get_object_string_from_fileobject (ECalBackendFileObject *obj_data, const gchar
 
 /* Remove_object handler for the file backend */
 static void
-e_cal_backend_file_remove_object (ECalBackendSync *backend, EDataCal *cal,
+e_cal_backend_file_remove_object (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable,
 				  const gchar *uid, const gchar *rid,
 				  CalObjModType mod, gchar **old_object,
 				  gchar **object, GError **error)
@@ -2921,7 +2700,7 @@ fetch_attachments (ECalBackendSync *backend, ECalComponent *comp)
 
 /* Update_objects handler for the file backend. */
 static void
-e_cal_backend_file_receive_objects (ECalBackendSync *backend, EDataCal *cal, const gchar *calobj, GError **error)
+e_cal_backend_file_receive_objects (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, GError **error)
 {
 	ECalBackendFile *cbfile;
 	ECalBackendFilePrivate *priv;
@@ -3185,7 +2964,7 @@ e_cal_backend_file_receive_objects (ECalBackendSync *backend, EDataCal *cal, con
 }
 
 static void
-e_cal_backend_file_send_objects (ECalBackendSync *backend, EDataCal *cal, const gchar *calobj, GList **users,
+e_cal_backend_file_send_objects (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, GSList **users,
 				 gchar **modified_calobj, GError **perror)
 {
 	*users = NULL;
@@ -3214,9 +2993,6 @@ e_cal_backend_file_init (ECalBackendFile *cbfile)
 	priv->custom_file = NULL;
 	priv->refresh_lock = g_mutex_new ();
 
-	/* The timezone defaults to UTC. */
-	priv->default_zone = icaltimezone_get_utc_timezone ();
-
         /*
          * data access is serialized via idle_save_rmutex, so locking at the
          * backend method level is not needed
@@ -3297,35 +3073,23 @@ e_cal_backend_file_class_init (ECalBackendFileClass *class)
 	object_class->finalize = e_cal_backend_file_finalize;
 	object_class->constructed = cal_backend_file_constructed;
 
-	sync_class->is_read_only_sync = e_cal_backend_file_is_read_only;
-	sync_class->get_cal_address_sync = e_cal_backend_file_get_cal_address;
-	sync_class->get_alarm_email_address_sync = e_cal_backend_file_get_alarm_email_address;
-	sync_class->get_ldap_attribute_sync = e_cal_backend_file_get_ldap_attribute;
-	sync_class->get_static_capabilities_sync = e_cal_backend_file_get_static_capabilities;
-	sync_class->open_sync = e_cal_backend_file_open;
-	sync_class->remove_sync = e_cal_backend_file_remove;
-	sync_class->create_object_sync = e_cal_backend_file_create_object;
-	sync_class->modify_object_sync = e_cal_backend_file_modify_object;
-	sync_class->remove_object_sync = e_cal_backend_file_remove_object;
-	sync_class->discard_alarm_sync = e_cal_backend_file_discard_alarm;
-	sync_class->receive_objects_sync = e_cal_backend_file_receive_objects;
-	sync_class->send_objects_sync = e_cal_backend_file_send_objects;
-	sync_class->get_default_object_sync = e_cal_backend_file_get_default_object;
-	sync_class->get_object_sync = e_cal_backend_file_get_object;
-	sync_class->get_object_list_sync = e_cal_backend_file_get_object_list;
-	sync_class->get_attachment_list_sync = e_cal_backend_file_get_attachment_list;
-	sync_class->add_timezone_sync = e_cal_backend_file_add_timezone;
-	sync_class->set_default_zone_sync = e_cal_backend_file_set_default_zone;
-	sync_class->get_freebusy_sync = e_cal_backend_file_get_free_busy;
-	sync_class->get_changes_sync = e_cal_backend_file_get_changes;
-
-	backend_class->is_loaded = e_cal_backend_file_is_loaded;
-	backend_class->start_query = e_cal_backend_file_start_query;
-	backend_class->get_mode = e_cal_backend_file_get_mode;
-	backend_class->set_mode = e_cal_backend_file_set_mode;
-
-	backend_class->internal_get_default_timezone = e_cal_backend_file_internal_get_default_timezone;
-	backend_class->internal_get_timezone = e_cal_backend_file_internal_get_timezone;
+	sync_class->get_backend_property_sync	= e_cal_backend_file_get_backend_property;
+	sync_class->open_sync			= e_cal_backend_file_open;
+	sync_class->remove_sync			= e_cal_backend_file_remove;
+	sync_class->create_object_sync		= e_cal_backend_file_create_object;
+	sync_class->modify_object_sync		= e_cal_backend_file_modify_object;
+	sync_class->remove_object_sync		= e_cal_backend_file_remove_object;
+	sync_class->receive_objects_sync	= e_cal_backend_file_receive_objects;
+	sync_class->send_objects_sync		= e_cal_backend_file_send_objects;
+	sync_class->get_object_sync		= e_cal_backend_file_get_object;
+	sync_class->get_object_list_sync	= e_cal_backend_file_get_object_list;
+	sync_class->get_attachment_uris_sync	= e_cal_backend_file_get_attachment_uris;
+	sync_class->add_timezone_sync		= e_cal_backend_file_add_timezone;
+	sync_class->get_free_busy_sync		= e_cal_backend_file_get_free_busy;
+
+	backend_class->start_view		= e_cal_backend_file_start_view;
+	backend_class->set_online		= e_cal_backend_file_set_online;
+	backend_class->internal_get_timezone	= e_cal_backend_file_internal_get_timezone;
 }
 
 void
@@ -3395,6 +3159,7 @@ e_cal_backend_file_reload (ECalBackendFile *cbfile, GError **perror)
 	}
   done:
 	g_static_rec_mutex_unlock (&priv->idle_save_rmutex);
+	e_cal_backend_notify_readonly (E_CAL_BACKEND (cbfile), cbfile->priv->read_only);
 
 	if (err)
 		g_propagate_error (perror, err);
@@ -3404,7 +3169,7 @@ e_cal_backend_file_reload (ECalBackendFile *cbfile, GError **perror)
 #include <glib.h>
 
 static void
-test_query_by_scanning_all_objects (ECalBackendFile* cbfile, const gchar *sexp, GList **objects)
+test_query_by_scanning_all_objects (ECalBackendFile* cbfile, const gchar *sexp, GSList **objects)
 {
 	MatchObjectData match_data;
 	ECalBackendFilePrivate *priv;
@@ -3414,7 +3179,6 @@ test_query_by_scanning_all_objects (ECalBackendFile* cbfile, const gchar *sexp,
 	match_data.search_needed = TRUE;
 	match_data.query = sexp;
 	match_data.obj_list = NULL;
-	match_data.default_zone = priv->default_zone;
 	match_data.backend = E_CAL_BACKEND (cbfile);
 
 	if (!strcmp (sexp, "#t"))
@@ -3443,9 +3207,9 @@ test_query_by_scanning_all_objects (ECalBackendFile* cbfile, const gchar *sexp,
 }
 
 static void
-write_list (GList* list)
+write_list (GSList* list)
 {
-	GList *l;
+	GSList *l;
 
 	for (l = list; l; l = l->next)
 	{
@@ -3458,9 +3222,9 @@ write_list (GList* list)
 }
 
 static void
-get_difference_of_lists (ECalBackendFile* cbfile, GList* smaller, GList* bigger)
+get_difference_of_lists (ECalBackendFile* cbfile, GSList* smaller, GSList* bigger)
 {
-	GList *l, *lsmaller;
+	GSList *l, *lsmaller;
 
 	for (l = bigger; l; l = l->next) {
 		gchar *str = l->data;
@@ -3488,7 +3252,7 @@ get_difference_of_lists (ECalBackendFile* cbfile, GList* smaller, GList* bigger)
 
 			e_cal_util_get_component_occur_times (comp, &time_start, &time_end,
 						   resolve_tzid, cbfile->priv->icalcomp,
-						   cbfile->priv->default_zone,
+						   icaltimezone_get_utc_timezone (),
 						   e_cal_backend_get_kind (E_CAL_BACKEND (cbfile)));
 
 			d (printf ("start %s\n", asctime(gmtime(&time_start))));
@@ -3502,27 +3266,27 @@ get_difference_of_lists (ECalBackendFile* cbfile, GList* smaller, GList* bigger)
 static void
 test_query (ECalBackendFile* cbfile, const gchar * query)
 {
-	GList *objects = NULL, *all_objects = NULL;
+	GSList *objects = NULL, *all_objects = NULL;
 
 	g_return_if_fail (query != NULL);
 
 	d (g_print ("Query %s\n", query));
 
 	test_query_by_scanning_all_objects (cbfile, query, &all_objects);
-	e_cal_backend_file_get_object_list (E_CAL_BACKEND_SYNC (cbfile), NULL, query, &objects, NULL);
+	e_cal_backend_file_get_object_list (E_CAL_BACKEND_SYNC (cbfile), NULL, NULL, query, &objects, NULL);
 	if (objects == NULL)
 	{
 		g_message (G_STRLOC " failed to get objects\n");
 		exit (0);
 	}
 
-	if (g_list_length (objects) < g_list_length (all_objects) )
+	if (g_slist_length (objects) < g_slist_length (all_objects) )
 	{
 		g_print ("ERROR\n");
 		get_difference_of_lists (cbfile, objects, all_objects);
 		exit (-1);
 	}
-	else if (g_list_length (objects) > g_list_length (all_objects) )
+	else if (g_slist_length (objects) > g_slist_length (all_objects) )
 	{
 		g_print ("ERROR\n");
 		write_list (all_objects);
@@ -3530,29 +3294,29 @@ test_query (ECalBackendFile* cbfile, const gchar * query)
 		exit (-1);
 	}
 
-	g_list_foreach (objects, (GFunc) g_free, NULL);
-	g_list_free (objects);
-	g_list_foreach (all_objects, (GFunc) g_free, NULL);
-	g_list_free (all_objects);
+	g_slist_foreach (objects, (GFunc) g_free, NULL);
+	g_slist_free (objects);
+	g_slist_foreach (all_objects, (GFunc) g_free, NULL);
+	g_slist_free (all_objects);
 }
 
 static void
 execute_query (ECalBackendFile* cbfile, const gchar * query)
 {
-	GList *objects = NULL;
+	GSList *objects = NULL;
 
 	g_return_if_fail (query != NULL);
 
 	d (g_print ("Query %s\n", query));
-	e_cal_backend_file_get_object_list (E_CAL_BACKEND_SYNC (cbfile), NULL, query, &objects, NULL);
+	e_cal_backend_file_get_object_list (E_CAL_BACKEND_SYNC (cbfile), NULL, NULL, query, &objects, NULL);
 	if (objects == NULL)
 	{
 		g_message (G_STRLOC " failed to get objects\n");
 		exit (0);
 	}
 
-	g_list_foreach (objects, (GFunc) g_free, NULL);
-	g_list_free (objects);
+	g_slist_foreach (objects, (GFunc) g_free, NULL);
+	g_slist_free (objects);
 }
 
 static gchar *fname = NULL;
@@ -3700,4 +3464,3 @@ err0:
 	return 0;
 }
 #endif
-
diff --git a/calendar/backends/http/e-cal-backend-http.c b/calendar/backends/http/e-cal-backend-http.c
index 7bf25e7..e468a39 100644
--- a/calendar/backends/http/e-cal-backend-http.c
+++ b/calendar/backends/http/e-cal-backend-http.c
@@ -54,18 +54,11 @@ struct _ECalBackendHttpPrivate {
 	gchar *uri;
 
 	/* Local/remote mode */
-	CalMode mode;
+	gboolean is_online;
 
 	/* The file cache */
 	ECalBackendStore *store;
 
-	/* The calendar's default timezone, used for resolving DATE and
-	   floating DATE-TIME values. */
-	icaltimezone *default_zone;
-
-	/* The list of live queries */
-	GList *queries;
-
 	/* Soup handles for remote file */
 	SoupSession *soup_session;
 
@@ -75,9 +68,9 @@ struct _ECalBackendHttpPrivate {
 
 	/* Flags */
 	gboolean opened;
+	gboolean requires_auth;
 
-	gchar *username;
-	gchar *password;
+	ECredentials *credentials;
 };
 
 
@@ -87,7 +80,7 @@ struct _ECalBackendHttpPrivate {
 static void e_cal_backend_http_dispose (GObject *object);
 static void e_cal_backend_http_finalize (GObject *object);
 static gboolean begin_retrieval_cb (ECalBackendHttp *cbhttp);
-static void e_cal_backend_http_add_timezone (ECalBackendSync *backend, EDataCal *cal, const gchar *tzobj, GError **perror);
+static void e_cal_backend_http_add_timezone (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *tzobj, GError **perror);
 
 static ECalBackendSyncClass *parent_class;
 
@@ -103,10 +96,8 @@ e_cal_backend_http_dispose (GObject *object)
 	cbhttp = E_CAL_BACKEND_HTTP (object);
 	priv = cbhttp->priv;
 
-	g_free (priv->username);
-	g_free (priv->password);
-	priv->username = NULL;
-	priv->password = NULL;
+	e_credentials_free (priv->credentials);
+	priv->credentials = NULL;
 
 	if (priv->source_changed_id) {
 		g_signal_handler_disconnect (e_cal_backend_get_source (E_CAL_BACKEND (cbhttp)), priv->source_changed_id);
@@ -142,11 +133,6 @@ e_cal_backend_http_finalize (GObject *object)
 		priv->uri = NULL;
 	}
 
-	if (priv->default_zone) {
-		icaltimezone_free (priv->default_zone, 1);
-		priv->default_zone = NULL;
-	}
-
 	if (priv->soup_session) {
 		soup_session_abort (priv->soup_session);
 		g_object_unref (priv->soup_session);
@@ -169,45 +155,36 @@ e_cal_backend_http_finalize (GObject *object)
 
 /* Calendar backend methods */
 
-/* Is_read_only handler for the file backend */
-static void
-e_cal_backend_http_is_read_only (ECalBackendSync *backend, EDataCal *cal, gboolean *read_only, GError **perror)
-{
-	*read_only = TRUE;
-}
-
-/* Get_email_address handler for the file backend */
-static void
-e_cal_backend_http_get_cal_address (ECalBackendSync *backend, EDataCal *cal, gchar **address, GError **perror)
-{
-	/* A HTTP backend has no particular email address associated
-	 * with it (although that would be a useful feature some day).
-	 */
-	*address = NULL;
-}
-
-static void
-e_cal_backend_http_get_ldap_attribute (ECalBackendSync *backend, EDataCal *cal, gchar **attribute, GError **perror)
-{
-	*attribute = NULL;
-}
-
-static void
-e_cal_backend_http_get_alarm_email_address (ECalBackendSync *backend, EDataCal *cal, gchar **address, GError **perror)
+static gboolean
+e_cal_backend_http_get_backend_property (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *prop_name, gchar **prop_value, GError **perror)
 {
-	/* A HTTP backend has no particular email address associated
-	 * with it (although that would be a useful feature some day).
-	 */
-	*address = NULL;
-}
+	gboolean processed = TRUE;
+
+	g_return_val_if_fail (prop_name != NULL, FALSE);
+	g_return_val_if_fail (prop_value != NULL, FALSE);
+
+	if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
+		*prop_value = g_strdup (CAL_STATIC_CAPABILITY_NO_EMAIL_ALARMS ","
+					CAL_STATIC_CAPABILITY_REFRESH_SUPPORTED);
+	} else if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS) ||
+		   g_str_equal (prop_name, CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS)) {
+		/* A HTTP backend has no particular email address associated
+		 * with it (although that would be a useful feature some day).
+		 */
+		*prop_value = NULL;
+	} else if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_DEFAULT_OBJECT)) {
+		icalcomponent *icalcomp;
+		icalcomponent_kind kind;
+
+		kind = e_cal_backend_get_kind (E_CAL_BACKEND (backend));
+		icalcomp = e_cal_util_new_component (kind);
+		*prop_value = icalcomponent_as_ical_string_r (icalcomp);
+		icalcomponent_free (icalcomp);
+	} else {
+		processed = FALSE;
+	}
 
-static void
-e_cal_backend_http_get_static_capabilities (ECalBackendSync *backend, EDataCal *cal, gchar **capabilities, GError **perror)
-{
-	*capabilities = g_strdup (
-		CAL_STATIC_CAPABILITY_NO_EMAIL_ALARMS ","
-		CAL_STATIC_CAPABILITY_REFRESH_SUPPORTED
-		);
+	return processed;
 }
 
 static gchar *
@@ -346,6 +323,11 @@ put_component_to_store (ECalBackendHttp *cb,
 				changed = (sequence1 != NULL && sequence2 == NULL) ||
 					  (sequence1 == NULL && sequence2 != NULL) ||
 					  (sequence1 != NULL && sequence2 != NULL && *sequence1 != *sequence2);
+
+				if (sequence1)
+					e_cal_component_free_sequence (sequence1);
+				if (sequence2)
+					e_cal_component_free_sequence (sequence2);
 			}
 		}
 
@@ -356,7 +338,7 @@ put_component_to_store (ECalBackendHttp *cb,
 	}
 
 	e_cal_util_get_component_occur_times (comp, &time_start, &time_end,
-				   resolve_tzid, cb, priv->default_zone,
+				   resolve_tzid, cb, icaltimezone_get_utc_timezone (),
 				   e_cal_backend_get_kind (E_CAL_BACKEND (cb)));
 
 	e_cal_backend_store_put_component_with_time_range (priv->store, comp, time_start, time_end);
@@ -430,9 +412,14 @@ retrieval_done (SoupSession *session, SoupMessage *msg, ECalBackendHttp *cbhttp)
 	/* check status code */
 	if (!SOUP_STATUS_IS_SUCCESSFUL (msg->status_code)) {
 		if (!priv->opened) {
-			e_cal_backend_notify_error (E_CAL_BACKEND (cbhttp),
-				msg->reason_phrase && *msg->reason_phrase ? msg->reason_phrase :
-				(soup_status_get_phrase (msg->status_code) ? soup_status_get_phrase (msg->status_code) : _("Unknown error")));
+			if (msg->status_code == 401 || msg->status_code == 403) {
+				priv->requires_auth = TRUE;
+				e_cal_backend_notify_auth_required (E_CAL_BACKEND (cbhttp), TRUE, priv->credentials);
+				return;
+			} else
+				e_cal_backend_notify_error (E_CAL_BACKEND (cbhttp),
+					msg->reason_phrase && *msg->reason_phrase ? msg->reason_phrase :
+					(soup_status_get_phrase (msg->status_code) ? soup_status_get_phrase (msg->status_code) : _("Unknown error")));
 		}
 
 		empty_cache (cbhttp);
@@ -564,11 +551,10 @@ soup_authenticate (SoupSession  *session,
 	cbhttp = E_CAL_BACKEND_HTTP (data);
 	priv =  cbhttp->priv;
 
-	soup_auth_authenticate (auth, priv->username, priv->password);
-
-	priv->username = NULL;
-	priv->password = NULL;
-
+	if (!retrying && priv->credentials && e_credentials_has_key (priv->credentials, E_CREDENTIALS_KEY_USERNAME)) {
+		soup_auth_authenticate (auth, e_credentials_peek (priv->credentials, E_CREDENTIALS_KEY_USERNAME), e_credentials_peek (priv->credentials, E_CREDENTIALS_KEY_PASSWORD));
+		e_credentials_clear_peek (priv->credentials);
+	}
 }
 
 static gboolean reload_cb                  (ECalBackendHttp *cbhttp);
@@ -582,7 +568,7 @@ begin_retrieval_cb (ECalBackendHttp *cbhttp)
 
 	priv = cbhttp->priv;
 
-	if (priv->mode != CAL_MODE_REMOTE)
+	if (!priv->is_online)
 		return FALSE;
 
 	maybe_start_reload_timeout (cbhttp);
@@ -733,8 +719,7 @@ source_changed_cb (ESource *source, ECalBackendHttp *cbhttp)
 
 /* Open handler for the file backend */
 static void
-e_cal_backend_http_open (ECalBackendSync *backend, EDataCal *cal, gboolean only_if_exists,
-			 const gchar *username, const gchar *password, GError **perror)
+e_cal_backend_http_open (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, gboolean only_if_exists, GError **perror)
 {
 	ECalBackendHttp *cbhttp;
 	ECalBackendHttpPrivate *priv;
@@ -745,8 +730,10 @@ e_cal_backend_http_open (ECalBackendSync *backend, EDataCal *cal, gboolean only_
 	priv = cbhttp->priv;
 
 	/* already opened, thus can skip all this initialization */
-	if (priv->opened)
+	if (priv->opened) {
+		e_cal_backend_notify_opened (E_CAL_BACKEND (backend), NULL);
 		return;
+	}
 
 	source = e_cal_backend_get_source (E_CAL_BACKEND (backend));
 
@@ -759,16 +746,6 @@ e_cal_backend_http_open (ECalBackendSync *backend, EDataCal *cal, gboolean only_
 	priv->uri = NULL;
 	g_free (tmp);
 
-	if (e_source_get_property (source, "auth") != NULL) {
-		if ((username == NULL || password == NULL)) {
-			g_propagate_error (perror, EDC_ERROR (AuthenticationRequired));
-			return;
-		}
-
-		priv->username = g_strdup (username);
-		priv->password = g_strdup (password);
-	}
-
 	if (!priv->store) {
 		const gchar *cache_dir;
 
@@ -781,20 +758,58 @@ e_cal_backend_http_open (ECalBackendSync *backend, EDataCal *cal, gboolean only_
 
 		if (!priv->store) {
 			g_propagate_error (perror, EDC_ERROR_EX (OtherError, _("Could not create cache file")));
+			e_cal_backend_notify_opened (E_CAL_BACKEND (backend), EDC_ERROR_EX (OtherError, _("Could not create cache file")));
 			return;
 		}
+	}
+
+	e_cal_backend_notify_readonly (E_CAL_BACKEND (backend), TRUE);
+	e_cal_backend_notify_online (E_CAL_BACKEND (backend), priv->is_online);
 
-		if (priv->default_zone) {
-			e_cal_backend_store_set_default_timezone (priv->store, priv->default_zone);
+	if (priv->is_online) {
+		if (e_source_get_property (source, "auth")) {
+			e_cal_backend_notify_auth_required (E_CAL_BACKEND (cbhttp), TRUE, priv->credentials);
+		} else if (priv->requires_auth && perror && !*perror) {
+			g_propagate_error (perror, EDC_ERROR (AuthenticationRequired));
+			e_cal_backend_notify_opened (E_CAL_BACKEND (backend), EDC_ERROR (AuthenticationRequired));
+		} else {
+			e_cal_backend_notify_opened (E_CAL_BACKEND (backend), NULL);
+			g_idle_add ((GSourceFunc) begin_retrieval_cb, cbhttp);
 		}
+	} else {
+		e_cal_backend_notify_opened (E_CAL_BACKEND (backend), NULL);
+	}
+}
+
+static void
+e_cal_backend_http_authenticate_user (ECalBackendSync *backend, GCancellable *cancellable, ECredentials *credentials, GError **error)
+{
+	ECalBackendHttp        *cbhttp;
+	ECalBackendHttpPrivate *priv;
+
+	cbhttp = E_CAL_BACKEND_HTTP (backend);
+	priv  = cbhttp->priv;
+
+	if (priv->credentials && credentials && e_credentials_equal_keys (priv->credentials, credentials, E_CREDENTIALS_KEY_USERNAME, E_CREDENTIALS_KEY_PASSWORD, NULL)) {
+		g_propagate_error (error, EDC_ERROR (AuthenticationRequired));
+		return;
 	}
 
-	if (priv->mode != CAL_MODE_LOCAL)
-		g_idle_add ((GSourceFunc) begin_retrieval_cb, cbhttp);
+	e_credentials_free (priv->credentials);
+	priv->credentials = NULL;
+
+	if (!credentials || !e_credentials_has_key (credentials, E_CREDENTIALS_KEY_USERNAME)) {
+		g_propagate_error (error, EDC_ERROR (AuthenticationRequired));
+		return;
+	}
+
+	priv->credentials = e_credentials_new_clone (credentials);
+
+	g_idle_add ((GSourceFunc) begin_retrieval_cb, cbhttp);
 }
 
 static void
-e_cal_backend_http_refresh (ECalBackendSync *backend, EDataCal *cal, GError **perror)
+e_cal_backend_http_refresh (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, GError **perror)
 {
 	ECalBackendHttp *cbhttp;
 	ECalBackendHttpPrivate *priv;
@@ -815,7 +830,7 @@ e_cal_backend_http_refresh (ECalBackendSync *backend, EDataCal *cal, GError **pe
 }
 
 static void
-e_cal_backend_http_remove (ECalBackendSync *backend, EDataCal *cal, GError **perror)
+e_cal_backend_http_remove (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, GError **perror)
 {
 	ECalBackendHttp *cbhttp;
 	ECalBackendHttpPrivate *priv;
@@ -829,106 +844,39 @@ e_cal_backend_http_remove (ECalBackendSync *backend, EDataCal *cal, GError **per
 	e_cal_backend_store_remove (priv->store);
 }
 
-/* is_loaded handler for the file backend */
-static gboolean
-e_cal_backend_http_is_loaded (ECalBackend *backend)
-{
-	ECalBackendHttp *cbhttp;
-	ECalBackendHttpPrivate *priv;
-
-	cbhttp = E_CAL_BACKEND_HTTP (backend);
-	priv = cbhttp->priv;
-
-	if (!priv->store)
-		return FALSE;
-
-	return TRUE;
-}
-
-/* is_remote handler for the http backend */
-static CalMode
-e_cal_backend_http_get_mode (ECalBackend *backend)
-{
-	ECalBackendHttp *cbhttp;
-	ECalBackendHttpPrivate *priv;
-
-	cbhttp = E_CAL_BACKEND_HTTP (backend);
-	priv = cbhttp->priv;
-
-	return priv->mode;
-}
-
 /* Set_mode handler for the http backend */
 static void
-e_cal_backend_http_set_mode (ECalBackend *backend, CalMode mode)
+e_cal_backend_http_set_online (ECalBackend *backend, gboolean is_online)
 {
 	ECalBackendHttp *cbhttp;
 	ECalBackendHttpPrivate *priv;
-	EDataCalMode set_mode;
 	gboolean loaded;
 
 	cbhttp = E_CAL_BACKEND_HTTP (backend);
 	priv = cbhttp->priv;
 
-	loaded = e_cal_backend_http_is_loaded (backend);
+	loaded = e_cal_backend_is_opened (backend);
 
-	if (priv->mode != mode) {
-		switch (mode) {
-			case CAL_MODE_LOCAL:
-				priv->mode = mode;
-				set_mode = cal_mode_to_corba (mode);
-				if (loaded && priv->reload_timeout_id) {
-					g_source_remove (priv->reload_timeout_id);
-					priv->reload_timeout_id = 0;
-				}
-				break;
-			case CAL_MODE_REMOTE:
-			case CAL_MODE_ANY:
-				priv->mode = mode;
-				set_mode = cal_mode_to_corba (mode);
-				if (loaded)
-					g_idle_add ((GSourceFunc) begin_retrieval_cb, backend);
-				break;
-
-				priv->mode = CAL_MODE_REMOTE;
-				set_mode = Remote;
-				break;
-			default:
-				set_mode = AnyMode;
-				break;
+	if ((priv->is_online ? 1 : 0) != (is_online ? 1 : 0)) {
+		priv->is_online = is_online;
+		if (!priv->is_online) {
+			if (loaded && priv->reload_timeout_id) {
+				g_source_remove (priv->reload_timeout_id);
+				priv->reload_timeout_id = 0;
+			}
+		} else {
+			if (loaded)
+				g_idle_add ((GSourceFunc) begin_retrieval_cb, backend);
 		}
-	} else {
-		set_mode = cal_mode_to_corba (priv->mode);
 	}
 
-	if (loaded) {
-
-		if (set_mode == AnyMode)
-			e_cal_backend_notify_mode (backend,
-						   ModeNotSupported,
-						   cal_mode_to_corba (priv->mode));
-		else
-			e_cal_backend_notify_mode (backend,
-						   ModeSet,
-						   set_mode);
-	}
-}
-
-static void
-e_cal_backend_http_get_default_object (ECalBackendSync *backend, EDataCal *cal, gchar **object, GError **perror)
-{
-	icalcomponent *icalcomp;
-	icalcomponent_kind kind;
-
-	kind = e_cal_backend_get_kind (E_CAL_BACKEND (backend));
-	icalcomp = e_cal_util_new_component (kind);
-	*object = icalcomponent_as_ical_string_r (icalcomp);
-	icalcomponent_free (icalcomp);
+	if (loaded)
+		e_cal_backend_notify_online (backend, priv->is_online);
 }
 
 /* Get_object_component handler for the http backend */
 static void
-e_cal_backend_http_get_object (ECalBackendSync *backend, EDataCal *cal, const gchar *uid, const gchar *rid, gchar **object, GError **error)
+e_cal_backend_http_get_object (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *uid, const gchar *rid, gchar **object, GError **error)
 {
 	ECalBackendHttp *cbhttp;
 	ECalBackendHttpPrivate *priv;
@@ -956,7 +904,7 @@ e_cal_backend_http_get_object (ECalBackendSync *backend, EDataCal *cal, const gc
 
 /* Add_timezone handler for the file backend */
 static void
-e_cal_backend_http_add_timezone (ECalBackendSync *backend, EDataCal *cal, const gchar *tzobj, GError **error)
+e_cal_backend_http_add_timezone (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *tzobj, GError **error)
 {
 	ECalBackendHttp *cbhttp;
 	ECalBackendHttpPrivate *priv;
@@ -987,40 +935,9 @@ e_cal_backend_http_add_timezone (ECalBackendSync *backend, EDataCal *cal, const
 	e_cal_backend_store_put_timezone (priv->store, zone);
 }
 
-static void
-e_cal_backend_http_set_default_zone (ECalBackendSync *backend, EDataCal *cal, const gchar *tzobj, GError **error)
-{
-	icalcomponent *tz_comp;
-	ECalBackendHttp *cbhttp;
-	ECalBackendHttpPrivate *priv;
-	icaltimezone *zone;
-
-	cbhttp = (ECalBackendHttp *) backend;
-
-	e_return_data_cal_error_if_fail (E_IS_CAL_BACKEND_HTTP (cbhttp), InvalidArg);
-	e_return_data_cal_error_if_fail (tzobj != NULL, InvalidArg);
-
-	priv = cbhttp->priv;
-
-	tz_comp = icalparser_parse_string (tzobj);
-	if (!tz_comp) {
-		g_propagate_error (error, EDC_ERROR (InvalidObject));
-		return;
-	}
-
-	zone = icaltimezone_new ();
-	icaltimezone_set_component (zone, tz_comp);
-
-	if (priv->default_zone)
-		icaltimezone_free (priv->default_zone, 1);
-
-	/* Set the default timezone to it. */
-	priv->default_zone = zone;
-}
-
 /* Get_objects_in_range handler for the file backend */
 static void
-e_cal_backend_http_get_object_list (ECalBackendSync *backend, EDataCal *cal, const gchar *sexp, GList **objects, GError **perror)
+e_cal_backend_http_get_object_list (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *sexp, GSList **objects, GError **perror)
 {
 	ECalBackendHttp *cbhttp;
 	ECalBackendHttpPrivate *priv;
@@ -1051,7 +968,7 @@ e_cal_backend_http_get_object_list (ECalBackendSync *backend, EDataCal *cal, con
 
 	for (l = components; l != NULL; l = g_slist_next (l)) {
 		if (e_cal_backend_sexp_match_comp (cbsexp, E_CAL_COMPONENT (l->data), E_CAL_BACKEND (backend))) {
-			*objects = g_list_append (*objects, e_cal_component_get_as_string (l->data));
+			*objects = g_slist_append (*objects, e_cal_component_get_as_string (l->data));
 		}
 	}
 
@@ -1060,14 +977,13 @@ e_cal_backend_http_get_object_list (ECalBackendSync *backend, EDataCal *cal, con
 	g_object_unref (cbsexp);
 }
 
-/* get_query handler for the file backend */
 static void
-e_cal_backend_http_start_query (ECalBackend *backend, EDataCalView *query)
+e_cal_backend_http_start_view (ECalBackend *backend, EDataCalView *query)
 {
 	ECalBackendHttp *cbhttp;
 	ECalBackendHttpPrivate *priv;
 	GSList *components, *l;
-	GList *objects = NULL;
+	GSList *objects = NULL;
 	ECalBackendSExp *cbsexp;
 	time_t occur_start = -1, occur_end = -1;
 	gboolean prunning_by_time;
@@ -1079,7 +995,7 @@ e_cal_backend_http_start_query (ECalBackend *backend, EDataCalView *query)
 
 	if (!priv->store) {
 		GError *error = EDC_ERROR (NoSuchCal);
-		e_data_cal_view_notify_done (query, error);
+		e_data_cal_view_notify_complete (query, error);
 		g_error_free (error);
 		return;
 	}
@@ -1098,19 +1014,19 @@ e_cal_backend_http_start_query (ECalBackend *backend, EDataCalView *query)
 
 	for (l = components; l != NULL; l = g_slist_next (l)) {
 		if (e_cal_backend_sexp_match_comp (cbsexp, E_CAL_COMPONENT (l->data), E_CAL_BACKEND (backend))) {
-			objects = g_list_append (objects, e_cal_component_get_as_string (l->data));
+			objects = g_slist_append (objects, e_cal_component_get_as_string (l->data));
 		}
 	}
 
-	e_data_cal_view_notify_objects_added (query, (const GList *) objects);
+	e_data_cal_view_notify_objects_added (query, objects);
 
 	g_slist_foreach (components, (GFunc) g_object_unref, NULL);
 	g_slist_free (components);
-	g_list_foreach (objects, (GFunc) g_free, NULL);
-	g_list_free (objects);
+	g_slist_foreach (objects, (GFunc) g_free, NULL);
+	g_slist_free (objects);
 	g_object_unref (cbsexp);
 
-	e_data_cal_view_notify_done (query, NULL /* Success */);
+	e_data_cal_view_notify_complete (query, NULL /* Success */);
 }
 
 /***** static icaltimezone *
@@ -1236,7 +1152,7 @@ create_user_free_busy (ECalBackendHttp *cbhttp, const gchar *address, const gcha
 						vfb,
 						resolve_tzid,
 						vcalendar_comp,
-						(icaltimezone *) e_cal_backend_store_get_default_timezone (store));
+						icaltimezone_get_utc_timezone ());
 	}
 	g_object_unref (obj_sexp);
 
@@ -1245,8 +1161,8 @@ create_user_free_busy (ECalBackendHttp *cbhttp, const gchar *address, const gcha
 
 /* Get_free_busy handler for the file backend */
 static void
-e_cal_backend_http_get_free_busy (ECalBackendSync *backend, EDataCal *cal, GList *users,
-				time_t start, time_t end, GList **freebusy, GError **error)
+e_cal_backend_http_get_free_busy (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const GSList *users,
+				time_t start, time_t end, GSList **freebusy, GError **error)
 {
 	ECalBackendHttp *cbhttp;
 	ECalBackendHttpPrivate *priv;
@@ -1269,19 +1185,19 @@ e_cal_backend_http_get_free_busy (ECalBackendSync *backend, EDataCal *cal, GList
 		if (e_cal_backend_mail_account_get_default (&address, &name)) {
 			vfb = create_user_free_busy (cbhttp, address, name, start, end);
 			calobj = icalcomponent_as_ical_string_r (vfb);
-                        *freebusy = g_list_append (*freebusy, calobj);
+                        *freebusy = g_slist_append (*freebusy, calobj);
 			icalcomponent_free (vfb);
 			g_free (address);
 			g_free (name);
 		}
 	} else {
-		GList *l;
+		const GSList *l;
 		for (l = users; l != NULL; l = l->next ) {
 			address = l->data;
 			if (e_cal_backend_mail_account_is_valid (address, &name)) {
 				vfb = create_user_free_busy (cbhttp, address, name, start, end);
 				calobj = icalcomponent_as_ical_string_r (vfb);
-                                *freebusy = g_list_append (*freebusy, calobj);
+                                *freebusy = g_slist_append (*freebusy, calobj);
 				icalcomponent_free (vfb);
 				g_free (name);
 			}
@@ -1289,29 +1205,14 @@ e_cal_backend_http_get_free_busy (ECalBackendSync *backend, EDataCal *cal, GList
 	}
 }
 
-/* Get_changes handler for the file backend */
-static void
-e_cal_backend_http_get_changes (ECalBackendSync *backend, EDataCal *cal, const gchar *change_id,
-				GList **adds, GList **modifies, GList **deletes, GError **perror)
-{
-	g_propagate_error (perror, EDC_ERROR (NotSupported));
-}
-
-/* Discard_alarm handler for the file backend */
 static void
-e_cal_backend_http_discard_alarm (ECalBackendSync *backend, EDataCal *cal, const gchar *uid, const gchar *auid, GError **perror)
-{
-	/* FIXME */
-}
-
-static void
-e_cal_backend_http_create_object (ECalBackendSync *backend, EDataCal *cal, gchar **calobj, gchar **uid, GError **perror)
+e_cal_backend_http_create_object (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, gchar **uid, gchar **new_calobj, GError **perror)
 {
 	g_propagate_error (perror, EDC_ERROR (PermissionDenied));
 }
 
 static void
-e_cal_backend_http_modify_object (ECalBackendSync *backend, EDataCal *cal, const gchar *calobj,
+e_cal_backend_http_modify_object (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj,
 				CalObjModType mod, gchar **old_object, gchar **new_object, GError **perror)
 {
 	g_propagate_error (perror, EDC_ERROR (PermissionDenied));
@@ -1319,7 +1220,7 @@ e_cal_backend_http_modify_object (ECalBackendSync *backend, EDataCal *cal, const
 
 /* Remove_object handler for the file backend */
 static void
-e_cal_backend_http_remove_object (ECalBackendSync *backend, EDataCal *cal,
+e_cal_backend_http_remove_object (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable,
 				const gchar *uid, const gchar *rid,
 				CalObjModType mod, gchar **old_object,
 				gchar **object, GError **perror)
@@ -1331,13 +1232,13 @@ e_cal_backend_http_remove_object (ECalBackendSync *backend, EDataCal *cal,
 
 /* Update_objects handler for the file backend. */
 static void
-e_cal_backend_http_receive_objects (ECalBackendSync *backend, EDataCal *cal, const gchar *calobj, GError **perror)
+e_cal_backend_http_receive_objects (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, GError **perror)
 {
 	g_propagate_error (perror, EDC_ERROR (PermissionDenied));
 }
 
 static void
-e_cal_backend_http_send_objects (ECalBackendSync *backend, EDataCal *cal, const gchar *calobj, GList **users,
+e_cal_backend_http_send_objects (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, GSList **users,
 				 gchar **modified_calobj, GError **perror)
 {
 	*users = NULL;
@@ -1347,21 +1248,6 @@ e_cal_backend_http_send_objects (ECalBackendSync *backend, EDataCal *cal, const
 }
 
 static icaltimezone *
-e_cal_backend_http_internal_get_default_timezone (ECalBackend *backend)
-{
-	ECalBackendHttp *cbhttp;
-	ECalBackendHttpPrivate *priv;
-
-	cbhttp = E_CAL_BACKEND_HTTP (backend);
-	priv = cbhttp->priv;
-
-	if (!priv->store)
-		return NULL;
-
-	return NULL;
-}
-
-static icaltimezone *
 e_cal_backend_http_internal_get_timezone (ECalBackend *backend, const gchar *tzid)
 {
 	ECalBackendHttp *cbhttp;
@@ -1419,33 +1305,22 @@ e_cal_backend_http_class_init (ECalBackendHttpClass *class)
 	object_class->dispose = e_cal_backend_http_dispose;
 	object_class->finalize = e_cal_backend_http_finalize;
 
-	sync_class->is_read_only_sync = e_cal_backend_http_is_read_only;
-	sync_class->get_cal_address_sync = e_cal_backend_http_get_cal_address;
-	sync_class->get_alarm_email_address_sync = e_cal_backend_http_get_alarm_email_address;
-	sync_class->get_ldap_attribute_sync = e_cal_backend_http_get_ldap_attribute;
-	sync_class->get_static_capabilities_sync = e_cal_backend_http_get_static_capabilities;
-	sync_class->open_sync = e_cal_backend_http_open;
-	sync_class->refresh_sync = e_cal_backend_http_refresh;
-	sync_class->remove_sync = e_cal_backend_http_remove;
-	sync_class->create_object_sync = e_cal_backend_http_create_object;
-	sync_class->modify_object_sync = e_cal_backend_http_modify_object;
-	sync_class->remove_object_sync = e_cal_backend_http_remove_object;
-	sync_class->discard_alarm_sync = e_cal_backend_http_discard_alarm;
-	sync_class->receive_objects_sync = e_cal_backend_http_receive_objects;
-	sync_class->send_objects_sync = e_cal_backend_http_send_objects;
-	sync_class->get_default_object_sync = e_cal_backend_http_get_default_object;
-	sync_class->get_object_sync = e_cal_backend_http_get_object;
-	sync_class->get_object_list_sync = e_cal_backend_http_get_object_list;
-	sync_class->add_timezone_sync = e_cal_backend_http_add_timezone;
-	sync_class->set_default_zone_sync = e_cal_backend_http_set_default_zone;
-	sync_class->get_freebusy_sync = e_cal_backend_http_get_free_busy;
-	sync_class->get_changes_sync = e_cal_backend_http_get_changes;
-
-	backend_class->is_loaded = e_cal_backend_http_is_loaded;
-	backend_class->start_query = e_cal_backend_http_start_query;
-	backend_class->get_mode = e_cal_backend_http_get_mode;
-	backend_class->set_mode = e_cal_backend_http_set_mode;
-
-	backend_class->internal_get_default_timezone = e_cal_backend_http_internal_get_default_timezone;
-	backend_class->internal_get_timezone = e_cal_backend_http_internal_get_timezone;
+	sync_class->get_backend_property_sync	= e_cal_backend_http_get_backend_property;
+	sync_class->open_sync			= e_cal_backend_http_open;
+	sync_class->authenticate_user_sync	= e_cal_backend_http_authenticate_user;
+	sync_class->refresh_sync		= e_cal_backend_http_refresh;
+	sync_class->remove_sync			= e_cal_backend_http_remove;
+	sync_class->create_object_sync		= e_cal_backend_http_create_object;
+	sync_class->modify_object_sync		= e_cal_backend_http_modify_object;
+	sync_class->remove_object_sync		= e_cal_backend_http_remove_object;
+	sync_class->receive_objects_sync	= e_cal_backend_http_receive_objects;
+	sync_class->send_objects_sync		= e_cal_backend_http_send_objects;
+	sync_class->get_object_sync		= e_cal_backend_http_get_object;
+	sync_class->get_object_list_sync	= e_cal_backend_http_get_object_list;
+	sync_class->add_timezone_sync		= e_cal_backend_http_add_timezone;
+	sync_class->get_free_busy_sync		= e_cal_backend_http_get_free_busy;
+
+	backend_class->start_view		= e_cal_backend_http_start_view;
+	backend_class->set_online		= e_cal_backend_http_set_online;
+	backend_class->internal_get_timezone	= e_cal_backend_http_internal_get_timezone;
 }
diff --git a/calendar/backends/weather/e-cal-backend-weather.c b/calendar/backends/weather/e-cal-backend-weather.c
index 1886a3b..cb2503b 100644
--- a/calendar/backends/weather/e-cal-backend-weather.c
+++ b/calendar/backends/weather/e-cal-backend-weather.c
@@ -42,7 +42,7 @@ G_DEFINE_TYPE (ECalBackendWeather, e_cal_backend_weather, E_TYPE_CAL_BACKEND_SYN
 static gboolean reload_cb (ECalBackendWeather *cbw);
 static gboolean begin_retrieval_cb (ECalBackendWeather *cbw);
 static ECalComponent* create_weather (ECalBackendWeather *cbw, WeatherInfo *report, gboolean is_forecast);
-static void e_cal_backend_weather_add_timezone (ECalBackendSync *backend, EDataCal *cal, const gchar *tzobj, GError **perror);
+static void e_cal_backend_weather_add_timezone (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *tzobj, GError **perror);
 
 /* Private part of the ECalBackendWeather structure */
 struct _ECalBackendWeatherPrivate {
@@ -50,14 +50,11 @@ struct _ECalBackendWeatherPrivate {
 	gchar *uri;
 
 	/* Local/remote mode */
-	CalMode mode;
+	gboolean is_online;
 
 	/* The file cache */
 	ECalBackendStore *store;
 
-	/* The calendar's default timezone, used for resolving DATE and
-	   floating DATE-TIME values. */
-	icaltimezone *default_zone;
 	GHashTable *zones;
 
 	/* Reload */
@@ -165,7 +162,7 @@ put_component_to_store (ECalBackendWeather *cb,
 	priv = cb->priv;
 
 	e_cal_util_get_component_occur_times (comp, &time_start, &time_end,
-				   resolve_tzid, cb, priv->default_zone,
+				   resolve_tzid, cb, icaltimezone_get_utc_timezone (),
 				   e_cal_backend_get_kind (E_CAL_BACKEND (cb)));
 
 	e_cal_backend_store_put_component_with_time_range (priv->store, comp, time_start, time_end);
@@ -253,7 +250,7 @@ begin_retrieval_cb (ECalBackendWeather *cbw)
 	ECalBackendWeatherPrivate *priv = cbw->priv;
 	GSource *source;
 
-	if (priv->mode != CAL_MODE_REMOTE)
+	if (!priv->is_online)
 		return TRUE;
 
 	maybe_start_reload_timeout (cbw);
@@ -369,7 +366,7 @@ create_weather (ECalBackendWeather *cbw, WeatherInfo *report, gboolean is_foreca
 		update_zone = icaltimezone_get_builtin_timezone (location->tz_hint);
 
 	if (!update_zone)
-		update_zone = priv->default_zone;
+		update_zone = icaltimezone_get_utc_timezone ();
 
 	/* Set all-day event's date from forecast data - cannot set is_date,
 	   because in that case no timezone conversion is done */
@@ -455,47 +452,38 @@ create_weather (ECalBackendWeather *cbw, WeatherInfo *report, gboolean is_foreca
 	return cal_comp;
 }
 
-static void
-e_cal_backend_weather_is_read_only (ECalBackendSync *backend, EDataCal *cal, gboolean *read_only, GError **perror)
-{
-	*read_only = TRUE;
-}
-
-static void
-e_cal_backend_weather_get_cal_address (ECalBackendSync *backend, EDataCal *cal, gchar **address, GError **perror)
-{
-	/* Weather has no particular email addresses associated with it */
-	*address = NULL;
-}
-
-static void
-e_cal_backend_weather_get_alarm_email_address (ECalBackendSync *backend, EDataCal *cal, gchar **address, GError **perror)
-{
-	/* Weather has no particular email addresses associated with it */
-	*address = NULL;
-}
-
-static void
-e_cal_backend_weather_get_ldap_attribute (ECalBackendSync *backend, EDataCal *cal, gchar **attribute, GError **perror)
-{
-	*attribute = NULL;
-}
+static gboolean
+e_cal_backend_weather_get_backend_property (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *prop_name, gchar **prop_value, GError **perror)
+{
+	gboolean processed = TRUE;
+
+	g_return_val_if_fail (prop_name != NULL, FALSE);
+	g_return_val_if_fail (prop_value != NULL, FALSE);
+
+	if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
+		*prop_value = g_strdup (CAL_STATIC_CAPABILITY_NO_ALARM_REPEAT ","
+					CAL_STATIC_CAPABILITY_NO_AUDIO_ALARMS ","
+					CAL_STATIC_CAPABILITY_NO_DISPLAY_ALARMS ","
+					CAL_STATIC_CAPABILITY_NO_PROCEDURE_ALARMS ","
+					CAL_STATIC_CAPABILITY_NO_TASK_ASSIGNMENT ","
+					CAL_STATIC_CAPABILITY_NO_THISANDFUTURE ","
+					CAL_STATIC_CAPABILITY_NO_THISANDPRIOR ","
+					CAL_STATIC_CAPABILITY_REFRESH_SUPPORTED);
+	} else if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS) ||
+		   g_str_equal (prop_name, CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS)) {
+		/* Weather has no particular email addresses associated with it */
+		*prop_value = NULL;
+	} else if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_DEFAULT_OBJECT)) {
+		g_propagate_error (perror, EDC_ERROR (UnsupportedMethod));
+	} else {
+		processed = FALSE;
+	}
 
-static void
-e_cal_backend_weather_get_static_capabilities (ECalBackendSync *backend, EDataCal *cal, gchar **capabilities, GError **perror)
-{
-	*capabilities = g_strdup (CAL_STATIC_CAPABILITY_NO_ALARM_REPEAT ","
-				  CAL_STATIC_CAPABILITY_NO_AUDIO_ALARMS  ","
-				  CAL_STATIC_CAPABILITY_NO_DISPLAY_ALARMS  ","
-				  CAL_STATIC_CAPABILITY_NO_PROCEDURE_ALARMS  ","
-				  CAL_STATIC_CAPABILITY_NO_TASK_ASSIGNMENT  ","
-				  CAL_STATIC_CAPABILITY_NO_THISANDFUTURE  ","
-				  CAL_STATIC_CAPABILITY_NO_THISANDPRIOR ","
-				  CAL_STATIC_CAPABILITY_REFRESH_SUPPORTED);
+	return processed;
 }
 
 static void
-e_cal_backend_weather_open (ECalBackendSync *backend, EDataCal *cal, gboolean only_if_exists, const gchar *username, const gchar *password, GError **perror)
+e_cal_backend_weather_open (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, gboolean only_if_exists, GError **perror)
 {
 	ECalBackendWeather *cbw;
 	ECalBackendWeatherPrivate *priv;
@@ -512,6 +500,9 @@ e_cal_backend_weather_open (ECalBackendSync *backend, EDataCal *cal, gboolean on
 		g_free (priv->city);
 	priv->city = g_strdup (strrchr (uri, '/') + 1);
 
+	e_cal_backend_notify_readonly (E_CAL_BACKEND (backend), TRUE);
+	e_cal_backend_notify_online (E_CAL_BACKEND (backend), priv->is_online);
+
 	if (!priv->store) {
 		e_cal_backend_cache_remove (cache_dir, "cache.xml");
 		priv->store = e_cal_backend_file_store_new (cache_dir);
@@ -520,28 +511,23 @@ e_cal_backend_weather_open (ECalBackendSync *backend, EDataCal *cal, gboolean on
 			g_propagate_error (perror, EDC_ERROR_EX (OtherError, _("Could not create cache file")));
 			return;
 		}
-	/* do we require to load this new store*/	
-		e_cal_backend_store_load (priv->store);
-
-		if (priv->default_zone) {
-			icalcomponent *icalcomp = icaltimezone_get_component (priv->default_zone);
-			icaltimezone *zone = icaltimezone_new ();
-
-			icaltimezone_set_component (zone, icalcomponent_new_clone (icalcomp));
 
-			g_hash_table_insert (priv->zones, g_strdup (icaltimezone_get_tzid (zone)), zone);
-		}
+		/* do we require to load this new store */
+		e_cal_backend_store_load (priv->store);
+		e_cal_backend_notify_opened (E_CAL_BACKEND (backend), NULL);
 
-		if (priv->mode == CAL_MODE_LOCAL)
+		if (!priv->is_online)
 			return;
 
 		if (!priv->begin_retrival_id)
 			priv->begin_retrival_id = g_idle_add ((GSourceFunc) begin_retrieval_cb, cbw);
 	}
+
+	e_cal_backend_notify_opened (E_CAL_BACKEND (backend), NULL);
 }
 
 static void
-e_cal_backend_weather_refresh (ECalBackendSync *backend, EDataCal *cal, GError **perror)
+e_cal_backend_weather_refresh (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, GError **perror)
 {
 	ECalBackendWeather *cbw;
 	ECalBackendWeatherPrivate *priv;
@@ -562,7 +548,7 @@ e_cal_backend_weather_refresh (ECalBackendSync *backend, EDataCal *cal, GError *
 }
 
 static void
-e_cal_backend_weather_remove (ECalBackendSync *backend, EDataCal *cal, GError **perror)
+e_cal_backend_weather_remove (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, GError **perror)
 {
 	ECalBackendWeather *cbw;
 	ECalBackendWeatherPrivate *priv;
@@ -580,24 +566,13 @@ e_cal_backend_weather_remove (ECalBackendSync *backend, EDataCal *cal, GError **
 }
 
 static void
-e_cal_backend_weather_discard_alarm (ECalBackendSync *backend, EDataCal *cal, const gchar *uid, const gchar *auid, GError **perror)
-{
-}
-
-static void
-e_cal_backend_weather_receive_objects (ECalBackendSync *backend, EDataCal *cal, const gchar *calobj, GError **perror)
+e_cal_backend_weather_receive_objects (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, GError **perror)
 {
 	g_propagate_error (perror, EDC_ERROR (PermissionDenied));
 }
 
 static void
-e_cal_backend_weather_get_default_object (ECalBackendSync *backend, EDataCal *cal, gchar **object, GError **perror)
-{
-	g_propagate_error (perror, EDC_ERROR (UnsupportedMethod));
-}
-
-static void
-e_cal_backend_weather_get_object (ECalBackendSync *backend, EDataCal *cal, const gchar *uid, const gchar *rid, gchar **object, GError **error)
+e_cal_backend_weather_get_object (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *uid, const gchar *rid, gchar **object, GError **error)
 {
 	ECalBackendWeather *cbw = E_CAL_BACKEND_WEATHER (backend);
 	ECalBackendWeatherPrivate *priv = cbw->priv;
@@ -617,7 +592,7 @@ e_cal_backend_weather_get_object (ECalBackendSync *backend, EDataCal *cal, const
 }
 
 static void
-e_cal_backend_weather_get_object_list (ECalBackendSync *backend, EDataCal *cal, const gchar *sexp_string, GList **objects, GError **perror)
+e_cal_backend_weather_get_object_list (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *sexp_string, GSList **objects, GError **perror)
 {
 	ECalBackendWeather *cbw = E_CAL_BACKEND_WEATHER (backend);
 	ECalBackendWeatherPrivate *priv = cbw->priv;
@@ -643,7 +618,7 @@ e_cal_backend_weather_get_object_list (ECalBackendSync *backend, EDataCal *cal,
 
 	for (l = components; l != NULL; l = g_slist_next (l)) {
 		if (e_cal_backend_sexp_match_comp (sexp, E_CAL_COMPONENT (l->data), E_CAL_BACKEND (backend)))
-			*objects = g_list_append (*objects, e_cal_component_get_as_string (l->data));
+			*objects = g_slist_append (*objects, e_cal_component_get_as_string (l->data));
 	}
 
 	g_slist_foreach (components, (GFunc) g_object_unref, NULL);
@@ -652,7 +627,7 @@ e_cal_backend_weather_get_object_list (ECalBackendSync *backend, EDataCal *cal,
 }
 
 static void
-e_cal_backend_weather_add_timezone (ECalBackendSync *backend, EDataCal *cal, const gchar *tzobj, GError **error)
+e_cal_backend_weather_add_timezone (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *tzobj, GError **error)
 {
 	ECalBackendWeather *cbw;
 	ECalBackendWeatherPrivate *priv;
@@ -687,38 +662,7 @@ e_cal_backend_weather_add_timezone (ECalBackendSync *backend, EDataCal *cal, con
 }
 
 static void
-e_cal_backend_weather_set_default_zone (ECalBackendSync *backend, EDataCal *cal, const gchar *tzobj, GError **error)
-{
-	icalcomponent *tz_comp;
-	ECalBackendWeather *cbw;
-	ECalBackendWeatherPrivate *priv;
-	icaltimezone *zone;
-
-	cbw = (ECalBackendWeather *) backend;
-
-	e_return_data_cal_error_if_fail (E_IS_CAL_BACKEND_WEATHER (cbw), InvalidArg);
-	e_return_data_cal_error_if_fail (tzobj != NULL, InvalidArg);
-
-	priv = cbw->priv;
-
-	tz_comp = icalparser_parse_string (tzobj);
-	if (!tz_comp) {
-		g_propagate_error (error, EDC_ERROR (InvalidObject));
-		return;
-	}
-
-	zone = icaltimezone_new ();
-	icaltimezone_set_component (zone, tz_comp);
-
-	if (priv->default_zone)
-		icaltimezone_free (priv->default_zone, 1);
-
-	/* Set the default timezone to it. */
-	priv->default_zone = zone;
-}
-
-static void
-e_cal_backend_weather_get_free_busy (ECalBackendSync *backend, EDataCal *cal, GList *users, time_t start, time_t end, GList **freebusy, GError **perror)
+e_cal_backend_weather_get_free_busy (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const GSList *users, time_t start, time_t end, GSList **freebusy, GError **perror)
 {
 	/* Weather doesn't count as busy time */
 	icalcomponent *vfb = icalcomponent_new_vfreebusy ();
@@ -729,37 +673,18 @@ e_cal_backend_weather_get_free_busy (ECalBackendSync *backend, EDataCal *cal, GL
 	icalcomponent_set_dtend (vfb, icaltime_from_timet_with_zone (end, FALSE, utc_zone));
 
 	calobj = icalcomponent_as_ical_string_r (vfb);
-	*freebusy = g_list_append (NULL, calobj);
+	*freebusy = g_slist_append (NULL, calobj);
 	icalcomponent_free (vfb);
 }
 
 static void
-e_cal_backend_weather_get_changes (ECalBackendSync *backend, EDataCal *cal, const gchar *change_id, GList **adds, GList **modifies, GList **deletes, GError **perror)
-{
-}
-
-static gboolean
-e_cal_backend_weather_is_loaded (ECalBackend *backend)
-{
-	ECalBackendWeather *cbw;
-	ECalBackendWeatherPrivate *priv;
-
-	cbw = E_CAL_BACKEND_WEATHER (backend);
-	priv = cbw->priv;
-
-	if (!priv->store)
-		return FALSE;
-
-	return TRUE;
-}
-
-static void e_cal_backend_weather_start_query (ECalBackend *backend, EDataCalView *query)
+e_cal_backend_weather_start_view (ECalBackend *backend, EDataCalView *query)
 {
 	ECalBackendWeather *cbw;
 	ECalBackendWeatherPrivate *priv;
 	ECalBackendSExp *sexp;
 	GSList *components, *l;
-	GList *objects;
+	GSList *objects;
 	GError *error;
 	time_t occur_start = -1, occur_end = -1;
 	gboolean prunning_by_time;
@@ -769,7 +694,7 @@ static void e_cal_backend_weather_start_query (ECalBackend *backend, EDataCalVie
 
 	if (!priv->store) {
 		error = EDC_ERROR (NoSuchCal);
-		e_data_cal_view_notify_done (query, error);
+		e_data_cal_view_notify_complete (query, error);
 		g_error_free (error);
 		return;
 	}
@@ -777,7 +702,7 @@ static void e_cal_backend_weather_start_query (ECalBackend *backend, EDataCalVie
 	sexp = e_data_cal_view_get_object_sexp (query);
 	if (!sexp) {
 		error = EDC_ERROR (InvalidQuery);
-		e_data_cal_view_notify_done (query, error);
+		e_data_cal_view_notify_complete (query, error);
 		g_error_free (error);
 		return;
 	}
@@ -790,92 +715,48 @@ static void e_cal_backend_weather_start_query (ECalBackend *backend, EDataCalVie
 
 	for (l = components; l != NULL; l = g_slist_next (l)) {
 		if (e_cal_backend_sexp_match_comp (sexp, E_CAL_COMPONENT (l->data), backend))
-			objects = g_list_append (objects, e_cal_component_get_as_string (l->data));
+			objects = g_slist_append (objects, e_cal_component_get_as_string (l->data));
 	}
 
 	if (objects)
-		e_data_cal_view_notify_objects_added (query, (const GList *) objects);
+		e_data_cal_view_notify_objects_added (query, objects);
 
 	g_slist_foreach (components, (GFunc) g_object_unref, NULL);
 	g_slist_free (components);
-	g_list_foreach (objects, (GFunc) g_free, NULL);
-	g_list_free (objects);
+	g_slist_foreach (objects, (GFunc) g_free, NULL);
+	g_slist_free (objects);
 	g_object_unref (sexp);
 
-	e_data_cal_view_notify_done (query, NULL /* Success */);
-}
-
-static CalMode
-e_cal_backend_weather_get_mode (ECalBackend *backend)
-{
-	ECalBackendWeather *cbw;
-	ECalBackendWeatherPrivate *priv;
-
-	cbw = E_CAL_BACKEND_WEATHER (backend);
-	priv = cbw->priv;
-
-	return priv->mode;
+	e_data_cal_view_notify_complete (query, NULL /* Success */);
 }
 
 static void
-e_cal_backend_weather_set_mode (ECalBackend *backend, CalMode mode)
+e_cal_backend_weather_set_online (ECalBackend *backend, gboolean is_online)
 {
 	ECalBackendWeather *cbw;
 	ECalBackendWeatherPrivate *priv;
-	EDataCalMode set_mode;
 	gboolean loaded;
 
 	cbw = E_CAL_BACKEND_WEATHER (backend);
 	priv = cbw->priv;
 
-	loaded = e_cal_backend_weather_is_loaded (backend);
-
-	if (priv->mode != mode) {
-		switch (mode) {
-			case CAL_MODE_LOCAL:
-			case CAL_MODE_REMOTE:
-				priv->mode = mode;
-				set_mode = cal_mode_to_corba (mode);
-				if (loaded && priv->reload_timeout_id) {
-					g_source_remove (priv->reload_timeout_id);
-					priv->reload_timeout_id = 0;
-				}
-				break;
-			case CAL_MODE_ANY:
-				priv->mode = mode;
-				set_mode = cal_mode_to_corba (mode);
-				if (loaded && !priv->begin_retrival_id)
-					priv->begin_retrival_id = g_idle_add ((GSourceFunc) begin_retrieval_cb, backend);
-				break;
-			default:
-				set_mode = AnyMode;
-				break;
+	loaded = e_cal_backend_is_opened (backend);
+
+	if ((priv->is_online ? 1: 0) != (is_online ? 1 : 0)) {
+		priv->is_online = is_online;
+		if (loaded && priv->reload_timeout_id) {
+			g_source_remove (priv->reload_timeout_id);
+			priv->reload_timeout_id = 0;
 		}
-	} else {
-		set_mode = cal_mode_to_corba (priv->mode);
 	}
 
 	if (loaded) {
-		if (set_mode == AnyMode)
-			e_cal_backend_notify_mode (backend,
-						   ModeNotSupported,
-						   cal_mode_to_corba (priv->mode));
-		else
-			e_cal_backend_notify_mode (backend,
-						   ModeSet,
-						   set_mode);
+		e_cal_backend_notify_online (backend, priv->is_online);
+		e_cal_backend_notify_readonly (backend, TRUE);
 	}
 }
 
 static icaltimezone *
-e_cal_backend_weather_internal_get_default_timezone (ECalBackend *backend)
-{
-	ECalBackendWeather *cbw = E_CAL_BACKEND_WEATHER (backend);
-
-	return cbw->priv->default_zone;
-}
-
-static icaltimezone *
 e_cal_backend_weather_internal_get_timezone (ECalBackend *backend, const gchar *tzid)
 {
 	icaltimezone *zone;
@@ -940,11 +821,6 @@ e_cal_backend_weather_finalize (GObject *object)
 		priv->city = NULL;
 	}
 
-	if (priv->default_zone) {
-		icaltimezone_free (priv->default_zone, 1);
-		priv->default_zone = NULL;
-	}
-
 	g_free (priv);
 	cbw->priv = NULL;
 
@@ -991,28 +867,17 @@ e_cal_backend_weather_class_init (ECalBackendWeatherClass *class)
 
 	object_class->finalize = e_cal_backend_weather_finalize;
 
-	sync_class->is_read_only_sync = e_cal_backend_weather_is_read_only;
-	sync_class->get_cal_address_sync = e_cal_backend_weather_get_cal_address;
-	sync_class->get_alarm_email_address_sync = e_cal_backend_weather_get_alarm_email_address;
-	sync_class->get_ldap_attribute_sync = e_cal_backend_weather_get_ldap_attribute;
-	sync_class->get_static_capabilities_sync = e_cal_backend_weather_get_static_capabilities;
-	sync_class->open_sync = e_cal_backend_weather_open;
-	sync_class->refresh_sync = e_cal_backend_weather_refresh;
-	sync_class->remove_sync = e_cal_backend_weather_remove;
-	sync_class->discard_alarm_sync = e_cal_backend_weather_discard_alarm;
-	sync_class->receive_objects_sync = e_cal_backend_weather_receive_objects;
-	sync_class->get_default_object_sync = e_cal_backend_weather_get_default_object;
-	sync_class->get_object_sync = e_cal_backend_weather_get_object;
-	sync_class->get_object_list_sync = e_cal_backend_weather_get_object_list;
-	sync_class->add_timezone_sync = e_cal_backend_weather_add_timezone;
-	sync_class->set_default_zone_sync = e_cal_backend_weather_set_default_zone;
-	sync_class->get_freebusy_sync = e_cal_backend_weather_get_free_busy;
-	sync_class->get_changes_sync = e_cal_backend_weather_get_changes;
-	backend_class->is_loaded = e_cal_backend_weather_is_loaded;
-	backend_class->start_query = e_cal_backend_weather_start_query;
-	backend_class->get_mode = e_cal_backend_weather_get_mode;
-	backend_class->set_mode = e_cal_backend_weather_set_mode;
-
-	backend_class->internal_get_default_timezone = e_cal_backend_weather_internal_get_default_timezone;
-	backend_class->internal_get_timezone = e_cal_backend_weather_internal_get_timezone;
+	sync_class->get_backend_property_sync	= e_cal_backend_weather_get_backend_property;
+	sync_class->open_sync			= e_cal_backend_weather_open;
+	sync_class->refresh_sync		= e_cal_backend_weather_refresh;
+	sync_class->remove_sync			= e_cal_backend_weather_remove;
+	sync_class->receive_objects_sync	= e_cal_backend_weather_receive_objects;
+	sync_class->get_object_sync		= e_cal_backend_weather_get_object;
+	sync_class->get_object_list_sync	= e_cal_backend_weather_get_object_list;
+	sync_class->add_timezone_sync		= e_cal_backend_weather_add_timezone;
+	sync_class->get_free_busy_sync		= e_cal_backend_weather_get_free_busy;
+
+	backend_class->start_view		= e_cal_backend_weather_start_view;
+	backend_class->set_online		= e_cal_backend_weather_set_online;
+	backend_class->internal_get_timezone	= e_cal_backend_weather_internal_get_timezone;
 }
diff --git a/calendar/libecal/Makefile.am b/calendar/libecal/Makefile.am
index cea385b..1ae10ad 100644
--- a/calendar/libecal/Makefile.am
+++ b/calendar/libecal/Makefile.am
@@ -15,7 +15,7 @@ libecal_INCLUDES = \
 
 libecal_1_2_la_CPPFLAGS =			\
 	$(AM_CPPFLAGS)				\
-	$(libecal_INCLUDES)				\
+	$(libecal_INCLUDES)			\
 	-DG_LOG_DOMAIN=\"libecal\"		\
 	$(LIBICAL_CFLAGS)			\
 	$(EVOLUTION_CALENDAR_CFLAGS)
@@ -23,6 +23,9 @@ libecal_1_2_la_CPPFLAGS =			\
 libecal_1_2_la_SOURCES =			\
 	$(MARSHAL_GENERATED)			\
 	e-cal.c					\
+	e-cal-client.c				\
+	e-cal-client-view.c			\
+	e-cal-client-view-private.h		\
 	e-cal-component.c			\
 	e-cal-recur.c				\
 	e-cal-time-util.c			\
@@ -46,6 +49,8 @@ libecalincludedir = $(privincludedir)/libecal
 
 libecalinclude_HEADERS =	\
 	e-cal.h			\
+	e-cal-client.h		\
+	e-cal-client-view.h	\
 	e-cal-component.h	\
 	e-cal-recur.h		\
 	e-cal-time-util.h	\
diff --git a/calendar/libecal/e-cal-client-view-private.h b/calendar/libecal/e-cal-client-view-private.h
new file mode 100644
index 0000000..8a99f54
--- /dev/null
+++ b/calendar/libecal/e-cal-client-view-private.h
@@ -0,0 +1,35 @@
+/* Evolution calendar - Live view client object
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ * Author: Federico Mena-Quintero <federico 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef E_CAL_CLIENT_VIEW_PRIVATE_H
+#define E_CAL_CLIENT_VIEW_PRIVATE_H
+
+#include "libecal/e-cal-client-view.h"
+
+G_BEGIN_DECLS
+
+struct _EGdbusCalView;
+struct _ECalClient;
+
+ECalClientView *_e_cal_client_view_new (struct _ECalClient *client,  struct _EGdbusCalView *gdbus_calview);
+
+G_END_DECLS
+
+#endif
diff --git a/calendar/libecal/e-cal-client-view.c b/calendar/libecal/e-cal-client-view.c
new file mode 100644
index 0000000..079e72a
--- /dev/null
+++ b/calendar/libecal/e-cal-client-view.c
@@ -0,0 +1,527 @@
+/*-*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* Evolution calendar - Live view client object
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ * Copyright (C) 2009 Intel Corporation
+ *
+ * Authors: Federico Mena-Quintero <federico ximian com>
+ *          Ross Burton <ross linux intel 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib/gi18n-lib.h>
+
+#include <string.h>
+#include "e-cal-client.h"
+#include "e-cal-client-view.h"
+#include "e-cal-client-view-private.h"
+
+#include "libedataserver/e-gdbus-marshallers.h"
+
+#include "e-gdbus-cal-view.h"
+
+G_DEFINE_TYPE (ECalClientView, e_cal_client_view, G_TYPE_OBJECT);
+
+/* Private part of the ECalClientView structure */
+struct _ECalClientViewPrivate {
+	GDBusProxy *gdbus_calview;
+	ECalClient *client;
+	gboolean running;
+};
+
+/* Property IDs */
+enum props {
+	PROP_0,
+	PROP_VIEW,
+	PROP_CLIENT
+};
+
+/* Signal IDs */
+enum {
+	OBJECTS_ADDED,
+	OBJECTS_MODIFIED,
+	OBJECTS_REMOVED,
+	PROGRESS,
+	COMPLETE,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+static GSList *
+build_object_list (const gchar * const *seq)
+{
+	GSList *list;
+	gint i;
+
+	list = NULL;
+	for (i = 0; seq[i]; i++) {
+		icalcomponent *comp;
+
+		comp = icalcomponent_new_from_string ((gchar *)seq[i]);
+		if (!comp)
+			continue;
+
+		list = g_slist_prepend (list, comp);
+	}
+
+	return g_slist_reverse (list);
+}
+
+static GSList *
+build_id_list (const gchar * const *seq)
+{
+	GSList *list;
+	gint i;
+
+	list = NULL;
+	for (i = 0; seq[i]; i++) {
+		ECalComponentId *id;
+		id = g_new (ECalComponentId, 1);
+		id->uid = g_strdup (seq[i]);
+		id->rid = NULL; /* TODO */
+		list = g_slist_prepend (list, id);
+	}
+
+	return g_slist_reverse (list);
+}
+
+static void
+objects_added_cb (EGdbusCalView *gdbus_calview, const gchar * const *objects, ECalClientView *view)
+{
+	GSList *list;
+
+	g_return_if_fail (E_IS_CAL_CLIENT_VIEW (view));
+
+	if (!view->priv->running)
+		return;
+
+	g_object_ref (view);
+
+	list = build_object_list (objects);
+
+	g_signal_emit (G_OBJECT (view), signals[OBJECTS_ADDED], 0, list);
+
+	g_slist_foreach (list, (GFunc) icalcomponent_free, NULL);
+	g_slist_free (list);
+
+	g_object_unref (view);
+}
+
+static void
+objects_modified_cb (EGdbusCalView *gdbus_calview, const gchar * const *objects, ECalClientView *view)
+{
+	GSList *list;
+
+	g_return_if_fail (E_IS_CAL_CLIENT_VIEW (view));
+
+	if (!view->priv->running)
+		return;
+
+	g_object_ref (view);
+
+	list = build_object_list (objects);
+
+	g_signal_emit (G_OBJECT (view), signals[OBJECTS_MODIFIED], 0, list);
+
+	g_slist_foreach (list, (GFunc) icalcomponent_free, NULL);
+	g_slist_free (list);
+
+	g_object_unref (view);
+}
+
+static void
+objects_removed_cb (EGdbusCalView *gdbus_calview, const gchar * const *uids, ECalClientView *view)
+{
+	GSList *list;
+
+	g_return_if_fail (E_IS_CAL_CLIENT_VIEW (view));
+
+	if (!view->priv->running)
+		return;
+
+	g_object_ref (view);
+
+	list = build_id_list (uids);
+
+	g_signal_emit (G_OBJECT (view), signals[OBJECTS_REMOVED], 0, list);
+
+	g_slist_foreach (list, (GFunc) e_cal_component_free_id, NULL);
+	g_slist_free (list);
+
+	g_object_unref (view);
+}
+
+static void
+progress_cb (EGdbusCalView *gdbus_calview, guint percent, const gchar *message, ECalClientView *view)
+{
+	g_return_if_fail (E_IS_CAL_CLIENT_VIEW (view));
+
+	if (!view->priv->running)
+		return;
+
+	g_signal_emit (G_OBJECT (view), signals[PROGRESS], 0, percent, message);
+}
+
+static void
+complete_cb (EGdbusCalView *gdbus_calview, const gchar * const *arg_error, ECalClientView *view)
+{
+	GError *error = NULL;
+
+	g_return_if_fail (E_IS_CAL_CLIENT_VIEW (view));
+
+	if (!view->priv->running)
+		return;
+
+	g_return_if_fail (e_gdbus_templates_decode_error (arg_error, &error));
+
+	g_signal_emit (G_OBJECT (view), signals[COMPLETE], 0, error);
+
+	if (error)
+		g_error_free (error);
+}
+
+/* Object initialization function for the calendar view */
+static void
+e_cal_client_view_init (ECalClientView *view)
+{
+	view->priv = G_TYPE_INSTANCE_GET_PRIVATE (view, E_TYPE_CAL_CLIENT_VIEW, ECalClientViewPrivate);
+	view->priv->running = FALSE;
+}
+
+static void
+cal_client_view_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
+{
+	ECalClientView *view;
+	ECalClientViewPrivate *priv;
+
+	view = E_CAL_CLIENT_VIEW (object);
+	priv = view->priv;
+
+	switch (property_id) {
+	case PROP_VIEW:
+		/* gdbus_calview can be set only once */
+		g_return_if_fail (priv->gdbus_calview == NULL);
+
+		priv->gdbus_calview = g_object_ref (g_value_get_pointer (value));
+		g_signal_connect (priv->gdbus_calview, "objects-added", G_CALLBACK (objects_added_cb), view);
+		g_signal_connect (priv->gdbus_calview, "objects-modified", G_CALLBACK (objects_modified_cb), view);
+		g_signal_connect (priv->gdbus_calview, "objects-removed", G_CALLBACK (objects_removed_cb), view);
+		g_signal_connect (priv->gdbus_calview, "progress", G_CALLBACK (progress_cb), view);
+		g_signal_connect (priv->gdbus_calview, "complete", G_CALLBACK (complete_cb), view);
+		break;
+	case PROP_CLIENT:
+		priv->client = E_CAL_CLIENT (g_value_dup_object (value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+		break;
+	}
+}
+
+static void
+cal_client_view_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
+{
+	ECalClientView *view;
+	ECalClientViewPrivate *priv;
+
+	view = E_CAL_CLIENT_VIEW (object);
+	priv = view->priv;
+
+	switch (property_id) {
+	case PROP_VIEW:
+		g_value_set_pointer (value, priv->gdbus_calview);
+		break;
+	case PROP_CLIENT:
+		g_value_set_object (value, priv->client);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+		break;
+	}
+}
+
+/* Finalize handler for the calendar view */
+static void
+cal_client_view_finalize (GObject *object)
+{
+	ECalClientView *view;
+	ECalClientViewPrivate *priv;
+
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (E_IS_CAL_CLIENT_VIEW (object));
+
+	view = E_CAL_CLIENT_VIEW (object);
+	priv = view->priv;
+
+	if (priv->gdbus_calview != NULL) {
+		GError *error = NULL;
+
+		g_signal_handlers_disconnect_matched (priv->gdbus_calview, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, view);
+		e_gdbus_cal_view_call_dispose_sync (priv->gdbus_calview, NULL, &error);
+		g_object_unref (priv->gdbus_calview);
+		priv->gdbus_calview = NULL;
+
+		if (error) {
+			g_warning ("Failed to dispose cal view: %s", error->message);
+			g_error_free (error);
+		}
+	}
+
+	if (priv->client) {
+		g_object_unref (priv->client);
+		priv->client = NULL;
+	}
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (e_cal_client_view_parent_class)->finalize (object);
+}
+
+/* Class initialization function for the calendar view */
+static void
+e_cal_client_view_class_init (ECalClientViewClass *klass)
+{
+	GObjectClass *object_class;
+
+	object_class = (GObjectClass *) klass;
+
+	object_class->set_property = cal_client_view_set_property;
+	object_class->get_property = cal_client_view_get_property;
+	object_class->finalize = cal_client_view_finalize;
+
+	g_type_class_add_private (klass, sizeof (ECalClientViewPrivate));
+
+	g_object_class_install_property (object_class, PROP_VIEW,
+		g_param_spec_pointer ("view", "The GDBus view proxy", NULL,
+				      G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+
+	g_object_class_install_property (object_class, PROP_CLIENT,
+		g_param_spec_object ("client", "The e-cal-client for the view", NULL, E_TYPE_CAL_CLIENT,
+				      G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
+        /**
+         * ECalClientView::objects-added:
+         * @view:: self
+         * @objects: (type GSList) (transfer none) (element-type long):
+         */
+	signals[OBJECTS_ADDED] =
+		g_signal_new ("objects-added",
+			      G_TYPE_FROM_CLASS (klass),
+			      G_SIGNAL_RUN_FIRST,
+			      G_STRUCT_OFFSET (ECalClientViewClass, objects_added),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__POINTER,
+			      G_TYPE_NONE, 1, G_TYPE_POINTER);
+        /**
+         * ECalClientView::objects-modified:
+         * @view:: self
+         * @objects: (type GSList) (transfer none) (element-type long):
+         */
+	signals[OBJECTS_MODIFIED] =
+		g_signal_new ("objects-modified",
+			      G_TYPE_FROM_CLASS (klass),
+			      G_SIGNAL_RUN_FIRST,
+			      G_STRUCT_OFFSET (ECalClientViewClass, objects_modified),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__POINTER,
+			      G_TYPE_NONE, 1, G_TYPE_POINTER);
+        /**
+         * ECalClientView::objects-removed:
+         * @view:: self
+         * @objects: (type GSList) (transfer none) (element-type ECalComponentId):
+         */
+	signals[OBJECTS_REMOVED] =
+		g_signal_new ("objects-removed",
+			      G_TYPE_FROM_CLASS (klass),
+			      G_SIGNAL_RUN_FIRST,
+			      G_STRUCT_OFFSET (ECalClientViewClass, objects_removed),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__POINTER,
+			      G_TYPE_NONE, 1, G_TYPE_POINTER);
+
+	signals[PROGRESS] =
+		g_signal_new ("progress",
+			      G_TYPE_FROM_CLASS (klass),
+			      G_SIGNAL_RUN_FIRST,
+			      G_STRUCT_OFFSET (ECalClientViewClass, progress),
+			      NULL, NULL,
+			      e_gdbus_marshallers_VOID__UINT_STRING,
+			      G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_STRING);
+
+	signals[COMPLETE] =
+		g_signal_new ("complete",
+			      G_TYPE_FROM_CLASS (klass),
+			      G_SIGNAL_RUN_FIRST,
+			      G_STRUCT_OFFSET (ECalClientViewClass, complete),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__BOXED,
+			      G_TYPE_NONE, 1, G_TYPE_ERROR);
+}
+
+/**
+ * _e_cal_client_view_new:
+ * @client: An #ECalClient object.
+ * @gdbuc_calview: The GDBus object for the view.
+ *
+ * Creates a new view object by issuing the view creation request to the
+ * calendar server.
+ *
+ * Returns: A newly-created view object, or NULL if the request failed.
+ **/
+ECalClientView *
+_e_cal_client_view_new (ECalClient *client, EGdbusCalView *gdbus_calview)
+{
+	ECalClientView *view;
+
+	view = g_object_new (E_TYPE_CAL_CLIENT_VIEW,
+		"client", client,
+		"view", gdbus_calview,
+		NULL);
+
+	return view;
+}
+
+/**
+ * e_cal_client_view_get_client
+ * @view: A #ECalClientView object.
+ *
+ * Get the #ECalClient associated with this view.
+ *
+ * Returns: the associated client.
+ **/
+ECalClient *
+e_cal_client_view_get_client (ECalClientView *view)
+{
+	g_return_val_if_fail (E_IS_CAL_CLIENT_VIEW (view), NULL);
+
+	return view->priv->client;
+}
+
+/**
+ * e_cal_client_view_is_running:
+ * @view: an #ECalClientView
+ *
+ * Retunrs: Whether view is running. Not running views are ignoring
+ * all events sent from the server.
+ **/
+gboolean
+e_cal_client_view_is_running (ECalClientView *view)
+{
+	g_return_val_if_fail (E_IS_CAL_CLIENT_VIEW (view), FALSE);
+
+	return view->priv->running;
+}
+
+/**
+ * e_cal_client_view_start:
+ * @view: An #ECalClientView object.
+ * @error: A #Gerror
+ *
+ * Starts a live query to the calendar/tasks backend.
+ **/
+void
+e_cal_client_view_start (ECalClientView *view, GError **error)
+{
+	ECalClientViewPrivate *priv;
+
+	g_return_if_fail (view != NULL);
+	g_return_if_fail (E_IS_CAL_CLIENT_VIEW (view));
+
+	priv = view->priv;
+
+	if (priv->gdbus_calview) {
+		GError *local_error = NULL;
+
+		if (e_gdbus_cal_view_call_start_sync (priv->gdbus_calview, NULL, &local_error))
+			priv->running = TRUE;
+
+		e_client_util_unwrap_dbus_error (local_error, error, NULL, 0, 0, FALSE);
+	} else {
+		g_set_error (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR, _("Cannot start view, D-Bus proxy gone"));
+	}
+}
+
+/**
+ * e_cal_client_view_stop:
+ * @view: An #ECalClientView object.
+ * @error: A #GError
+ *
+ * Stops a live query to the calendar/tasks backend.
+ */
+void
+e_cal_client_view_stop (ECalClientView *view, GError **error)
+{
+	ECalClientViewPrivate *priv;
+
+	g_return_if_fail (view != NULL);
+	g_return_if_fail (E_IS_CAL_CLIENT_VIEW (view));
+
+	priv = view->priv;
+	priv->running = FALSE;
+
+	if (priv->gdbus_calview) {
+		GError *local_error = NULL;
+
+		e_gdbus_cal_view_call_stop_sync (priv->gdbus_calview, NULL, &local_error);
+
+		e_client_util_unwrap_dbus_error (local_error, error, NULL, 0, 0, FALSE);
+	} else {
+		g_set_error (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR, _("Cannot stop view, D-Bus proxy gone"));
+	}
+}
+
+/**
+ * e_cal_client_view_set_fields_of_interest:
+ * @view: An #ECalClientView object
+ * @fields_of_interest: List of field names in which the client is interested
+ * @error: A #GError
+ *
+ * Client can instruct server to which fields it is interested in only, thus
+ * the server can return less data over the wire. The server can still return
+ * complete objects, this is just a hint to it that the listed fields will
+ * be used only. The UID/RID fields are returned always. Initial views has no fields
+ * of interest and using %NULL for @fields_of_interest will unset any previous
+ * changes.
+ *
+ * Some backends can use summary information of its cache to create artifical
+ * objects, which will omit stored object parsing. If this cannot be done then
+ * it will simply return object as is stored in the cache.
+ **/
+void
+e_cal_client_view_set_fields_of_interest (ECalClientView *view, const GSList *fields_of_interest, GError **error)
+{
+	ECalClientViewPrivate *priv;
+
+	g_return_if_fail (view != NULL);
+	g_return_if_fail (E_IS_CAL_CLIENT_VIEW (view));
+
+	priv = view->priv;
+
+	if (priv->gdbus_calview) {
+		GError *local_error = NULL;
+		gchar **strv;
+
+		strv = e_client_util_slist_to_strv (fields_of_interest);
+		e_gdbus_cal_view_call_set_fields_of_interest_sync (priv->gdbus_calview, (const gchar * const *) strv, NULL, &local_error);
+		g_strfreev (strv);
+
+		e_client_util_unwrap_dbus_error (local_error, error, NULL, 0, 0, FALSE);
+	} else {
+		g_set_error (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR, _("Cannot set fields of interest, D-Bus proxy gone"));
+	}
+}
diff --git a/calendar/libecal/e-cal-client-view.h b/calendar/libecal/e-cal-client-view.h
new file mode 100644
index 0000000..fe3cf27
--- /dev/null
+++ b/calendar/libecal/e-cal-client-view.h
@@ -0,0 +1,68 @@
+/* Evolution calendar - Live view client object
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ * Author: Federico Mena-Quintero <federico 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef E_CAL_CLIENT_VIEW_H
+#define E_CAL_CLIENT_VIEW_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define E_TYPE_CAL_CLIENT_VIEW            (e_cal_client_view_get_type ())
+#define E_CAL_CLIENT_VIEW(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_CAL_CLIENT_VIEW, ECalClientView))
+#define E_CAL_CLIENT_VIEW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_CAL_CLIENT_VIEW, ECalClientViewClass))
+#define E_IS_CAL_CLIENT_VIEW(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_CAL_CLIENT_VIEW))
+#define E_IS_CAL_CLIENT_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_CAL_CLIENT_VIEW))
+
+typedef struct _ECalClientView		ECalClientView;
+typedef struct _ECalClientViewClass	ECalClientViewClass;
+typedef struct _ECalClientViewPrivate	ECalClientViewPrivate;
+
+struct _ECalClient;
+
+struct _ECalClientView {
+	GObject object;
+
+	/*< private >*/
+	ECalClientViewPrivate *priv;
+};
+
+struct _ECalClientViewClass {
+	GObjectClass parent_class;
+
+	/* Notification signals */
+	void (* objects_added)		(ECalClientView *view, const GSList *objects);
+	void (* objects_modified)	(ECalClientView *view, const GSList *objects);
+	void (* objects_removed)	(ECalClientView *view, const GSList *uids);
+
+	void (* progress)		(ECalClientView *view, gint percent, const gchar *message);
+	void (* complete)		(ECalClientView *view, const GError *error);
+};
+
+GType			e_cal_client_view_get_type		(void);
+struct _ECalClient *	e_cal_client_view_get_client		(ECalClientView *view);
+gboolean		e_cal_client_view_is_running		(ECalClientView *view);
+void			e_cal_client_view_set_fields_of_interest(ECalClientView *view, const GSList *fields_of_interest, GError **error);
+void			e_cal_client_view_start			(ECalClientView *view, GError **error);
+void			e_cal_client_view_stop			(ECalClientView *view, GError **error);
+
+G_END_DECLS
+
+#endif /* E_CAL_CLIENT_VIEW_H */
diff --git a/calendar/libecal/e-cal-client.c b/calendar/libecal/e-cal-client.c
new file mode 100644
index 0000000..ad6b4e8
--- /dev/null
+++ b/calendar/libecal/e-cal-client.c
@@ -0,0 +1,4106 @@
+/*
+ * e-cal-client.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 2011 Red Hat, Inc. (www.redhat.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <gio/gio.h>
+
+#include "libedataserver/e-data-server-util.h"
+#include "libedataserver/e-client-private.h"
+
+#include "libedata-cal/e-data-cal-types.h"
+
+#include "e-cal-client.h"
+#include "e-cal-client-view-private.h"
+#include "e-cal-component.h"
+#include "e-cal-check-timezones.h"
+#include "e-cal-time-util.h"
+
+#include "e-gdbus-cal.h"
+#include "e-gdbus-cal-factory.h"
+#include "e-gdbus-cal-view.h"
+
+struct _ECalClientPrivate
+{
+	/* GDBus data */
+	GDBusProxy *gdbus_cal;
+	guint gone_signal_id;
+
+	ECalClientSourceType source_type;
+	icaltimezone *default_zone;
+	gchar *cache_dir;
+
+	GMutex *zone_cache_lock;
+	GHashTable *zone_cache;
+};
+
+enum {
+	FREE_BUSY_DATA,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+G_DEFINE_TYPE (ECalClient, e_cal_client, E_TYPE_CLIENT)
+
+/**
+ * Well-known calendar backend properties:
+ * @CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS: Contains default calendar's email
+ *   address suggested by the backend.
+ * @CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS: Contains default alarm email
+ *   address suggested by the backend.
+ * @CAL_BACKEND_PROPERTY_DEFAULT_OBJECT: Contains iCal component string
+ *   of an #icalcomponent with the default values for properties needed.
+ *   Preferred way of retrieving this property is by
+ *   calling e_cal_client_get_default_object().
+ *
+ * See also: @CLIENT_BACKEND_PROPERTY_OPENED, @CLIENT_BACKEND_PROPERTY_OPENING,
+ *   @CLIENT_BACKEND_PROPERTY_ONLINE, @CLIENT_BACKEND_PROPERTY_READONLY
+ *   @CLIENT_BACKEND_PROPERTY_CACHE_DIR, @CLIENT_BACKEND_PROPERTY_CAPABILITIES
+ **/
+
+/**
+ * e_cal_client_source_type_enum_get_type:
+ *
+ * Registers the #ECalClientSourceTypeEnum type with glib.
+ *
+ * Returns: the ID of the #ECalClientSourceTypeEnum type.
+ */
+GType
+e_cal_client_source_type_enum_get_type (void)
+{
+	static volatile gsize enum_type__volatile = 0;
+
+	if (g_once_init_enter (&enum_type__volatile)) {
+		GType enum_type;
+		static GEnumValue values[] = {
+			{ E_CAL_CLIENT_SOURCE_TYPE_EVENTS, "Events",  "Events"  },
+			{ E_CAL_CLIENT_SOURCE_TYPE_TASKS,  "Tasks",   "Tasks"   },
+			{ E_CAL_CLIENT_SOURCE_TYPE_MEMOS,  "Memos",   "Memos"   },
+			{ E_CAL_CLIENT_SOURCE_TYPE_LAST,   "Invalid", "Invalid" },
+			{ -1, NULL, NULL}
+		};
+
+		enum_type = g_enum_register_static ("ECalClientSourceTypeEnum", values);
+		g_once_init_leave (&enum_type__volatile, enum_type);
+	}
+
+	return enum_type__volatile;
+}
+
+GQuark
+e_cal_client_error_quark (void)
+{
+	static GQuark q = 0;
+	if (q == 0)
+		q = g_quark_from_static_string ("e-cal-client-error-quark");
+
+	return q;
+}
+
+const gchar *
+e_cal_client_error_to_string (ECalClientError code)
+{
+	switch (code) {
+	case E_CAL_CLIENT_ERROR_NO_SUCH_CALENDAR:
+		return C_("CalClientError", "No such calendar");
+	case E_CAL_CLIENT_ERROR_OBJECT_NOT_FOUND:
+		return C_("CalClientError", "Object not found");
+	case E_CAL_CLIENT_ERROR_INVALID_OBJECT:
+		return C_("CalClientError", "Invalid object");
+	case E_CAL_CLIENT_ERROR_UNKNOWN_USER:
+		return C_("CalClientError", "Unknown user");
+	case E_CAL_CLIENT_ERROR_OBJECT_ID_ALREADY_EXISTS:
+		return C_("CalClientError", "Object ID already exists");
+	}
+
+	return C_("CalClientError", "Unknown error");
+}
+
+/**
+ * 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_dbus_error (GError *error, GError **client_error)
+{
+	#define err(a,b) "org.gnome.evolution.dataserver.Calendar." a, b
+	static struct EClientErrorsList
+	cal_errors[] = {
+		{ err ("Success",				-1) },
+		{ err ("ObjectNotFound",			E_CAL_CLIENT_ERROR_OBJECT_NOT_FOUND) },
+		{ err ("InvalidObject",				E_CAL_CLIENT_ERROR_INVALID_OBJECT) },
+		{ err ("ObjectIdAlreadyExists",			E_CAL_CLIENT_ERROR_OBJECT_ID_ALREADY_EXISTS) },
+		{ err ("NoSuchCal",				E_CAL_CLIENT_ERROR_NO_SUCH_CALENDAR) },
+		{ err ("UnknownUser",				E_CAL_CLIENT_ERROR_UNKNOWN_USER) },
+	}, cl_errors[] = {
+		{ err ("Busy",					E_CLIENT_ERROR_BUSY) },
+		{ err ("InvalidArg",				E_CLIENT_ERROR_INVALID_ARG) },
+		{ err ("RepositoryOffline",			E_CLIENT_ERROR_REPOSITORY_OFFLINE) },
+		{ err ("PermissionDenied",			E_CLIENT_ERROR_PERMISSION_DENIED) },
+		{ err ("AuthenticationFailed",			E_CLIENT_ERROR_AUTHENTICATION_FAILED) },
+		{ err ("AuthenticationRequired",		E_CLIENT_ERROR_AUTHENTICATION_REQUIRED) },
+		{ err ("CouldNotCancel",			E_CLIENT_ERROR_COULD_NOT_CANCEL) },
+		{ err ("NotSupported",				E_CLIENT_ERROR_NOT_SUPPORTED) },
+		{ err ("InvalidRange",				E_CLIENT_ERROR_OTHER_ERROR) },
+		{ err ("UnsupportedField",			E_CLIENT_ERROR_OTHER_ERROR) },
+		{ err ("UnsupportedMethod",			E_CLIENT_ERROR_OTHER_ERROR) },
+		{ err ("UnsupportedAuthenticationMethod",	E_CLIENT_ERROR_OTHER_ERROR) },
+		{ err ("TLSNotAvailable",			E_CLIENT_ERROR_OTHER_ERROR) },
+		{ err ("OfflineUnavailable",			E_CLIENT_ERROR_OTHER_ERROR) },
+		{ err ("SearchSizeLimitExceeded",		E_CLIENT_ERROR_OTHER_ERROR) },
+		{ err ("SearchTimeLimitExceeded",		E_CLIENT_ERROR_OTHER_ERROR) },
+		{ err ("InvalidQuery",				E_CLIENT_ERROR_OTHER_ERROR) },
+		{ err ("QueryRefused",				E_CLIENT_ERROR_OTHER_ERROR) },
+		{ err ("InvalidServerVersion",			E_CLIENT_ERROR_OTHER_ERROR) },
+		{ err ("OtherError",				E_CLIENT_ERROR_OTHER_ERROR) }
+	};
+	#undef err
+
+	if (error == NULL)
+		return TRUE;
+
+	if (!e_client_util_unwrap_dbus_error (error, client_error, cal_errors, G_N_ELEMENTS (cal_errors), E_CAL_CLIENT_ERROR, TRUE))
+		e_client_util_unwrap_dbus_error (error, client_error, cl_errors, G_N_ELEMENTS (cl_errors), E_CLIENT_ERROR, FALSE);
+
+	return FALSE;
+}
+
+static void
+set_proxy_gone_error (GError **error)
+{
+	g_set_error_literal (error, E_CLIENT_ERROR, E_CLIENT_ERROR_DBUS_ERROR, _("D-Bus calendar proxy gone"));
+}
+
+static guint active_cal_clients = 0, cal_connection_closed_id = 0;
+static EGdbusCalFactory *cal_factory_proxy = NULL;
+static GStaticRecMutex cal_factory_proxy_lock = G_STATIC_REC_MUTEX_INIT;
+#define LOCK_FACTORY()   g_static_rec_mutex_lock (&cal_factory_proxy_lock)
+#define UNLOCK_FACTORY() g_static_rec_mutex_unlock (&cal_factory_proxy_lock)
+
+static void gdbus_cal_factory_proxy_closed_cb (GDBusConnection *connection, gboolean remote_peer_vanished, GError *error, gpointer user_data);
+
+static void
+gdbus_cal_factory_proxy_disconnect (GDBusConnection *connection)
+{
+	LOCK_FACTORY ();
+
+	if (!connection && cal_factory_proxy)
+		connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (cal_factory_proxy));
+
+	if (connection && cal_connection_closed_id) {
+		g_dbus_connection_signal_unsubscribe (connection, cal_connection_closed_id);
+		g_signal_handlers_disconnect_by_func (connection, gdbus_cal_factory_proxy_closed_cb, NULL);
+	}
+
+	if (cal_factory_proxy)
+		g_object_unref (cal_factory_proxy);
+
+	cal_connection_closed_id = 0;
+	cal_factory_proxy = NULL;
+
+	UNLOCK_FACTORY ();
+}
+
+static void
+gdbus_cal_factory_proxy_closed_cb (GDBusConnection *connection, gboolean remote_peer_vanished, GError *error, gpointer user_data)
+{
+	GError *err = NULL;
+
+	LOCK_FACTORY ();
+
+	gdbus_cal_factory_proxy_disconnect (connection);
+
+	if (error)
+		unwrap_dbus_error (g_error_copy (error), &err);
+
+	if (err) {
+		g_debug ("GDBus connection is closed%s: %s", remote_peer_vanished ? ", remote peer vanished" : "", err->message);
+		g_error_free (err);
+	} else if (active_cal_clients) {
+		g_debug ("GDBus connection is closed%s", remote_peer_vanished ? ", remote peer vanished" : "");
+	}
+
+	UNLOCK_FACTORY ();
+}
+
+static void
+gdbus_cal_factory_connection_gone_cb (GDBusConnection *connection, const gchar *sender_name, const gchar *object_path, const gchar *interface_name, const gchar *signal_name, GVariant *parameters, gpointer user_data)
+{
+	/* signal subscription takes care of correct parameters,
+	   thus just do what is to be done here */
+	gdbus_cal_factory_proxy_closed_cb (connection, TRUE, NULL, user_data);
+}
+
+static gboolean
+gdbus_cal_factory_activate (GError **error)
+{
+	GDBusConnection *connection;
+
+	LOCK_FACTORY ();
+
+	if (G_LIKELY (cal_factory_proxy)) {
+		UNLOCK_FACTORY ();
+		return TRUE;
+	}
+
+	cal_factory_proxy = e_gdbus_cal_factory_proxy_new_for_bus_sync (
+		G_BUS_TYPE_SESSION,
+		G_DBUS_PROXY_FLAGS_NONE,
+		CALENDAR_DBUS_SERVICE_NAME,
+		"/org/gnome/evolution/dataserver/CalendarFactory",
+		NULL,
+		error);
+
+	if (!cal_factory_proxy) {
+		UNLOCK_FACTORY ();
+		return FALSE;
+	}
+
+	connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (cal_factory_proxy));
+	cal_connection_closed_id = g_dbus_connection_signal_subscribe (connection,
+		NULL,						/* sender */
+		"org.freedesktop.DBus",				/* interface */
+		"NameOwnerChanged",				/* member */
+		"/org/freedesktop/DBus",			/* object_path */
+		"org.gnome.evolution.dataserver.Calendar",	/* arg0 */
+		G_DBUS_SIGNAL_FLAGS_NONE,
+		gdbus_cal_factory_connection_gone_cb, NULL, NULL);
+
+	g_signal_connect (connection, "closed", G_CALLBACK (gdbus_cal_factory_proxy_closed_cb), NULL);
+
+	UNLOCK_FACTORY ();
+
+	return TRUE;
+}
+
+static void gdbus_cal_client_disconnect (ECalClient *client);
+
+/*
+ * Called when the calendar server dies.
+ */
+static void
+gdbus_cal_client_closed_cb (GDBusConnection *connection, gboolean remote_peer_vanished, GError *error, ECalClient *client)
+{
+	GError *err = NULL;
+
+	g_assert (E_IS_CAL_CLIENT (client));
+
+	if (error)
+		unwrap_dbus_error (g_error_copy (error), &err);
+
+	if (err) {
+		g_debug (G_STRLOC ": ECalClient GDBus connection is closed%s: %s", remote_peer_vanished ? ", remote peer vanished" : "", err->message);
+		g_error_free (err);
+	} else {
+		g_debug (G_STRLOC ": ECalClient GDBus connection is closed%s", remote_peer_vanished ? ", remote peer vanished" : "");
+	}
+
+	gdbus_cal_client_disconnect (client);
+
+	e_client_emit_backend_died (E_CLIENT (client));
+}
+
+static void
+gdbus_cal_client_connection_gone_cb (GDBusConnection *connection, const gchar *sender_name, const gchar *object_path, const gchar *interface_name, const gchar *signal_name, GVariant *parameters, gpointer user_data)
+{
+	/* signal subscription takes care of correct parameters,
+	   thus just do what is to be done here */
+	gdbus_cal_client_closed_cb (connection, TRUE, NULL, user_data);
+}
+
+static void
+gdbus_cal_client_disconnect (ECalClient *client)
+{
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CAL_CLIENT (client));
+	g_return_if_fail (client->priv != NULL);
+
+	/* Ensure that everything relevant is NULL */
+	LOCK_FACTORY ();
+
+	if (client->priv->gdbus_cal) {
+		GDBusConnection *connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (client->priv->gdbus_cal));
+
+		g_signal_handlers_disconnect_by_func (connection, gdbus_cal_client_closed_cb, client);
+		g_dbus_connection_signal_unsubscribe (connection, client->priv->gone_signal_id);
+		client->priv->gone_signal_id = 0;
+
+		e_gdbus_cal_call_close_sync (client->priv->gdbus_cal, NULL, NULL);
+		g_object_unref (client->priv->gdbus_cal);
+		client->priv->gdbus_cal = NULL;
+	}
+
+	UNLOCK_FACTORY ();
+}
+
+static void
+backend_error_cb (EGdbusCal *object, const gchar *message, ECalClient *client)
+{
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CAL_CLIENT (client));
+	g_return_if_fail (message != NULL);
+
+	e_client_emit_backend_error (E_CLIENT (client), message);
+}
+
+static void
+readonly_cb (EGdbusCal *object, gboolean readonly, ECalClient *client)
+{
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CAL_CLIENT (client));
+
+	e_client_set_readonly (E_CLIENT (client), readonly);
+}
+
+static void
+online_cb (EGdbusCal *object, gboolean is_online, ECalClient *client)
+{
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CAL_CLIENT (client));
+
+	e_client_set_online (E_CLIENT (client), is_online);
+}
+
+static void
+auth_required_cb (EGdbusCal *object, const gchar * const *credentials_strv, ECalClient *client)
+{
+	ECredentials *credentials;
+
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CAL_CLIENT (client));
+
+	if (credentials_strv)
+		credentials = e_credentials_new_strv (credentials_strv);
+	else
+		credentials = e_credentials_new ();
+
+	e_client_process_authentication (E_CLIENT (client), credentials);
+
+	e_credentials_free (credentials);
+}
+
+static void
+opened_cb (EGdbusCal *object, const gchar * const *error_strv, ECalClient *client)
+{
+	GError *error = NULL;
+
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CAL_CLIENT (client));
+	g_return_if_fail (error_strv != NULL);
+	g_return_if_fail (e_gdbus_templates_decode_error (error_strv, &error));
+
+	e_client_emit_opened (E_CLIENT (client), error);
+
+	if (error)
+		g_error_free (error);
+}
+
+static void
+free_busy_data_cb (EGdbusCal *object, const gchar * const *free_busy_strv, ECalClient *client)
+{
+	GSList *ecalcomps = NULL;
+	gint ii;
+
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CAL_CLIENT (client));
+	g_return_if_fail (free_busy_strv != NULL);
+
+
+	for (ii = 0; free_busy_strv[ii]; ii++) {
+		ECalComponent *comp;
+		icalcomponent *icalcomp;
+		icalcomponent_kind kind;
+
+		icalcomp = icalcomponent_new_from_string (free_busy_strv[ii]);
+		if (!icalcomp)
+			continue;
+
+		kind = icalcomponent_isa (icalcomp);
+		if (kind == ICAL_VFREEBUSY_COMPONENT) {
+			comp = e_cal_component_new ();
+			if (!e_cal_component_set_icalcomponent (comp, icalcomp)) {
+				icalcomponent_free (icalcomp);
+				g_object_unref (G_OBJECT (comp));
+				continue;
+			}
+
+			ecalcomps = g_slist_prepend (ecalcomps, comp);
+		} else {
+			icalcomponent_free (icalcomp);
+		}
+	}
+
+	ecalcomps = g_slist_reverse (ecalcomps);
+
+	g_signal_emit (client, signals[FREE_BUSY_DATA], 0, ecalcomps);
+
+	e_client_util_free_object_slist (ecalcomps);
+}
+
+static EDataCalObjType
+convert_type (ECalClientSourceType type)
+{
+	switch (type) {
+	case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+		return Event;
+	case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+		return Todo;
+	case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+		return Journal;
+	default:
+		return AnyType;
+	}
+
+	return AnyType;
+}
+
+/**
+ * e_cal_client_new:
+ * @source: An #ESource pointer
+ * @source_type: source type of the calendar
+ * @error: A #GError pointer
+ *
+ * Creates a new #ECalClient corresponding to the given source.  There are
+ * only two operations that are valid on this calendar at this point:
+ * e_client_open(), and e_client_remove().
+ *
+ * Returns: a new but unopened #ECalClient.
+ *
+ * Since: 3.2
+ **/
+ECalClient *
+e_cal_client_new (ESource *source, ECalClientSourceType source_type, GError **error)
+{
+	ECalClient *client;
+	GError *err = NULL;
+	GDBusConnection *connection;
+	gchar *xml, **strv;
+	gchar *path = NULL;
+
+	g_return_val_if_fail (source != NULL, NULL);
+	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
+	g_return_val_if_fail (source_type == E_CAL_CLIENT_SOURCE_TYPE_EVENTS || source_type == E_CAL_CLIENT_SOURCE_TYPE_TASKS || source_type == E_CAL_CLIENT_SOURCE_TYPE_MEMOS, NULL);
+
+	if (!gdbus_cal_factory_activate (&err)) {
+		if (err) {
+			unwrap_dbus_error (err, &err);
+			g_warning ("%s: Failed to run calendar factory: %s", G_STRFUNC, err->message);
+			g_propagate_error (error, err);
+		} else {
+			g_warning ("%s: Failed to run calendar factory: Unknown error", G_STRFUNC);
+			g_set_error_literal (error, E_CLIENT_ERROR, E_CLIENT_ERROR_DBUS_ERROR, _("Failed to run calendar factory"));
+		}
+
+		return NULL;
+	}
+
+	xml = e_source_to_standalone_xml (source);
+	if (!xml || !*xml) {
+		g_free (xml);
+		g_set_error_literal (error, E_CLIENT_ERROR, E_CLIENT_ERROR_INVALID_ARG, _("Invalid source"));
+		return NULL;
+	}
+
+	strv = e_gdbus_cal_factory_encode_get_cal (xml, convert_type (source_type));
+	if (!strv) {
+		g_free (xml);
+		g_set_error_literal (error, E_CLIENT_ERROR, E_CLIENT_ERROR_OTHER_ERROR, _("Other error"));
+		return NULL;
+	}
+
+	client = g_object_new (E_TYPE_CAL_CLIENT, "source", source, NULL);
+	client->priv->source_type = source_type;
+
+	if (!e_gdbus_cal_factory_call_get_cal_sync (G_DBUS_PROXY (cal_factory_proxy), (const gchar * const *) strv, &path, NULL, &err)) {
+		unwrap_dbus_error (err, &err);
+		g_free (xml);
+		g_strfreev (strv);
+		g_warning ("%s: Cannot get calendar from factory: %s", G_STRFUNC, err ? err->message : "[no error]");
+		if (err)
+			g_propagate_error (error, err);
+		g_object_unref (client);
+
+		return NULL;
+	}
+
+	g_free (xml);
+	g_strfreev (strv);
+
+	client->priv->gdbus_cal = G_DBUS_PROXY (e_gdbus_cal_proxy_new_sync (g_dbus_proxy_get_connection (G_DBUS_PROXY (cal_factory_proxy)),
+						      G_DBUS_PROXY_FLAGS_NONE,
+						      CALENDAR_DBUS_SERVICE_NAME,
+						      path,
+						      NULL,
+						      &err));
+
+	if (!client->priv->gdbus_cal) {
+		g_free (path);
+		unwrap_dbus_error (err, &err);
+		g_warning ("%s: Cannot create calendar proxy: %s", G_STRFUNC, err ? err->message : "Unknown error");
+		if (err)
+			g_propagate_error (error, err);
+
+		g_object_unref (client);
+
+		return NULL;
+	}
+
+	g_free (path);
+
+	connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (client->priv->gdbus_cal));
+	client->priv->gone_signal_id = g_dbus_connection_signal_subscribe (connection,
+		"org.freedesktop.DBus",				/* sender */
+		"org.freedesktop.DBus",				/* interface */
+		"NameOwnerChanged",				/* member */
+		"/org/freedesktop/DBus",			/* object_path */
+		"org.gnome.evolution.dataserver.Calendar",	/* arg0 */
+		G_DBUS_SIGNAL_FLAGS_NONE,
+		gdbus_cal_client_connection_gone_cb, client, NULL);
+
+	g_signal_connect (connection, "closed", G_CALLBACK (gdbus_cal_client_closed_cb), client);
+
+	g_signal_connect (client->priv->gdbus_cal, "backend_error", G_CALLBACK (backend_error_cb), client);
+	g_signal_connect (client->priv->gdbus_cal, "readonly", G_CALLBACK (readonly_cb), client);
+	g_signal_connect (client->priv->gdbus_cal, "online", G_CALLBACK (online_cb), client);
+	g_signal_connect (client->priv->gdbus_cal, "auth-required", G_CALLBACK (auth_required_cb), client);
+	g_signal_connect (client->priv->gdbus_cal, "opened", G_CALLBACK (opened_cb), client);
+	g_signal_connect (client->priv->gdbus_cal, "free-busy-data", G_CALLBACK (free_busy_data_cb), client);
+
+	return client;
+}
+
+/**
+ * e_cal_client_new_from_uri:
+ * @uri: the URI to load
+ * @source_type: source type of the calendar
+ * @error: A #GError pointer
+ *
+ * Creates a new #ECalClient corresponding to the given uri.  See the
+ * documentation for e_cal_client_new() for further information.
+ *
+ * Returns: a new but unopened #ECalClient.
+ *
+ * Since: 3.2
+ **/
+ECalClient *
+e_cal_client_new_from_uri (const gchar *uri, ECalClientSourceType source_type, GError **error)
+{
+	ESourceList *source_list = NULL;
+	ESource *source;
+	ECalClient *client;
+
+	g_return_val_if_fail (uri != NULL, NULL);
+
+	if (!e_cal_client_get_sources (&source_list, source_type, error))
+		return NULL;
+
+	source = e_client_util_get_source_for_uri (source_list, uri);
+	if (!source && g_str_has_prefix (uri, "file://")) {
+		gchar *local_uri;
+
+		local_uri = g_strconcat ("local://", uri + 7, NULL);
+		source = e_client_util_get_source_for_uri (source_list, uri);
+
+		g_free (local_uri);
+	}
+
+	if (!source) {
+		g_object_unref (source_list);
+		g_set_error (error, E_CLIENT_ERROR, E_CLIENT_ERROR_INVALID_ARG, _("Incorrect uri '%s'"), uri);
+
+		return NULL;
+	}
+
+	client = e_cal_client_new (source, source_type, error);
+
+	g_object_unref (source);
+	g_object_unref (source_list);
+
+	return client;
+}
+
+/**
+ * e_cal_client_new_system:
+ * @source_type: source type of the calendar
+ * @error: A #GError pointer
+ *
+ * Creates a new #ECalClient corresponding to the user's system
+ * calendar.  See the documentation for e_cal_client_new() for further
+ * information.
+ *
+ * Returns: a new but unopened #ECalClient.
+ *
+ * Since: 3.2
+ **/
+ECalClient *
+e_cal_client_new_system (ECalClientSourceType source_type, GError **error)
+{
+	ESourceList *source_list = NULL;
+	ESource *source;
+	ECalClient *client;
+
+	if (!e_cal_client_get_sources (&source_list, source_type, error))
+		return NULL;
+
+	source = e_client_util_get_system_source (source_list);
+	if (!source) {
+		g_object_unref (source_list);
+		g_set_error_literal (error, E_CAL_CLIENT_ERROR, E_CAL_CLIENT_ERROR_NO_SUCH_CALENDAR, _("Failed to find system calendar"));
+
+		return NULL;
+	}
+
+	client = e_cal_client_new (source, source_type, error);
+
+	g_object_unref (source);
+	g_object_unref (source_list);
+
+	return client;
+}
+
+/**
+ * e_cal_client_new_default:
+ * @source_type: source type of the calendar
+ * @error: return location for a #GError, or %NULL
+ *
+ * Creates a new #ECalClient corresponding to the user's default
+ * calendar.  See the documentation for e_cal_client_new() for
+ * further information.
+ *
+ * Returns: a new but unopened #ECalClient
+ *
+ * Since: 3.2
+ **/
+ECalClient *
+e_cal_client_new_default (ECalClientSourceType source_type, GError **error)
+{
+	ESourceList *source_list = NULL;
+	ESource *source;
+	ECalClient *client;
+
+	if (!e_cal_client_get_sources (&source_list, source_type, error))
+		return NULL;
+
+	source = e_source_list_peek_default_source (source_list);
+	if (!source) {
+		g_set_error_literal (error, E_CAL_CLIENT_ERROR, E_CAL_CLIENT_ERROR_NO_SUCH_CALENDAR, _("Calendar does not exist"));
+		g_object_unref (source_list);
+
+		return NULL;
+	}
+
+	client = e_cal_client_new (source, source_type, error);
+
+	g_object_unref (source_list);
+
+	return client;
+}
+
+/**
+ * e_cal_client_set_default:
+ * @client: An #ECalClient pointer
+ * @error: A #GError pointer
+ *
+ * Sets the #ESource of the #ECalClient as the "default" calendar.  This is the source
+ * that will be loaded in the e_cal_client_get_default_calendar() call.
+ *
+ * Returns: %TRUE if the setting was stored in libecal's ESourceList, otherwise %FALSE.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_set_default (ECalClient *client, GError **error)
+{
+	ESource *source;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+
+	source = e_client_get_source (E_CLIENT (client));
+	g_return_val_if_fail (source != NULL, FALSE);
+
+	return e_cal_client_set_default_source (source, e_cal_client_get_source_type (client), error);
+}
+
+/**
+ * e_cal_client_set_default_source:
+ * @source: An #ESource pointer
+ * @source_type: source type of the calendar
+ * @error: A #GError pointer
+ *
+ * Sets @source as the "default" calendar.  This is the source that
+ * will be loaded in the e_cal_client_get_default_calendar() call.
+ *
+ * Returns: %TRUE if the setting was stored in libecal's ESourceList, otherwise %FALSE.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_set_default_source (ESource *source, ECalClientSourceType source_type, GError **error)
+{
+	ESourceList *source_list = NULL;
+	gboolean res = FALSE;
+
+	g_return_val_if_fail (source != NULL, FALSE);
+	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+
+	if (!e_cal_client_get_sources (&source_list, source_type, error))
+		return FALSE;
+
+	res = e_client_util_set_default (source_list, source);
+
+	if (res)
+		res = e_source_list_sync (source_list, error);
+	else
+		g_set_error (error, E_CLIENT_ERROR, E_CLIENT_ERROR_INVALID_ARG,
+			_("There was no source for UID '%s' stored in a source list."), e_source_peek_uid (source));
+
+	g_object_unref (source_list);
+
+	return res;
+}
+
+/**
+ * e_cal_client_get_sources:
+ * @sources: (out): A pointer to an #ESourceList to set
+ * @source_type: source type of calendars
+ * @error: A pointer to a GError to set on error
+ *
+ * Populate @*sources with the list of all sources which have been
+ * added to Evolution.
+ *
+ * Returns: %TRUE if @sources was set, otherwise %FALSE.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_get_sources (ESourceList **sources, ECalClientSourceType source_type, GError **error)
+{
+	GConfClient *gconf;
+	const gchar *key = NULL;
+
+	g_return_val_if_fail (sources != NULL, FALSE);
+
+	switch (source_type) {
+	case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+		key = "/apps/evolution/calendar/sources";
+		break;
+	case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+		key = "/apps/evolution/tasks/sources";
+		break;
+	case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+		key = "/apps/evolution/memos/sources";
+		break;
+	default:
+		g_set_error_literal (error, E_CLIENT_ERROR, E_CLIENT_ERROR_INVALID_ARG, _("Invalid source type"));
+		return FALSE;
+	}
+
+	g_return_val_if_fail (key != NULL, FALSE);
+
+	gconf = gconf_client_get_default ();
+	*sources = e_source_list_new_for_gconf (gconf, key);
+	g_object_unref (gconf);
+
+	return TRUE;
+}
+
+/**
+ * e_cal_client_get_source_type:
+ * @client: A calendar client.
+ *
+ * Gets the source type of the calendar client.
+ *
+ * Returns: an #ECalClientSourceType value corresponding
+ * to the source type of the calendar client.
+ *
+ * Since: 3.2
+ **/
+ECalClientSourceType
+e_cal_client_get_source_type (ECalClient *client)
+{
+	g_return_val_if_fail (client != NULL, E_CAL_CLIENT_SOURCE_TYPE_LAST);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (client), E_CAL_CLIENT_SOURCE_TYPE_LAST);
+	g_return_val_if_fail (client->priv != NULL, E_CAL_CLIENT_SOURCE_TYPE_LAST);
+
+	return client->priv->source_type;
+}
+
+/**
+ * e_cal_client_get_local_attachment_store
+ * @client: A calendar client.
+ *
+ * Queries the URL where the calendar attachments are
+ * serialized in the local filesystem. This enable clients
+ * to operate with the reference to attachments rather than the data itself
+ * unless it specifically uses the attachments for open/sending
+ * operations.
+ *
+ * Returns: The URL where the attachments are serialized in the
+ * local filesystem.
+ *
+ * Since: 3.2
+ **/
+const gchar *
+e_cal_client_get_local_attachment_store (ECalClient *client)
+{
+	gchar *cache_dir = NULL;
+	GError *error = NULL;
+
+	g_return_val_if_fail (client != NULL, NULL);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (client), NULL);
+	g_return_val_if_fail (client->priv != NULL, NULL);
+
+	if (client->priv->cache_dir || !client->priv->gdbus_cal)
+		return client->priv->cache_dir;
+
+	e_gdbus_cal_call_get_backend_property_sync (client->priv->gdbus_cal, CLIENT_BACKEND_PROPERTY_CACHE_DIR, &cache_dir, NULL, &error);
+
+	if (error == NULL) {
+		client->priv->cache_dir = cache_dir;
+	} else {
+		unwrap_dbus_error (error, &error);
+		g_warning ("%s", error->message);
+		g_error_free (error);
+	}
+
+	return client->priv->cache_dir;
+}
+
+/**
+ * e_cal_client_set_default_timezone:
+ * @client: A calendar client.
+ * @zone: A timezone object.
+ *
+ * Sets the default timezone to use to resolve DATE and floating DATE-TIME
+ * values. This will typically be from the user's timezone setting. Call this
+ * before using any other object fetching functions.
+ *
+ * Since: 3.2
+ **/
+void
+e_cal_client_set_default_timezone (ECalClient *client, /* const */ icaltimezone *zone)
+{
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CAL_CLIENT (client));
+	g_return_if_fail (client->priv != NULL);
+	g_return_if_fail (zone != NULL);
+
+	icaltimezone_free (client->priv->default_zone, 1);
+	client->priv->default_zone = icaltimezone_copy (zone);
+}
+
+/**
+ * e_cal_client_get_default_timezone:
+ * @client: A calendar client.
+ *
+ * Returns: Default timezone previously set with e_cal_client_set_default_timezone().
+ * Returned pointer is owned by the @client and should not be freed.
+ *
+ * Since: 3.2
+ **/
+/* const */ icaltimezone *
+e_cal_client_get_default_timezone (ECalClient *client)
+{
+	g_return_val_if_fail (client != NULL, NULL);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (client), NULL);
+	g_return_val_if_fail (client->priv != NULL, NULL);
+
+	return client->priv->default_zone;
+}
+
+/**
+ * e_cal_client_check_one_alarm_only:
+ * @client: A calendar client.
+ *
+ * Checks if a calendar supports only one alarm per component.
+ *
+ * Returns: TRUE if the calendar allows only one alarm, FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_check_one_alarm_only (ECalClient *client)
+{
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+
+	return e_client_check_capability (E_CLIENT (client), CAL_STATIC_CAPABILITY_ONE_ALARM_ONLY);
+}
+
+/**
+ * e_cal_client_check_save_schedules:
+ * @client: A calendar client.
+ *
+ * Checks whether the calendar saves schedules.
+ *
+ * Returns: TRUE if it saves schedules, FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_check_save_schedules (ECalClient *client)
+{
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+
+	return e_client_check_capability (E_CLIENT (client), CAL_STATIC_CAPABILITY_SAVE_SCHEDULES);
+}
+
+/**
+ * e_cal_client_check_organizer_must_attend:
+ * @client: A calendar client.
+ *
+ * Checks if a calendar forces organizers of meetings to be also attendees.
+ *
+ * Returns: TRUE if the calendar forces organizers to attend meetings,
+ * FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_check_organizer_must_attend (ECalClient *client)
+{
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+
+	return e_client_check_capability (E_CLIENT (client), CAL_STATIC_CAPABILITY_ORGANIZER_MUST_ATTEND);
+}
+
+/**
+ * e_cal_get_organizer_must_accept:
+ * @client: A calendar client.
+ *
+ * Checks whether a calendar requires organizer to accept their attendance to
+ * meetings.
+ *
+ * Returns: TRUE if the calendar requires organizers to accept, FALSE
+ * otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_check_organizer_must_accept (ECalClient *client)
+{
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+
+	return e_client_check_capability (E_CLIENT (client), CAL_STATIC_CAPABILITY_ORGANIZER_MUST_ACCEPT);
+}
+
+/**
+ * e_cal_client_check_recurrences_no_master:
+ * @client: A calendar client.
+ *
+ * Checks if the calendar has a master object for recurrences.
+ *
+ * Returns: TRUE if the calendar has a master object for recurrences,
+ * FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_check_recurrences_no_master (ECalClient *client)
+{
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+
+	return e_client_check_capability (E_CLIENT (client), CAL_STATIC_CAPABILITY_RECURRENCES_NO_MASTER);
+}
+
+/**
+ * e_cal_client_free_icalcomp_slist:
+ * @icalcomps: slist of icalcomponent objects
+ *
+ * Frees each element of @icalcomps list and the list itself.
+ * Each element is an object of icalcomponent type.
+ *
+ * Since: 3.2
+ **/
+void
+e_cal_client_free_icalcomp_slist (GSList *icalcomps)
+{
+	g_slist_foreach (icalcomps, (GFunc) icalcomponent_free, NULL);
+	g_slist_free (icalcomps);
+}
+
+/**
+ * e_cal_client_free_ecalcomp_slist:
+ * @ecalcomps: list of ECalComponent objects
+ *
+ * Frees each element of @ecalcomps list and the list itself.
+ * Each element is an object of ECalComponent type.
+ *
+ * Since: 3.2
+ **/
+void
+e_cal_client_free_ecalcomp_slist (GSList *ecalcomps)
+{
+	g_slist_foreach (ecalcomps, (GFunc) g_object_unref, NULL);
+	g_slist_free (ecalcomps);
+}
+
+/**
+ * e_cal_client_resolve_tzid_cb:
+ * @tzid: ID of the timezone to resolve.
+ * @data: Closure data for the callback, in this case #ECalClient.
+ *
+ * Resolves TZIDs for the recurrence generator.
+ *
+ * Returns: The timezone identified by the @tzid argument, or %NULL if
+ * it could not be found.
+ */
+icaltimezone *
+e_cal_client_resolve_tzid_cb (const gchar *tzid, gpointer data)
+{
+	ECalClient *client = data;
+	icaltimezone *zone = NULL;
+	GError *error = NULL;
+
+	g_return_val_if_fail (client != NULL, NULL);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (client), NULL);
+
+	e_cal_client_get_timezone_sync (client, tzid, &zone, NULL, &error);
+
+	if (error) {
+		g_debug ("%s: Failed to find '%s' timezone: %s", G_STRFUNC, tzid, error->message);
+		g_error_free (error);
+	}
+
+	return zone;
+}
+
+struct comp_instance {
+	ECalComponent *comp;
+	time_t start;
+	time_t end;
+};
+
+struct instances_info {
+	GSList **instances;
+	icaltimezone *start_zone;
+};
+
+/* Called from cal_recur_generate_instances(); adds an instance to the list */
+static gboolean
+add_instance (ECalComponent *comp, time_t start, time_t end, gpointer data)
+{
+	GSList **list;
+	struct comp_instance *ci;
+	struct icaltimetype itt;
+	icalcomponent *icalcomp;
+	struct instances_info *instances_hold;
+
+	instances_hold = data;
+	list = instances_hold->instances;
+
+	ci = g_new (struct comp_instance, 1);
+
+	icalcomp = icalcomponent_new_clone (e_cal_component_get_icalcomponent (comp));
+
+	/* add the instance to the list */
+	ci->comp = e_cal_component_new ();
+	e_cal_component_set_icalcomponent (ci->comp, icalcomp);
+
+	/* set the RECUR-ID for the instance */
+	if (e_cal_util_component_has_recurrences (icalcomp)) {
+		if (!(icalcomponent_get_first_property (icalcomp, ICAL_RECURRENCEID_PROPERTY))) {
+			ECalComponentRange *range;
+			ECalComponentDateTime datetime;
+
+			e_cal_component_get_dtstart (comp, &datetime);
+
+			if (instances_hold->start_zone)
+				itt = icaltime_from_timet_with_zone (start, datetime.value->is_date, instances_hold->start_zone);
+			else {
+				itt = icaltime_from_timet (start, datetime.value->is_date);
+
+				if (datetime.tzid) {
+					g_free ((gchar *) datetime.tzid);
+					datetime.tzid = NULL;
+				}
+			}
+
+			g_free (datetime.value);
+			datetime.value = &itt;
+
+			range = g_new0 (ECalComponentRange, 1);
+			range->type = E_CAL_COMPONENT_RANGE_SINGLE;
+			range->datetime = datetime;
+
+			e_cal_component_set_recurid (ci->comp, range);
+
+			if (datetime.tzid)
+				g_free ((gchar *) datetime.tzid);
+			g_free (range);
+		}
+	}
+
+	ci->start = start;
+	ci->end = end;
+
+	*list = g_slist_prepend (*list, ci);
+
+	return TRUE;
+}
+
+/* Used from g_slist_sort(); compares two struct comp_instance structures */
+static gint
+compare_comp_instance (gconstpointer a, gconstpointer b)
+{
+	const struct comp_instance *cia, *cib;
+	time_t diff;
+
+	cia = a;
+	cib = b;
+
+	diff = cia->start - cib->start;
+	return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
+}
+
+static GSList *
+process_detached_instances (GSList *instances, GSList *detached_instances)
+{
+	struct comp_instance *ci, *cid;
+	GSList *dl, *unprocessed_instances = NULL;
+
+	for (dl = detached_instances; dl != NULL; dl = dl->next) {
+		GSList *il;
+		const gchar *uid;
+		gboolean processed;
+		ECalComponentRange recur_id, instance_recur_id;
+
+		processed = FALSE;
+
+		cid = dl->data;
+		e_cal_component_get_uid (cid->comp, &uid);
+		e_cal_component_get_recurid (cid->comp, &recur_id);
+
+		/* search for coincident instances already expanded */
+		for (il = instances; il != NULL; il = il->next) {
+			const gchar *instance_uid;
+			gint cmp;
+
+			ci = il->data;
+			e_cal_component_get_uid (ci->comp, &instance_uid);
+			e_cal_component_get_recurid (ci->comp, &instance_recur_id);
+			if (strcmp (uid, instance_uid) == 0) {
+				gchar *i_rid = NULL, *d_rid = NULL;
+
+				i_rid = e_cal_component_get_recurid_as_string (ci->comp);
+				d_rid = e_cal_component_get_recurid_as_string (cid->comp);
+
+				if (i_rid && d_rid && strcmp (i_rid, d_rid) == 0) {
+					g_object_unref (ci->comp);
+					ci->comp = g_object_ref (cid->comp);
+					ci->start = cid->start;
+					ci->end = cid->end;
+
+					processed = TRUE;
+				} else {
+					if (!instance_recur_id.datetime.value ||
+					    !recur_id.datetime.value) {
+						/*
+						 * Prevent obvious segfault by ignoring missing
+						 * recurrency ids. Real problem might be elsewhere,
+						 * but anything is better than crashing...
+						 */
+						g_log (G_LOG_DOMAIN,
+						       G_LOG_LEVEL_CRITICAL,
+						       "UID %s: instance RECURRENCE-ID %s + detached instance RECURRENCE-ID %s: cannot compare",
+						       uid,
+						       i_rid,
+						       d_rid);
+
+						e_cal_component_free_datetime (&instance_recur_id.datetime);
+						g_free (i_rid);
+						g_free (d_rid);
+						continue;
+					}
+					cmp = icaltime_compare (*instance_recur_id.datetime.value,
+								*recur_id.datetime.value);
+					if ((recur_id.type == E_CAL_COMPONENT_RANGE_THISPRIOR && cmp <= 0) ||
+					    (recur_id.type == E_CAL_COMPONENT_RANGE_THISFUTURE && cmp >= 0)) {
+						ECalComponent *comp;
+
+						comp = e_cal_component_new ();
+						e_cal_component_set_icalcomponent (
+							comp,
+							icalcomponent_new_clone (e_cal_component_get_icalcomponent (cid->comp)));
+						e_cal_component_set_recurid (comp, &instance_recur_id);
+
+						/* replace the generated instances */
+						g_object_unref (ci->comp);
+						ci->comp = comp;
+					}
+				}
+				g_free (i_rid);
+				g_free (d_rid);
+			}
+			e_cal_component_free_datetime (&instance_recur_id.datetime);
+		}
+
+		e_cal_component_free_datetime (&recur_id.datetime);
+
+		if (!processed)
+			unprocessed_instances = g_slist_prepend (unprocessed_instances, cid);
+	}
+
+	/* add the unprocessed instances (ie, detached instances with no master object */
+	while (unprocessed_instances != NULL) {
+		cid = unprocessed_instances->data;
+		ci = g_new0 (struct comp_instance, 1);
+		ci->comp = g_object_ref (cid->comp);
+		ci->start = cid->start;
+		ci->end = cid->end;
+		instances = g_slist_append (instances, ci);
+
+		unprocessed_instances = g_slist_remove (unprocessed_instances, cid);
+	}
+
+	return instances;
+}
+
+static void
+generate_instances (ECalClient *client, time_t start, time_t end, const gchar *uid,
+		    ECalRecurInstanceFn cb, gpointer cb_data)
+{
+	GSList *objects = NULL;
+	GSList *instances, *detached_instances = NULL;
+	GSList *l;
+	gchar *query;
+	gchar *iso_start, *iso_end;
+	ECalClientPrivate *priv;
+
+	priv = client->priv;
+
+	/* Generate objects */
+	if (uid && *uid) {
+		GError *error = NULL;
+		gint tries = 0;
+
+ try_again:
+		if (!e_cal_client_get_objects_for_uid_sync (client, uid, &objects, NULL, &error)) {
+			if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_BUSY) && tries >= 10) {
+				tries++;
+				g_usleep (500);
+				g_clear_error (&error);
+
+				goto try_again;
+			}
+
+			unwrap_dbus_error (error, &error);
+			g_message ("Failed to get recurrence objects for uid %s \n", error ? error->message : "Unknown error");
+			g_clear_error (&error);
+			return;
+		}
+	} else {
+		iso_start = isodate_from_time_t (start);
+		if (!iso_start)
+			return;
+
+		iso_end = isodate_from_time_t (end);
+		if (!iso_end) {
+			g_free (iso_start);
+			return;
+		}
+
+		query = g_strdup_printf ("(occur-in-time-range? (make-time \"%s\") (make-time \"%s\"))",
+					 iso_start, iso_end);
+		g_free (iso_start);
+		g_free (iso_end);
+		if (!e_cal_client_get_object_list_as_comps_sync (client, query, &objects, NULL, NULL)) {
+			g_free (query);
+			return;
+		}
+		g_free (query);
+	}
+
+	instances = NULL;
+
+	for (l = objects; l; l = l->next) {
+		ECalComponent *comp;
+		icaltimezone *default_zone;
+
+		if (priv->default_zone)
+			default_zone = priv->default_zone;
+		else
+			default_zone = icaltimezone_get_utc_timezone ();
+
+		comp = l->data;
+		if (e_cal_component_is_instance (comp)) {
+			struct comp_instance *ci;
+			ECalComponentDateTime dtstart, dtend;
+			icaltimezone *start_zone = NULL, *end_zone = NULL;
+
+			/* keep the detached instances apart */
+			ci = g_new0 (struct comp_instance, 1);
+			ci->comp = comp;
+
+			e_cal_component_get_dtstart (comp, &dtstart);
+			e_cal_component_get_dtend (comp, &dtend);
+
+			/* For DATE-TIME values with a TZID, we use
+			e_cal_resolve_tzid_cb to resolve the TZID.
+			For DATE values and DATE-TIME values without a
+			TZID (i.e. floating times) we use the default
+			timezone. */
+			if (dtstart.tzid && !dtstart.value->is_date) {
+				start_zone = e_cal_client_resolve_tzid_cb (dtstart.tzid, client);
+				if (!start_zone)
+					start_zone = default_zone;
+			} else {
+				start_zone = default_zone;
+			}
+
+			if (dtend.tzid && !dtend.value->is_date) {
+				end_zone = e_cal_client_resolve_tzid_cb (dtend.tzid, client);
+				if (!end_zone)
+					end_zone = default_zone;
+			} else {
+				end_zone = default_zone;
+			}
+
+			ci->start = icaltime_as_timet_with_zone (*dtstart.value, start_zone);
+
+			if (dtend.value)
+				ci->end = icaltime_as_timet_with_zone (*dtend.value, end_zone);
+			else if (icaltime_is_date (*dtstart.value))
+				ci->end = time_day_end (ci->start);
+			else
+				ci->end = ci->start;
+
+			e_cal_component_free_datetime (&dtstart);
+			e_cal_component_free_datetime (&dtend);
+
+			if (ci->start <= end && ci->end >= start) {
+				detached_instances = g_slist_prepend (detached_instances, ci);
+			} else {
+				/* it doesn't fit to our time range, thus skip it */
+				g_object_unref (G_OBJECT (ci->comp));
+				g_free (ci);
+			}
+		} else {
+			ECalComponentDateTime datetime;
+			icaltimezone *start_zone;
+			struct instances_info *instances_hold;
+
+			/* Get the start timezone */
+			e_cal_component_get_dtstart (comp, &datetime);
+			e_cal_client_get_timezone_sync (client, datetime.tzid, &start_zone, NULL, NULL);
+			e_cal_component_free_datetime (&datetime);
+
+			instances_hold = g_new0 (struct instances_info, 1);
+			instances_hold->instances = &instances;
+			instances_hold->start_zone = start_zone;
+
+			e_cal_recur_generate_instances (comp, start, end, add_instance, instances_hold,
+							e_cal_client_resolve_tzid_cb, client,
+							default_zone);
+
+			g_free (instances_hold);
+			g_object_unref (comp);
+		}
+	}
+
+	g_slist_free (objects);
+
+	/* Generate instances and spew them out */
+
+	instances = g_slist_sort (instances, compare_comp_instance);
+	instances = process_detached_instances (instances, detached_instances);
+
+	for (l = instances; l; l = l->next) {
+		struct comp_instance *ci;
+		gboolean result;
+
+		ci = l->data;
+
+		result = (* cb) (ci->comp, ci->start, ci->end, cb_data);
+
+		if (!result)
+			break;
+	}
+
+	/* Clean up */
+
+	for (l = instances; l; l = l->next) {
+		struct comp_instance *ci;
+
+		ci = l->data;
+		g_object_unref (G_OBJECT (ci->comp));
+		g_free (ci);
+	}
+
+	g_slist_free (instances);
+
+	for (l = detached_instances; l; l = l->next) {
+		struct comp_instance *ci;
+
+		ci = l->data;
+		g_object_unref (G_OBJECT (ci->comp));
+		g_free (ci);
+	}
+
+	g_slist_free (detached_instances);
+}
+
+/**
+ * e_cal_generate_instances:
+ * @client: A calendar client.
+ * @start: Start time for query.
+ * @end: End time for query.
+ * @cb: Callback for each generated instance.
+ * @cb_data: Closure data for the callback.
+ *
+ * Does a combination of #e_cal_client_get_object_list () and
+ * #e_cal_client_recur_generate_instances().
+ *
+ * The callback function should do a g_object_ref() of the calendar component
+ * it gets passed if it intends to keep it around, since it will be unref'ed
+ * as soon as the callback returns.
+ **/
+void
+e_cal_client_generate_instances (ECalClient *client, time_t start, time_t end, ECalRecurInstanceFn cb, gpointer cb_data)
+{
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CAL_CLIENT (client));
+	g_return_if_fail (e_client_is_opened (E_CLIENT (client)));
+
+	g_return_if_fail (start >= 0);
+	g_return_if_fail (end >= 0);
+	g_return_if_fail (cb != NULL);
+
+	generate_instances (client, start, end, NULL, cb, cb_data);
+}
+
+/**
+ * e_cal_client_generate_instances_for_object:
+ * @client: A calendar client.
+ * @icalcomp: Object to generate instances from.
+ * @start: Start time for query.
+ * @end: End time for query.
+ * @cb: Callback for each generated instance.
+ * @cb_data: Closure data for the callback.
+ *
+ * Does a combination of #e_cal_client_get_object_list () and
+ * #e_cal_client_recur_generate_instances(), like #e_cal_client_generate_instances(), but
+ * for a single object.
+ *
+ * The callback function should do a g_object_ref() of the calendar component
+ * it gets passed if it intends to keep it around, since it will be unref'ed
+ * as soon as the callback returns.
+ **/
+void
+e_cal_client_generate_instances_for_object (ECalClient *client, icalcomponent *icalcomp, time_t start, time_t end, ECalRecurInstanceFn cb, gpointer cb_data)
+{
+	ECalComponent *comp;
+	const gchar *uid;
+	gchar *rid;
+	gboolean result;
+	GSList *instances = NULL;
+	ECalComponentDateTime datetime;
+	icaltimezone *start_zone;
+	struct instances_info *instances_hold;
+	gboolean is_single_instance = FALSE;
+
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CAL_CLIENT (client));
+	g_return_if_fail (e_client_is_opened (E_CLIENT (client)));
+
+	g_return_if_fail (start >= 0);
+	g_return_if_fail (end >= 0);
+	g_return_if_fail (cb != NULL);
+
+	comp = e_cal_component_new ();
+	e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (icalcomp));
+
+	if (!e_cal_component_has_recurrences (comp))
+		is_single_instance = TRUE;
+
+	/* If the backend stores it as individual instances and does not
+	 * have a master object - do not expand */
+	if (is_single_instance || e_client_check_capability (E_CLIENT (client), CAL_STATIC_CAPABILITY_RECURRENCES_NO_MASTER)) {
+		/* return the same instance */
+		result = (* cb)  (comp, icaltime_as_timet_with_zone (icalcomponent_get_dtstart (icalcomp), client->priv->default_zone),
+				icaltime_as_timet_with_zone (icalcomponent_get_dtend (icalcomp), client->priv->default_zone), cb_data);
+		g_object_unref (comp);
+		return;
+	}
+
+	e_cal_component_get_uid (comp, &uid);
+	rid = e_cal_component_get_recurid_as_string (comp);
+
+	/* Get the start timezone */
+	e_cal_component_get_dtstart (comp, &datetime);
+	e_cal_client_get_timezone_sync (client, datetime.tzid, &start_zone, NULL, NULL);
+	e_cal_component_free_datetime (&datetime);
+
+	instances_hold = g_new0 (struct instances_info, 1);
+	instances_hold->instances = &instances;
+	instances_hold->start_zone = start_zone;
+
+	/* generate all instances in the given time range */
+	generate_instances (client, start, end, uid, add_instance, instances_hold);
+
+	instances = *(instances_hold->instances);
+	/* now only return back the instances for the given object */
+	result = TRUE;
+	while (instances != NULL) {
+		struct comp_instance *ci;
+		gchar *instance_rid = NULL;
+
+		ci = instances->data;
+
+		if (result) {
+			instance_rid = e_cal_component_get_recurid_as_string (ci->comp);
+
+			if (rid && *rid) {
+				if (instance_rid && *instance_rid && strcmp (rid, instance_rid) == 0)
+					result = (* cb) (ci->comp, ci->start, ci->end, cb_data);
+			} else
+				result = (* cb)  (ci->comp, ci->start, ci->end, cb_data);
+		}
+
+		/* remove instance from list */
+		instances = g_slist_remove (instances, ci);
+		g_object_unref (ci->comp);
+		g_free (ci);
+		g_free (instance_rid);
+	}
+
+	/* clean up */
+	g_object_unref (comp);
+	g_free (instances_hold);
+	g_free (rid);
+}
+
+typedef struct _ForeachTZIDCallbackData ForeachTZIDCallbackData;
+struct _ForeachTZIDCallbackData {
+	ECalClient *client;
+	GHashTable *timezone_hash;
+	gboolean success;
+};
+
+/* This adds the VTIMEZONE given by the TZID parameter to the GHashTable in
+   data. */
+static void
+foreach_tzid_callback (icalparameter *param, gpointer cbdata)
+{
+	ForeachTZIDCallbackData *data = cbdata;
+	const gchar *tzid;
+	icaltimezone *zone = NULL;
+	icalcomponent *vtimezone_comp;
+	gchar *vtimezone_as_string;
+
+	/* Get the TZID string from the parameter. */
+	tzid = icalparameter_get_tzid (param);
+	if (!tzid)
+		return;
+
+	/* Check if we've already added it to the GHashTable. */
+	if (g_hash_table_lookup (data->timezone_hash, tzid))
+		return;
+
+	if (!e_cal_client_get_timezone_sync (data->client, tzid, &zone, NULL, NULL) || !zone) {
+		data->success = FALSE;
+		return;
+	}
+
+	/* Convert it to a string and add it to the hash. */
+	vtimezone_comp = icaltimezone_get_component (zone);
+	if (!vtimezone_comp)
+		return;
+
+	vtimezone_as_string = icalcomponent_as_ical_string_r (vtimezone_comp);
+
+	g_hash_table_insert (data->timezone_hash, (gchar *) tzid, vtimezone_as_string);
+}
+
+/* This appends the value string to the GString given in data. */
+static void
+append_timezone_string (gpointer key, gpointer value, gpointer data)
+{
+	GString *vcal_string = data;
+
+	g_string_append (vcal_string, value);
+	g_free (value);
+}
+
+/* This simply frees the hash values. */
+static void
+free_timezone_string (gpointer key, gpointer value, gpointer data)
+{
+	g_free (value);
+}
+
+/**
+ * e_cal_client_get_component_as_string:
+ * @client: A calendar client.
+ * @icalcomp: A calendar component object.
+ *
+ * Gets a calendar component as an iCalendar string, with a toplevel
+ * VCALENDAR component and all VTIMEZONEs needed for the component.
+ *
+ * Returns: the component as a complete iCalendar string, or NULL on
+ * failure. The string should be freed with g_free().
+ *
+ * Since: 3.2
+ **/
+gchar *
+e_cal_client_get_component_as_string (ECalClient *client, icalcomponent *icalcomp)
+{
+	GHashTable *timezone_hash;
+	GString *vcal_string;
+	ForeachTZIDCallbackData cbdata;
+	gchar *obj_string;
+
+	g_return_val_if_fail (client != NULL, NULL);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (client), NULL);
+	g_return_val_if_fail (client->priv != NULL, NULL);
+	g_return_val_if_fail (icalcomp != NULL, NULL);
+
+	timezone_hash = g_hash_table_new (g_str_hash, g_str_equal);
+
+	/* Add any timezones needed to the hash. We use a hash since we only
+	   want to add each timezone once at most. */
+	cbdata.client = client;
+	cbdata.timezone_hash = timezone_hash;
+	cbdata.success = TRUE;
+	icalcomponent_foreach_tzid (icalcomp, foreach_tzid_callback, &cbdata);
+	if (!cbdata.success) {
+		g_hash_table_foreach (timezone_hash, free_timezone_string, NULL);
+		return NULL;
+	}
+
+	/* Create the start of a VCALENDAR, to add the VTIMEZONES to,
+	   and remember its length so we know if any VTIMEZONEs get added. */
+	vcal_string = g_string_new (NULL);
+	g_string_append (vcal_string,
+			 "BEGIN:VCALENDAR\n"
+			 "PRODID:-//Ximian//NONSGML Evolution Calendar//EN\n"
+			 "VERSION:2.0\n"
+			 "METHOD:PUBLISH\n");
+
+	/* Now concatenate all the timezone strings. This also frees the
+	   timezone strings as it goes. */
+	g_hash_table_foreach (timezone_hash, append_timezone_string, vcal_string);
+
+	/* Get the string for the VEVENT/VTODO. */
+	obj_string = icalcomponent_as_ical_string_r (icalcomp);
+
+	/* If there were any timezones to send, create a complete VCALENDAR,
+	   else just send the VEVENT/VTODO string. */
+	g_string_append (vcal_string, obj_string);
+	g_string_append (vcal_string, "END:VCALENDAR\n");
+	g_free (obj_string);
+
+	obj_string = g_string_free (vcal_string, FALSE);
+
+	g_hash_table_destroy (timezone_hash);
+
+	return obj_string;
+}
+
+static void
+cal_client_get_backend_property (EClient *client, const gchar *prop_name, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_client_proxy_call_string (client, prop_name, cancellable, callback, user_data, cal_client_get_backend_property,
+			e_gdbus_cal_call_get_backend_property,
+			NULL, NULL, e_gdbus_cal_call_get_backend_property_finish, NULL, NULL);
+}
+
+static gboolean
+cal_client_get_backend_property_finish (EClient *client, GAsyncResult *result, gchar **prop_value, GError **error)
+{
+	return e_client_proxy_call_finish_string (client, result, prop_value, error, cal_client_get_backend_property);
+}
+
+static gboolean
+cal_client_get_backend_property_sync (EClient *client, const gchar *prop_name, gchar **prop_value, GCancellable *cancellable, GError **error)
+{
+	ECalClient *cal_client;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+
+	cal_client = E_CAL_CLIENT (client);
+	g_return_val_if_fail (cal_client != NULL, FALSE);
+	g_return_val_if_fail (cal_client->priv != NULL, FALSE);
+
+	if (!cal_client->priv->gdbus_cal) {
+		set_proxy_gone_error (error);
+		return FALSE;
+	}
+
+	return e_client_proxy_call_sync_string__string (client, prop_name, prop_value, cancellable, error, e_gdbus_cal_call_get_backend_property_sync);
+}
+
+static void
+cal_client_set_backend_property (EClient *client, const gchar *prop_name, const gchar *prop_value, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	gchar **prop_name_value;
+
+	prop_name_value = e_gdbus_cal_encode_set_backend_property (prop_name, prop_value);
+
+	e_client_proxy_call_strv (client, (const gchar * const *) prop_name_value, cancellable, callback, user_data, cal_client_set_backend_property,
+			e_gdbus_cal_call_set_backend_property,
+			e_gdbus_cal_call_set_backend_property_finish, NULL, NULL, NULL, NULL);
+
+	g_strfreev (prop_name_value);
+}
+
+static gboolean
+cal_client_set_backend_property_finish (EClient *client, GAsyncResult *result, GError **error)
+{
+	return e_client_proxy_call_finish_void (client, result, error, cal_client_set_backend_property);
+}
+
+static gboolean
+cal_client_set_backend_property_sync (EClient *client, const gchar *prop_name, const gchar *prop_value, GCancellable *cancellable, GError **error)
+{
+	ECalClient *cal_client;
+	gboolean res;
+	gchar **prop_name_value;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+
+	cal_client = E_CAL_CLIENT (client);
+	g_return_val_if_fail (cal_client != NULL, FALSE);
+	g_return_val_if_fail (cal_client->priv != NULL, FALSE);
+
+	if (!cal_client->priv->gdbus_cal) {
+		set_proxy_gone_error (error);
+		return FALSE;
+	}
+
+	prop_name_value = e_gdbus_cal_encode_set_backend_property (prop_name, prop_value);
+	res = e_client_proxy_call_sync_strv__void (client, (const gchar * const *) prop_name_value, cancellable, error, e_gdbus_cal_call_set_backend_property_sync);
+	g_strfreev (prop_name_value);
+
+	return res;
+}
+
+static void
+cal_client_open (EClient *client, gboolean only_if_exists, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_client_proxy_call_boolean (client, only_if_exists, cancellable, callback, user_data, cal_client_open,
+			e_gdbus_cal_call_open,
+			e_gdbus_cal_call_open_finish, NULL, NULL, NULL, NULL);
+}
+
+static gboolean
+cal_client_open_finish (EClient *client, GAsyncResult *result, GError **error)
+{
+	return e_client_proxy_call_finish_void (client, result, error, cal_client_open);
+}
+
+static gboolean
+cal_client_open_sync (EClient *client, gboolean only_if_exists, GCancellable *cancellable, GError **error)
+{
+	ECalClient *cal_client;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+
+	cal_client = E_CAL_CLIENT (client);
+	g_return_val_if_fail (cal_client != NULL, FALSE);
+	g_return_val_if_fail (cal_client->priv != NULL, FALSE);
+
+	if (!cal_client->priv->gdbus_cal) {
+		set_proxy_gone_error (error);
+		return FALSE;
+	}
+
+	return e_client_proxy_call_sync_boolean__void (client, only_if_exists, cancellable, error, e_gdbus_cal_call_open_sync);
+}
+
+static void
+cal_client_remove (EClient *client, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_client_proxy_call_void (client, cancellable, callback, user_data, cal_client_remove,
+			e_gdbus_cal_call_remove,
+			e_gdbus_cal_call_remove_finish, NULL, NULL, NULL, NULL);
+}
+
+static gboolean
+cal_client_remove_finish (EClient *client, GAsyncResult *result, GError **error)
+{
+	return e_client_proxy_call_finish_void (client, result, error, cal_client_remove);
+}
+
+static gboolean
+cal_client_remove_sync (EClient *client, GCancellable *cancellable, GError **error)
+{
+	ECalClient *cal_client;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+
+	cal_client = E_CAL_CLIENT (client);
+	g_return_val_if_fail (cal_client != NULL, FALSE);
+	g_return_val_if_fail (cal_client->priv != NULL, FALSE);
+
+	if (!cal_client->priv->gdbus_cal) {
+		set_proxy_gone_error (error);
+		return FALSE;
+	}
+
+	return e_client_proxy_call_sync_void__void (client, cancellable, error, e_gdbus_cal_call_remove_sync);
+}
+
+static void
+cal_client_refresh (EClient *client, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_client_proxy_call_void (client, cancellable, callback, user_data, cal_client_refresh,
+			e_gdbus_cal_call_refresh,
+			e_gdbus_cal_call_refresh_finish, NULL, NULL, NULL, NULL);
+}
+
+static gboolean
+cal_client_refresh_finish (EClient *client, GAsyncResult *result, GError **error)
+{
+	return e_client_proxy_call_finish_void (client, result, error, cal_client_refresh);
+}
+
+static gboolean
+cal_client_refresh_sync (EClient *client, GCancellable *cancellable, GError **error)
+{
+	ECalClient *cal_client;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+
+	cal_client = E_CAL_CLIENT (client);
+	g_return_val_if_fail (cal_client != NULL, FALSE);
+	g_return_val_if_fail (cal_client->priv != NULL, FALSE);
+
+	if (!cal_client->priv->gdbus_cal) {
+		set_proxy_gone_error (error);
+		return FALSE;
+	}
+
+	return e_client_proxy_call_sync_void__void (client, cancellable, error, e_gdbus_cal_call_refresh_sync);
+}
+
+static gboolean
+complete_string_exchange (gboolean res, gchar *out_string, gchar **result, GError **error)
+{
+	g_return_val_if_fail (result != NULL, FALSE);
+
+	if (res && out_string) {
+		if (*out_string) {
+			*result = out_string;
+		} else {
+			/* empty string is returned as NULL */
+			*result = NULL;
+			g_free (out_string);
+		}
+	} else {
+		*result = NULL;
+		g_free (out_string);
+		res = FALSE;
+
+		if (error && !*error)
+			g_set_error_literal (error, E_CLIENT_ERROR, E_CLIENT_ERROR_INVALID_ARG, e_client_error_to_string (E_CLIENT_ERROR_INVALID_ARG));
+	}
+
+	return res;
+}
+
+/**
+ * e_cal_client_get_default_object:
+ * @client: an #ECalClient
+ * @cancellable: a #GCancellable; can be %NULL
+ * @callback: callback to call when a result is ready
+ * @user_data: user data for the @callback
+ *
+ * Retrives an #icalcomponent from the backend that contains the default
+ * values for properties needed. The call is finished
+ * by e_cal_client_get_default_object_finish() from the @callback.
+ *
+ * Since: 3.2
+ **/
+void
+e_cal_client_get_default_object (ECalClient *client, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_client_proxy_call_string (E_CLIENT (client), CAL_BACKEND_PROPERTY_DEFAULT_OBJECT, cancellable, callback, user_data, e_cal_client_get_default_object,
+			e_gdbus_cal_call_get_backend_property,
+			NULL, NULL, e_gdbus_cal_call_get_backend_property_finish, NULL, NULL);
+}
+
+static gboolean
+complete_get_object (gboolean res, gchar *out_string, icalcomponent **icalcomp, GError **error)
+{
+	g_return_val_if_fail (icalcomp != NULL, FALSE);
+
+	if (res && out_string) {
+		*icalcomp = icalparser_parse_string (out_string);
+		if (!*icalcomp) {
+			g_set_error_literal (error, E_CAL_CLIENT_ERROR, E_CAL_CLIENT_ERROR_INVALID_OBJECT, e_cal_client_error_to_string (E_CAL_CLIENT_ERROR_INVALID_OBJECT));
+			res = FALSE;
+		}
+	} else {
+		*icalcomp = NULL;
+		res = FALSE;
+	}
+
+	g_free (out_string);
+
+	return res;
+}
+
+/**
+ * e_cal_client_get_default_object_finish:
+ * @client: an #ECalClient
+ * @result: a #GAsyncResult
+ * @icalcomp: (out): Return value for the default calendar object.
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Finishes previous call of e_cal_client_get_default_object() and
+ * sets @icalcomp to an #icalcomponent from the backend that contains
+ * the default values for properties needed. This @icalcomp should be
+ * freed with icalcomponent_free().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_get_default_object_finish (ECalClient *client, GAsyncResult *result, icalcomponent **icalcomp, GError **error)
+{
+	gboolean res;
+	gchar *out_string = NULL;
+
+	g_return_val_if_fail (icalcomp != NULL, FALSE);
+
+	res = e_client_proxy_call_finish_string (E_CLIENT (client), result, &out_string, error, e_cal_client_get_default_object);
+
+	return complete_get_object (res, out_string, icalcomp, error);
+}
+
+/**
+ * e_cal_client_get_default_object_sync:
+ * @client: an #ECalClient
+ * @icalcomp: (out): Return value for the default calendar object.
+ * @cancellable: a #GCancellable; can be %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Retrives an #icalcomponent from the backend that contains the default
+ * values for properties needed. This @icalcomp should be freed with
+ * icalcomponent_free().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_get_default_object_sync (ECalClient *client, icalcomponent **icalcomp, GCancellable *cancellable, GError **error)
+{
+	gboolean res;
+	gchar *out_string = NULL;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+	g_return_val_if_fail (icalcomp != NULL, FALSE);
+
+	if (!client->priv->gdbus_cal) {
+		set_proxy_gone_error (error);
+		return FALSE;
+	}
+
+	res = e_client_proxy_call_sync_string__string (E_CLIENT (client), CAL_BACKEND_PROPERTY_DEFAULT_OBJECT, &out_string, cancellable, error, e_gdbus_cal_call_get_backend_property_sync);
+
+	return complete_get_object (res, out_string, icalcomp, error);
+}
+
+/**
+ * e_cal_client_get_object:
+ * @client: an #ECalClient
+ * @uid: Unique identifier for a calendar component.
+ * @rid: Recurrence identifier.
+ * @cancellable: a #GCancellable; can be %NULL
+ * @callback: callback to call when a result is ready
+ * @user_data: user data for the @callback
+ *
+ * Queries a calendar for a calendar component object based on its unique
+ * identifier. The call is finished by e_cal_client_get_object_finish()
+ * from the @callback.
+ *
+ * Since: 3.2
+ **/
+void
+e_cal_client_get_object (ECalClient *client, const gchar *uid, const gchar *rid, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	gchar **strv;
+
+	g_return_if_fail (uid != NULL);
+
+	strv = e_gdbus_cal_encode_get_object (uid, rid);
+
+	e_client_proxy_call_strv (E_CLIENT (client), (const gchar * const *) strv, cancellable, callback, user_data, e_cal_client_get_object,
+			e_gdbus_cal_call_get_object,
+			NULL, NULL, e_gdbus_cal_call_get_object_finish, NULL, NULL);
+
+	g_strfreev (strv);
+}
+
+/**
+ * e_cal_client_get_object_finish:
+ * @client: an #ECalClient
+ * @result: a #GAsyncResult
+ * @icalcomp: (out): Return value for the calendar component object.
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Finishes previous call of e_cal_client_get_object() and
+ * sets @icalcomp to queried component.
+ * This component should be freed with icalcomponent_free().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_get_object_finish (ECalClient *client, GAsyncResult *result, icalcomponent **icalcomp, GError **error)
+{
+	gboolean res;
+	gchar *out_string = NULL;
+
+	g_return_val_if_fail (icalcomp != NULL, FALSE);
+
+	res = e_client_proxy_call_finish_string (E_CLIENT (client), result, &out_string, error, e_cal_client_get_object);
+
+	return complete_get_object (res, out_string, icalcomp, error);;
+}
+
+/**
+ * e_cal_client_get_object_sync:
+ * @client: an #ECalClient
+ * @uid: Unique identifier for a calendar component.
+ * @rid: Recurrence identifier.
+ * @icalcomp: (out): Return value for the calendar component object.
+ * @cancellable: a #GCancellable; can be %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Queries a calendar for a calendar component object based
+ * on its unique identifier.
+ * This component should be freed with icalcomponent_free().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_get_object_sync (ECalClient *client, const gchar *uid, const gchar *rid, icalcomponent **icalcomp, GCancellable *cancellable, GError **error)
+{
+	gboolean res;
+	gchar *out_string = NULL, **strv;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+	g_return_val_if_fail (uid != NULL, FALSE);
+	g_return_val_if_fail (icalcomp != NULL, FALSE);
+
+	if (!client->priv->gdbus_cal) {
+		set_proxy_gone_error (error);
+		return FALSE;
+	}
+
+	strv = e_gdbus_cal_encode_get_object (uid, rid);
+	res = e_client_proxy_call_sync_strv__string (E_CLIENT (client), (const gchar * const *) strv, &out_string, cancellable, error, e_gdbus_cal_call_get_object_sync);
+	g_strfreev (strv);
+
+	return complete_get_object (res, out_string, icalcomp, error);
+}
+
+/**
+ * e_cal_client_get_objects_for_uid:
+ * @client: an #ECalClient
+ * @uid: Unique identifier for a calendar component
+ * @cancellable: a #GCancellable; can be %NULL
+ * @callback: callback to call when a result is ready
+ * @user_data: user data for the @callback
+ *
+ * Queries a calendar for all calendar components with the given unique
+ * ID. This will return any recurring event and all its detached recurrences.
+ * For non-recurring events, it will just return the object with that ID.
+ * The call is finished by e_cal_client_get_objects_for_uid_finish() from
+ * the @callback.
+ *
+ * Since: 3.2
+ **/
+void
+e_cal_client_get_objects_for_uid (ECalClient *client, const gchar *uid, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	gchar **strv;
+
+	g_return_if_fail (uid != NULL);
+
+	strv = e_gdbus_cal_encode_get_object (uid, "");
+
+	e_client_proxy_call_strv (E_CLIENT (client), (const gchar * const *) strv, cancellable, callback, user_data, e_cal_client_get_objects_for_uid,
+			e_gdbus_cal_call_get_object,
+			NULL, NULL, e_gdbus_cal_call_get_object_finish, NULL, NULL);
+
+	g_strfreev (strv);
+}
+
+static gboolean
+complete_get_objects_for_uid (ECalClientSourceType source_type, gboolean res, gchar *out_string, GSList **ecalcomps, GError **error)
+{
+	icalcomponent *icalcomp = NULL;
+	icalcomponent_kind kind;
+	ECalComponent *comp;
+
+	res = complete_get_object (res, out_string, &icalcomp, error);
+	if (!res || !icalcomp)
+		return FALSE;
+
+	kind = icalcomponent_isa (icalcomp);
+	if ((kind == ICAL_VEVENT_COMPONENT && source_type == E_CAL_CLIENT_SOURCE_TYPE_EVENTS) ||
+	    (kind == ICAL_VTODO_COMPONENT && source_type == E_CAL_CLIENT_SOURCE_TYPE_TASKS) ||
+	    (kind == ICAL_VJOURNAL_COMPONENT && source_type == E_CAL_CLIENT_SOURCE_TYPE_MEMOS)) {
+		comp = e_cal_component_new ();
+		e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (icalcomp));
+		*ecalcomps = g_slist_append (NULL, comp);
+	} else if (kind == ICAL_VCALENDAR_COMPONENT) {
+		icalcomponent *subcomp;
+		icalcomponent_kind kind_to_find;
+
+		switch (source_type) {
+		case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+			kind_to_find = ICAL_VTODO_COMPONENT;
+			break;
+		case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+			kind_to_find = ICAL_VJOURNAL_COMPONENT;
+			break;
+		case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+		default:
+			kind_to_find = ICAL_VEVENT_COMPONENT;
+			break;
+		}
+
+		*ecalcomps = NULL;
+		subcomp = icalcomponent_get_first_component (icalcomp, kind_to_find);
+		while (subcomp) {
+			comp = e_cal_component_new ();
+			e_cal_component_set_icalcomponent (comp, icalcomponent_new_clone (subcomp));
+			*ecalcomps = g_slist_prepend (*ecalcomps, comp);
+			subcomp = icalcomponent_get_next_component (icalcomp, kind_to_find);
+		}
+
+		*ecalcomps = g_slist_reverse (*ecalcomps);
+	}
+
+	icalcomponent_free (icalcomp);
+
+	return TRUE;
+}
+
+/**
+ * e_cal_client_get_objects_for_uid_finish:
+ * @client: an #ECalClient
+ * @result: a #GAsyncResult
+ * @ecalcomps: (out): Return value for the list of objects obtained from the backend
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Finishes previous call of e_cal_client_get_objects_for_uid() and
+ * sets @ecalcomps to a list of #ECalComponent-s corresponding to
+ * found components for a given uid of the same type as this client.
+ * This list should be freed with e_cal_client_free_ecalcomp_slist().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_get_objects_for_uid_finish (ECalClient *client, GAsyncResult *result, GSList **ecalcomps, GError **error)
+{
+	gboolean res;
+	gchar *out_string = NULL;
+
+	g_return_val_if_fail (ecalcomps != NULL, FALSE);
+
+	res = e_client_proxy_call_finish_string (E_CLIENT (client), result, &out_string, error, e_cal_client_get_objects_for_uid);
+
+	return complete_get_objects_for_uid (e_cal_client_get_source_type (client), res, out_string, ecalcomps, error);
+}
+
+/**
+ * e_cal_client_get_objects_for_uid_sync:
+ * @client: an #ECalClient
+ * @uid: Unique identifier for a calendar component
+ * @ecalcomps: (out): Return value for the list of objects obtained from the backend
+ * @cancellable: a #GCancellable; can be %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Queries a calendar for all calendar components with the given unique
+ * ID. This will return any recurring event and all its detached recurrences.
+ * For non-recurring events, it will just return the object with that ID.
+ * This list should be freed with e_cal_client_free_ecalcomp_slist().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_get_objects_for_uid_sync (ECalClient *client, const gchar *uid, GSList **ecalcomps, GCancellable *cancellable, GError **error)
+{
+	gboolean res;
+	gchar *out_string = NULL, **strv = NULL;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+	g_return_val_if_fail (uid != NULL, FALSE);
+	g_return_val_if_fail (ecalcomps != NULL, FALSE);
+
+	if (!client->priv->gdbus_cal) {
+		set_proxy_gone_error (error);
+		return FALSE;
+	}
+
+	strv = e_gdbus_cal_encode_get_object (uid, "");
+	res = e_client_proxy_call_sync_strv__string (E_CLIENT (client), (const gchar * const *) strv, &out_string, cancellable, error, e_gdbus_cal_call_get_object_sync);
+	g_strfreev (strv);
+
+	return complete_get_objects_for_uid (e_cal_client_get_source_type (client), res, out_string, ecalcomps, error);
+}
+
+/**
+ * e_cal_client_get_object_list:
+ * @client: an #ECalClient
+ * @sexp: an S-expression representing the query
+ * @cancellable: a #GCancellable; can be %NULL
+ * @callback: callback to call when a result is ready
+ * @user_data: user data for the @callback
+ *
+ * Gets a list of objects from the calendar that match the query specified
+ * by the @sexp argument, returning matching objects as a list of #icalcomponent-s.
+ * The call is finished by e_cal_client_get_object_list_finish() from
+ * the @callback.
+ *
+ * Since: 3.2
+ **/
+void
+e_cal_client_get_object_list (ECalClient *client, const gchar *sexp, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	gchar *gdbus_sexp = NULL;
+
+	g_return_if_fail (sexp != NULL);
+
+	e_client_proxy_call_string (E_CLIENT (client), e_util_ensure_gdbus_string (sexp, &gdbus_sexp), cancellable, callback, user_data, e_cal_client_get_object_list,
+			e_gdbus_cal_call_get_object_list,
+			NULL, NULL, NULL, e_gdbus_cal_call_get_object_list_finish, NULL);
+
+	g_free (gdbus_sexp);
+}
+
+static gboolean
+complete_get_object_list (gboolean res, gchar **out_strv, GSList **icalcomps, GError **error)
+{
+	g_return_val_if_fail (icalcomps != NULL, FALSE);
+
+	*icalcomps = NULL;
+
+	if (res && out_strv) {
+		gint ii;
+		icalcomponent *icalcomp;
+
+		for (ii = 0; out_strv[ii]; ii++) {
+			icalcomp = icalcomponent_new_from_string (out_strv[ii]);
+
+			if (!icalcomp)
+				continue;
+
+			*icalcomps = g_slist_prepend (*icalcomps, icalcomp);
+		}
+
+		*icalcomps = g_slist_reverse (*icalcomps);
+	} else {
+		res = FALSE;
+	}
+
+	g_strfreev (out_strv);
+
+	return res;
+}
+
+/**
+ * e_cal_client_get_object_list_finish:
+ * @client: an #ECalClient
+ * @result: a #GAsyncResult
+ * @icalcomps: (out): list of matching #icalcomponent-s
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Finishes previous call of e_cal_client_get_object_list() and
+ * sets @icalcomps to a matching list of #icalcomponent-s.
+ * This list should be freed with #e_cal_client_free_icalcomp_slist().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_get_object_list_finish (ECalClient *client, GAsyncResult *result, GSList **icalcomps, GError **error)
+{
+	gboolean res;
+	gchar **out_strv = NULL;
+
+	g_return_val_if_fail (icalcomps != NULL, FALSE);
+
+	res = e_client_proxy_call_finish_strv (E_CLIENT (client), result, &out_strv, error, e_cal_client_get_object_list);
+
+	return complete_get_object_list (res, out_strv, icalcomps, error);
+}
+
+/**
+ * e_cal_client_get_object_list_sync:
+ * @client: an #ECalClient
+ * @sexp: an S-expression representing the query
+ * @icalcomps: (out): list of matching #icalcomponent-s
+ * @cancellable: a #GCancellable; can be %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Gets a list of objects from the calendar that match the query specified
+ * by the @sexp argument. The objects will be returned in the @icalcomps
+ * argument, which is a list of #icalcomponent.
+ * This list should be freed with #e_cal_client_free_icalcomp_slist().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_get_object_list_sync (ECalClient *client, const gchar *sexp, GSList **icalcomps, GCancellable *cancellable, GError **error)
+{
+	gboolean res;
+	gchar **out_strv = NULL, *gdbus_sexp = NULL;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+	g_return_val_if_fail (sexp != NULL, FALSE);
+	g_return_val_if_fail (icalcomps != NULL, FALSE);
+
+	if (!client->priv->gdbus_cal) {
+		set_proxy_gone_error (error);
+		return FALSE;
+	}
+
+	res = e_client_proxy_call_sync_string__strv (E_CLIENT (client), e_util_ensure_gdbus_string (sexp, &gdbus_sexp), &out_strv, cancellable, error, e_gdbus_cal_call_get_object_list_sync);
+	g_free (gdbus_sexp);
+
+	return complete_get_object_list (res, out_strv, icalcomps, error);
+}
+
+/**
+ * e_cal_client_get_object_list_as_comps:
+ * @client: an #ECalClient
+ * @sexp: an S-expression representing the query
+ * @cancellable: a #GCancellable; can be %NULL
+ * @callback: callback to call when a result is ready
+ * @user_data: user data for the @callback
+ *
+ * Gets a list of objects from the calendar that match the query specified
+ * by the @sexp argument, returning matching objects as a list of #ECalComponent-s.
+ * The call is finished by e_cal_client_get_object_list_as_comps_finish() from
+ * the @callback.
+ *
+ * Since: 3.2
+ **/
+void
+e_cal_client_get_object_list_as_comps (ECalClient *client, const gchar *sexp, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	gchar *gdbus_sexp = NULL;
+
+	g_return_if_fail (sexp != NULL);
+
+	e_client_proxy_call_string (E_CLIENT (client), e_util_ensure_gdbus_string (sexp, &gdbus_sexp), cancellable, callback, user_data, e_cal_client_get_object_list_as_comps,
+			e_gdbus_cal_call_get_object_list,
+			NULL, NULL, NULL, e_gdbus_cal_call_get_object_list_finish, NULL);
+
+	g_free (gdbus_sexp);
+}
+
+static gboolean
+complete_get_object_list_as_comps (gboolean res, gchar **out_strv, GSList **ecalcomps, GError **error)
+{
+	GSList *icalcomps = NULL;
+
+	g_return_val_if_fail (ecalcomps != NULL, FALSE);
+
+	*ecalcomps = NULL;
+
+	res = complete_get_object_list (res, out_strv, &icalcomps, error);
+
+	if (res) {
+		GSList *iter;
+
+		for (iter = icalcomps; iter; iter = iter->next) {
+			ECalComponent *comp;
+
+			comp = e_cal_component_new ();
+			/* takes ownership of the icalcomp, thus free only the list at the end */
+			if (e_cal_component_set_icalcomponent (comp, iter->data))
+				*ecalcomps = g_slist_prepend (*ecalcomps, comp);
+			else
+				icalcomponent_free (iter->data);
+		}
+
+		g_slist_free (icalcomps);
+
+		*ecalcomps = g_slist_reverse (*ecalcomps);
+	} else {
+		e_cal_client_free_icalcomp_slist (icalcomps);
+	}
+
+	return res;
+}
+
+/**
+ * e_cal_client_get_object_list_as_comps_finish:
+ * @client: an #ECalClient
+ * @result: a #GAsyncResult
+ * @ecalcomps: (out): list of matching #ECalComponent-s
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Finishes previous call of e_cal_client_get_object_list_as_comps() and
+ * sets @ecalcomps to a matching list of #ECalComponent-s.
+ * This list should be freed with #e_cal_client_free_ecalcomp_slist().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_get_object_list_as_comps_finish (ECalClient *client, GAsyncResult *result, GSList **ecalcomps, GError **error)
+{
+	gboolean res;
+	gchar **out_strv = NULL;
+
+	g_return_val_if_fail (ecalcomps != NULL, FALSE);
+
+	res = e_client_proxy_call_finish_strv (E_CLIENT (client), result, &out_strv, error, e_cal_client_get_object_list_as_comps);
+
+	return complete_get_object_list_as_comps (res, out_strv, ecalcomps, error);
+}
+
+/**
+ * e_cal_client_get_object_list_as_comps_sync:
+ * @client: an #ECalClient
+ * @sexp: an S-expression representing the query
+ * @ecalcomps: (out): list of matching #ECalComponent-s
+ * @cancellable: a #GCancellable; can be %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Gets a list of objects from the calendar that match the query specified
+ * by the @sexp argument. The objects will be returned in the @ecalcomps
+ * argument, which is a list of #ECalComponent.
+ * This list should be freed with #e_cal_client_free_ecalcomp_slist().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_get_object_list_as_comps_sync (ECalClient *client, const gchar *sexp, GSList **ecalcomps, GCancellable *cancellable, GError **error)
+{
+	gboolean res;
+	gchar **out_strv = NULL, *gdbus_sexp = NULL;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+	g_return_val_if_fail (sexp != NULL, FALSE);
+	g_return_val_if_fail (ecalcomps != NULL, FALSE);
+
+	if (!client->priv->gdbus_cal) {
+		set_proxy_gone_error (error);
+		return FALSE;
+	}
+
+	res = e_client_proxy_call_sync_string__strv (E_CLIENT (client), e_util_ensure_gdbus_string (sexp, &gdbus_sexp), &out_strv, cancellable, error, e_gdbus_cal_call_get_object_list_sync);
+	g_free (gdbus_sexp);
+
+	return complete_get_object_list_as_comps (res, out_strv, ecalcomps, error);
+}
+
+/**
+ * e_cal_client_get_free_busy:
+ * @client: an #ECalClient
+ * @start: Start time for query
+ * @end: End time for query
+ * @users: List of users to retrieve free/busy information for
+ * @cancellable: a #GCancellable; can be %NULL
+ * @callback: callback to call when a result is ready
+ * @user_data: user data for the @callback
+ *
+ * Begins retrieval of free/busy information from the calendar server
+ * as a list of #ECalComponent-s. Connect to "free-busy-data" signal
+ * to receive chunks of free/busy components.
+ * The call is finished by e_cal_client_get_free_busy_finish() from
+ * the @callback.
+ *
+ * Since: 3.2
+ **/
+void
+e_cal_client_get_free_busy (ECalClient *client, time_t start, time_t end, const GSList *users, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	gchar **strv;
+
+	g_return_if_fail (start > 0);
+	g_return_if_fail (end > 0);
+	g_return_if_fail (users != NULL);
+
+	strv = e_gdbus_cal_encode_get_free_busy (start, end, users);
+
+	e_client_proxy_call_strv (E_CLIENT (client), (const gchar * const *) strv, cancellable, callback, user_data, e_cal_client_get_free_busy,
+			e_gdbus_cal_call_get_free_busy,
+			e_gdbus_cal_call_get_free_busy_finish, NULL, NULL, NULL, NULL);
+
+	g_strfreev (strv);
+}
+
+/**
+ * e_cal_client_get_free_busy_finish:
+ * @client: an #ECalClient
+ * @result: a #GAsyncResult
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Finishes previous call of e_cal_client_get_free_busy().
+ * All VFREEBUSY #ECalComponent-s were received by "free-busy-data" signal.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_get_free_busy_finish (ECalClient *client, GAsyncResult *result, GError **error)
+{
+	return e_client_proxy_call_finish_void (E_CLIENT (client), result, error, e_cal_client_get_free_busy);
+}
+
+/**
+ * e_cal_client_get_free_busy_sync:
+ * @client: an #ECalClient
+ * @start: Start time for query
+ * @end: End time for query
+ * @users: List of users to retrieve free/busy information for
+ * @cancellable: a #GCancellable; can be %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Gets free/busy information from the calendar server.
+ * All VFREEBUSY #ECalComponent-s were received by "free-busy-data" signal.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_get_free_busy_sync (ECalClient *client, time_t start, time_t end, const GSList *users, GCancellable *cancellable, GError **error)
+{
+	gboolean res;
+	gchar **strv;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+	g_return_val_if_fail (users != NULL, FALSE);
+
+	if (!client->priv->gdbus_cal) {
+		set_proxy_gone_error (error);
+		return FALSE;
+	}
+
+	strv = e_gdbus_cal_encode_get_free_busy (start, end, users);
+	res = e_client_proxy_call_sync_strv__void (E_CLIENT (client), (const gchar * const *) strv, cancellable, error, e_gdbus_cal_call_get_free_busy_sync);
+	g_strfreev (strv);
+
+	return res;
+}
+
+/**
+ * e_cal_client_create_object:
+ * @client: an #ECalClient
+ * @icalcomp: The component to create
+ * @cancellable: a #GCancellable; can be %NULL
+ * @callback: callback to call when a result is ready
+ * @user_data: user data for the @callback
+ *
+ * Requests the calendar backend to create the object specified by the @icalcomp
+ * argument. Some backends would assign a specific UID to the newly created object,
+ * but this function does not modify the original @icalcomp if its UID changes.
+ * The call is finished by e_cal_client_create_object_finish() from
+ * the @callback.
+ *
+ * Since: 3.2
+ **/
+void
+e_cal_client_create_object (ECalClient *client, /* const */ icalcomponent *icalcomp, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	gchar *comp_str, *gdbus_comp = NULL;
+
+	g_return_if_fail (icalcomp != NULL);
+
+	comp_str = icalcomponent_as_ical_string_r (icalcomp);
+
+	e_client_proxy_call_string (E_CLIENT (client), e_util_ensure_gdbus_string (comp_str, &gdbus_comp), cancellable, callback, user_data, e_cal_client_create_object,
+			e_gdbus_cal_call_create_object,
+			NULL, NULL, e_gdbus_cal_call_create_object_finish, NULL, NULL);
+
+	g_free (comp_str);
+	g_free (gdbus_comp);
+}
+
+/**
+ * e_cal_client_create_object_finish:
+ * @client: an #ECalClient
+ * @result: a #GAsyncResult
+ * @uid: (out): Return value for the UID assigned to the new component by the calendar backend
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Finishes previous call of e_cal_client_create_object() and
+ * sets @uid to newly assigned UID for the created object.
+ * This @uid should be freed with g_free().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_create_object_finish (ECalClient *client, GAsyncResult *result, gchar **uid, GError **error)
+{
+	gboolean res;
+	gchar *out_string = NULL;
+
+	g_return_val_if_fail (uid != NULL, FALSE);
+
+	res = e_client_proxy_call_finish_string (E_CLIENT (client), result, &out_string, error, e_cal_client_create_object);
+
+	return complete_string_exchange (res, out_string, uid, error);
+}
+
+/**
+ * e_cal_client_create_object_sync:
+ * @client: an #ECalClient
+ * @icalcomp: The component to create
+ * @uid: (out): Return value for the UID assigned to the new component by the calendar backend
+ * @cancellable: a #GCancellable; can be %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Requests the calendar backend to create the object specified by the @icalcomp
+ * argument. Some backends would assign a specific UID to the newly created object,
+ * in those cases that UID would be returned in the @uid argument. This function
+ * does not modify the original @icalcomp if its UID changes.
+ * Returned @uid should be freed with g_free().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_create_object_sync (ECalClient *client, /* const */ icalcomponent *icalcomp, gchar **uid, GCancellable *cancellable, GError **error)
+{
+	gboolean res;
+	gchar *comp_str, *gdbus_comp = NULL;
+	gchar *out_string = NULL;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+	g_return_val_if_fail (icalcomp != NULL, FALSE);
+	g_return_val_if_fail (uid != NULL, FALSE);
+
+	if (!client->priv->gdbus_cal) {
+		set_proxy_gone_error (error);
+		return FALSE;
+	}
+
+	comp_str = icalcomponent_as_ical_string_r (icalcomp);
+
+	res = e_client_proxy_call_sync_string__string (E_CLIENT (client), e_util_ensure_gdbus_string (comp_str, &gdbus_comp), &out_string, cancellable, error, e_gdbus_cal_call_create_object_sync);
+
+	g_free (comp_str);
+	g_free (gdbus_comp);
+
+	return complete_string_exchange (res, out_string, uid, error);
+}
+
+/**
+ * e_cal_client_modify_object:
+ * @client: an #ECalClient
+ * @icalcomp: Component to modify
+ * @mod: Type of modification
+ * @cancellable: a #GCancellable; can be %NULL
+ * @callback: callback to call when a result is ready
+ * @user_data: user data for the @callback
+ *
+ * Requests the calendar backend to modify an existing object. If the object
+ * does not exist on the calendar, an error will be returned.
+ *
+ * For recurrent appointments, the @mod argument specifies what to modify,
+ * if all instances (CALOBJ_MOD_ALL), a single instance (CALOBJ_MOD_THIS),
+ * or a specific set of instances (CALOBJ_MOD_THISNADPRIOR and
+ * CALOBJ_MOD_THISANDFUTURE).
+ *
+ * The call is finished by e_cal_client_modify_object_finish() from
+ * the @callback.
+ *
+ * Since: 3.2
+ **/
+void
+e_cal_client_modify_object (ECalClient *client, /* const */ icalcomponent *icalcomp, CalObjModType mod, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	gchar *comp_str, **strv;
+
+	g_return_if_fail (icalcomp != NULL);
+
+	comp_str = icalcomponent_as_ical_string_r (icalcomp);
+	strv = e_gdbus_cal_encode_modify_object (comp_str, mod);
+
+	e_client_proxy_call_strv (E_CLIENT (client), (const gchar * const *) strv, cancellable, callback, user_data, e_cal_client_modify_object,
+			e_gdbus_cal_call_modify_object,
+			e_gdbus_cal_call_modify_object_finish, NULL, NULL, NULL, NULL);
+
+	g_strfreev (strv);
+	g_free (comp_str);
+}
+
+/**
+ * e_cal_client_modify_object_finish:
+ * @client: an #ECalClient
+ * @result: a #GAsyncResult
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Finishes previous call of e_cal_client_modify_object().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_modify_object_finish (ECalClient *client, GAsyncResult *result, GError **error)
+{
+	return e_client_proxy_call_finish_void (E_CLIENT (client), result, error, e_cal_client_modify_object);
+}
+
+/**
+ * e_cal_client_modify_object_sync:
+ * @client: an #ECalClient
+ * @icalcomp: Component to modify
+ * @mod: Type of modification
+ * @cancellable: a #GCancellable; can be %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Requests the calendar backend to modify an existing object. If the object
+ * does not exist on the calendar, an error will be returned.
+ *
+ * For recurrent appointments, the @mod argument specifies what to modify,
+ * if all instances (CALOBJ_MOD_ALL), a single instance (CALOBJ_MOD_THIS),
+ * or a specific set of instances (CALOBJ_MOD_THISNADPRIOR and
+ * CALOBJ_MOD_THISANDFUTURE).
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_modify_object_sync (ECalClient *client, /* const */ icalcomponent *icalcomp, CalObjModType mod, GCancellable *cancellable, GError **error)
+{
+	gboolean res;
+	gchar *comp_str, **strv;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+	g_return_val_if_fail (icalcomp != NULL, FALSE);
+
+	if (!client->priv->gdbus_cal) {
+		set_proxy_gone_error (error);
+		return FALSE;
+	}
+
+	comp_str = icalcomponent_as_ical_string_r (icalcomp);
+	strv = e_gdbus_cal_encode_modify_object (comp_str, mod);
+
+	res = e_client_proxy_call_sync_strv__void (E_CLIENT (client), (const gchar * const *) strv, cancellable, error, e_gdbus_cal_call_modify_object_sync);
+
+	g_strfreev (strv);
+	g_free (comp_str);
+
+	return res;
+}
+
+/**
+ * e_cal_client_remove_object:
+ * @client: an #ECalClient
+ * @uid: UID of the object to remove
+ * @rid: Recurrence ID of the specific recurrence to remove
+ * @mod: Type of the removal
+ * @cancellable: a #GCancellable; can be %NULL
+ * @callback: callback to call when a result is ready
+ * @user_data: user data for the @callback
+ *
+ * This function allows the removal of instances of a recurrent
+ * appointment. By using a combination of the @uid, @rid and @mod
+ * arguments, you can remove specific instances. If what you want
+ * is to remove all instances, use #NULL @rid and CALOBJ_MODE_THIS
+ * for the @mod.
+ *
+ * The call is finished by e_cal_client_remove_object_finish() from
+ * the @callback.
+ *
+ * Since: 3.2
+ **/
+void
+e_cal_client_remove_object (ECalClient *client, const gchar *uid, const gchar *rid, CalObjModType mod, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	gchar **strv;
+
+	g_return_if_fail (uid != NULL);
+
+	strv = e_gdbus_cal_encode_remove_object (uid, rid, mod);
+
+	e_client_proxy_call_strv (E_CLIENT (client), (const gchar * const *) strv, cancellable, callback, user_data, e_cal_client_remove_object,
+			e_gdbus_cal_call_remove_object,
+			e_gdbus_cal_call_remove_object_finish, NULL, NULL, NULL, NULL);
+
+	g_strfreev (strv);
+}
+
+/**
+ * e_cal_client_remove_object_finish:
+ * @client: an #ECalClient
+ * @result: a #GAsyncResult
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Finishes previous call of e_cal_client_remove_object().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_remove_object_finish (ECalClient *client, GAsyncResult *result, GError **error)
+{
+	return e_client_proxy_call_finish_void (E_CLIENT (client), result, error, e_cal_client_remove_object);
+}
+
+/**
+ * e_cal_client_remove_object_sync:
+ * @client: an #ECalClient
+ * @uid: UID of the object to remove
+ * @rid: Recurrence ID of the specific recurrence to remove
+ * @mod: Type of the removal
+ * @cancellable: a #GCancellable; can be %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * This function allows the removal of instances of a recurrent
+ * appointment. By using a combination of the @uid, @rid and @mod
+ * arguments, you can remove specific instances. If what you want
+ * is to remove all instances, use #NULL @rid and CALOBJ_MODE_THIS
+ * for the @mod.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_remove_object_sync (ECalClient *client, const gchar *uid, const gchar *rid, CalObjModType mod, GCancellable *cancellable, GError **error)
+{
+	gboolean res;
+	gchar **strv;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+	g_return_val_if_fail (uid != NULL, FALSE);
+
+	if (!client->priv->gdbus_cal) {
+		set_proxy_gone_error (error);
+		return FALSE;
+	}
+
+	strv = e_gdbus_cal_encode_remove_object (uid, rid, mod);
+
+	res = e_client_proxy_call_sync_strv__void (E_CLIENT (client), (const gchar * const *) strv, cancellable, error, e_gdbus_cal_call_remove_object_sync);
+
+	g_strfreev (strv);
+
+	return res;
+}
+
+/**
+ * e_cal_client_receive_objects:
+ * @client: an #ECalClient
+ * @icalcomp: An #icalcomponent
+ * @cancellable: a #GCancellable; can be %NULL
+ * @callback: callback to call when a result is ready
+ * @user_data: user data for the @callback
+ *
+ * Makes the backend receive the set of iCalendar objects specified in the
+ * @icalcomp argument. This is used for iTIP confirmation/cancellation
+ * messages for scheduled meetings.
+ *
+ * The call is finished by e_cal_client_receive_objects_finish() from
+ * the @callback.
+ *
+ * Since: 3.2
+ **/
+void
+e_cal_client_receive_objects (ECalClient *client, /* const */ icalcomponent *icalcomp, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	gchar *comp_str, *gdbus_comp = NULL;
+
+	g_return_if_fail (icalcomp != NULL);
+
+	comp_str = icalcomponent_as_ical_string_r (icalcomp);
+
+	e_client_proxy_call_string (E_CLIENT (client), e_util_ensure_gdbus_string (comp_str, &gdbus_comp), cancellable, callback, user_data, e_cal_client_receive_objects,
+			e_gdbus_cal_call_receive_objects,
+			e_gdbus_cal_call_receive_objects_finish, NULL, NULL, NULL, NULL);
+
+	g_free (comp_str);
+	g_free (gdbus_comp);
+}
+
+/**
+ * e_cal_client_receive_objects_finish:
+ * @client: an #ECalClient
+ * @result: a #GAsyncResult
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Finishes previous call of e_cal_client_receive_objects().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_receive_objects_finish (ECalClient *client, GAsyncResult *result, GError **error)
+{
+	return e_client_proxy_call_finish_void (E_CLIENT (client), result, error, e_cal_client_receive_objects);
+}
+
+/**
+ * e_cal_client_receive_objects_sync:
+ * @client: an #ECalClient
+ * @icalcomp: An #icalcomponent
+ * @cancellable: a #GCancellable; can be %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Makes the backend receive the set of iCalendar objects specified in the
+ * @icalcomp argument. This is used for iTIP confirmation/cancellation
+ * messages for scheduled meetings.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_receive_objects_sync (ECalClient *client, /* const */ icalcomponent *icalcomp, GCancellable *cancellable, GError **error)
+{
+	gboolean res;
+	gchar *comp_str, *gdbus_comp = NULL;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+
+	if (!client->priv->gdbus_cal) {
+		set_proxy_gone_error (error);
+		return FALSE;
+	}
+
+	comp_str = icalcomponent_as_ical_string_r (icalcomp);
+
+	res = e_client_proxy_call_sync_string__void (E_CLIENT (client), e_util_ensure_gdbus_string (comp_str, &gdbus_comp), cancellable, error, e_gdbus_cal_call_receive_objects_sync);
+
+	g_free (comp_str);
+	g_free (gdbus_comp);
+
+	return res;
+}
+
+/**
+ * e_cal_client_send_objects:
+ * @client: an #ECalClient
+ * @icalcomp: An icalcomponent to be sent
+ * @cancellable: a #GCancellable; can be %NULL
+ * @callback: callback to call when a result is ready
+ * @user_data: user data for the @callback
+ *
+ * Requests a calendar backend to send meeting information stored in @icalcomp.
+ * The backend can modify this component and request a send to particular users.
+ * The call is finished by e_cal_client_send_objects_finish() from
+ * the @callback.
+ *
+ * Since: 3.2
+ **/
+void
+e_cal_client_send_objects (ECalClient *client, /* const */ icalcomponent *icalcomp, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	gchar *comp_str, *gdbus_comp = NULL;
+
+	g_return_if_fail (icalcomp != NULL);
+
+	comp_str = icalcomponent_as_ical_string_r (icalcomp);
+
+	e_client_proxy_call_string (E_CLIENT (client), e_util_ensure_gdbus_string (comp_str, &gdbus_comp), cancellable, callback, user_data, e_cal_client_send_objects,
+			e_gdbus_cal_call_send_objects,
+			NULL, NULL, NULL, e_gdbus_cal_call_send_objects_finish, NULL);
+
+	g_free (comp_str);
+	g_free (gdbus_comp);
+}
+
+static gboolean
+complete_send_objects (gboolean res, gchar **out_strv, GSList **users, icalcomponent **modified_icalcomp, GError **error)
+{
+	g_return_val_if_fail (users != NULL, FALSE);
+	g_return_val_if_fail (modified_icalcomp != NULL, FALSE);
+
+	*users = NULL;
+	*modified_icalcomp = NULL;
+
+	if (res && out_strv) {
+		gchar *calobj = NULL;
+
+		if (e_gdbus_cal_decode_send_objects ((const gchar * const *) out_strv, &calobj, users)) {
+			*modified_icalcomp = icalparser_parse_string (calobj);
+			if (!*modified_icalcomp) {
+				g_set_error_literal (error, E_CAL_CLIENT_ERROR, E_CAL_CLIENT_ERROR_INVALID_OBJECT, e_cal_client_error_to_string (E_CAL_CLIENT_ERROR_INVALID_OBJECT));
+				e_client_util_free_string_slist (*users);
+				*users = NULL;
+				res = FALSE;
+			}
+		} else {
+			g_set_error_literal (error, E_CLIENT_ERROR, E_CLIENT_ERROR_INVALID_ARG, e_client_error_to_string (E_CLIENT_ERROR_INVALID_ARG));
+			e_client_util_free_string_slist (*users);
+			*users = NULL;
+			res = FALSE;
+		}
+
+		g_free (calobj);
+	} else {
+		res = FALSE;
+	}
+
+	g_strfreev (out_strv);
+
+	return res;
+}
+
+/**
+ * e_cal_client_send_objects_finish:
+ * @client: an #ECalClient
+ * @result: a #GAsyncResult
+ * @users: (out): List of users to send the @modified_icalcomp to
+ * @modified_icalcomp: (out): Return value for the icalcomponent to be sent
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Finishes previous call of e_cal_client_send_objects() and
+ * populates @users with a list of users to send @modified_icalcomp to.
+ * The @users list should be freed with e_client_util_free_string_slist() and
+ * the @modified_icalcomp should be freed with icalcomponent_free().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_send_objects_finish (ECalClient *client, GAsyncResult *result, GSList **users, icalcomponent **modified_icalcomp, GError **error)
+{
+	gboolean res;
+	gchar **out_strv = NULL;
+
+	g_return_val_if_fail (users != NULL, FALSE);
+	g_return_val_if_fail (modified_icalcomp != NULL, FALSE);
+
+	res = e_client_proxy_call_finish_strv (E_CLIENT (client), result, &out_strv, error, e_cal_client_send_objects);
+
+	return complete_send_objects (res, out_strv, users, modified_icalcomp, error);
+}
+
+/**
+ * e_cal_client_send_objects_sync:
+ * @client: an #ECalClient
+ * @icalcomp: An icalcomponent to be sent
+ * @users: (out): List of users to send the @modified_icalcomp to
+ * @modified_icalcomp: (out): Return value for the icalcomponent to be sent
+ * @cancellable: a #GCancellable; can be %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Requests a calendar backend to send meeting information stored in @icalcomp.
+ * The backend can modify this component and request a send to users in the @users list.
+ * The @users list should be freed with e_client_util_free_string_slist() and
+ * the @modified_icalcomp should be freed with icalcomponent_free().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_send_objects_sync (ECalClient *client, /* const */ icalcomponent *icalcomp, GSList **users, icalcomponent **modified_icalcomp, GCancellable *cancellable, GError **error)
+{
+	gboolean res;
+	gchar **out_strv = NULL, *comp_str, *gdbus_comp = NULL;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+	g_return_val_if_fail (icalcomp != NULL, FALSE);
+	g_return_val_if_fail (users != NULL, FALSE);
+	g_return_val_if_fail (modified_icalcomp != NULL, FALSE);
+
+	if (!client->priv->gdbus_cal) {
+		set_proxy_gone_error (error);
+		return FALSE;
+	}
+
+	comp_str = icalcomponent_as_ical_string_r (icalcomp);
+
+	res = e_client_proxy_call_sync_string__strv (E_CLIENT (client), e_util_ensure_gdbus_string (comp_str, &gdbus_comp), &out_strv, cancellable, error, e_gdbus_cal_call_send_objects_sync);
+
+	g_free (comp_str);
+	g_free (gdbus_comp);
+
+	return complete_send_objects (res, out_strv, users, modified_icalcomp, error);
+}
+
+/**
+ * e_cal_client_get_attachment_uris:
+ * @client: an #ECalClient
+ * @uid: Unique identifier for a calendar component
+ * @rid: Recurrence identifier
+ * @cancellable: a #GCancellable; can be %NULL
+ * @callback: callback to call when a result is ready
+ * @user_data: user data for the @callback
+ *
+ * Queries a calendar for a specified component's object attachment uris.
+ * The call is finished by e_cal_client_get_attachment_uris_finish() from
+ * the @callback.
+ *
+ * Since: 3.2
+ **/
+void
+e_cal_client_get_attachment_uris (ECalClient *client, const gchar *uid, const gchar *rid, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	gchar **strv;
+
+	g_return_if_fail (uid != NULL);
+
+	strv = e_gdbus_cal_encode_get_attachment_uris (uid, rid);
+
+	e_client_proxy_call_strv (E_CLIENT (client), (const gchar * const *) strv, cancellable, callback, user_data, e_cal_client_get_attachment_uris,
+			e_gdbus_cal_call_get_attachment_uris,
+			NULL, NULL, NULL, e_gdbus_cal_call_get_attachment_uris_finish, NULL);
+
+	g_strfreev (strv);
+}
+
+/**
+ * e_cal_client_get_attachment_uris_finish:
+ * @client: an #ECalClient
+ * @result: a #GAsyncResult
+ * @attachment_uris: (out:) Return the list of attachment uris
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Finishes previous call of e_cal_client_get_attachment_uris() and
+ * sets @attachment_uris to uris for component's attachments.
+ * The list should be freed with e_client_util_free_string_slist().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_get_attachment_uris_finish (ECalClient *client, GAsyncResult *result, GSList **attachment_uris, GError **error)
+{
+	gboolean res;
+	gchar **out_strv = NULL;
+
+	g_return_val_if_fail (attachment_uris != NULL, FALSE);
+
+	res = e_client_proxy_call_finish_strv (E_CLIENT (client), result, &out_strv, error, e_cal_client_get_attachment_uris);
+
+	if (res && out_strv) {
+		*attachment_uris = e_client_util_strv_to_slist ((const gchar * const *) out_strv);
+	} else {
+		*attachment_uris = NULL;
+	}
+
+	g_strfreev (out_strv);
+
+	return res;
+}
+
+/**
+ * e_cal_client_get_attachment_uris_sync:
+ * @client: an #ECalClient
+ * @uid: Unique identifier for a calendar component
+ * @rid: Recurrence identifier
+ * @attachment_uris: (out:) Return the list of attachment uris
+ * @cancellable: a #GCancellable; can be %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Queries a calendar for a specified component's object attachment uris.
+ * The list should be freed with e_client_util_free_string_slist().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_get_attachment_uris_sync (ECalClient *client, const gchar *uid, const gchar *rid, GSList **attachment_uris, GCancellable *cancellable, GError **error)
+{
+	gboolean res;
+	gchar **strv, **out_strv = NULL;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+	g_return_val_if_fail (uid != NULL, FALSE);
+	g_return_val_if_fail (attachment_uris != NULL, FALSE);
+
+	if (!client->priv->gdbus_cal) {
+		set_proxy_gone_error (error);
+		return FALSE;
+	}
+
+	strv = e_gdbus_cal_encode_get_attachment_uris (uid, rid);
+
+	res = e_client_proxy_call_sync_strv__strv (E_CLIENT (client), (const gchar * const *) strv, &out_strv, cancellable, error, e_gdbus_cal_call_get_attachment_uris_sync);
+
+	g_strfreev (strv);
+
+	if (res && out_strv) {
+		*attachment_uris = e_client_util_strv_to_slist ((const gchar * const *) out_strv);
+	} else {
+		*attachment_uris = NULL;
+	}
+
+	g_strfreev (out_strv);
+
+	return res;
+}
+
+/**
+ * e_cal_client_discard_alarm:
+ * @client: an #ECalClient
+ * @uid: Unique identifier for a calendar component
+ * @rid: Recurrence identifier
+ * @auid: Alarm identifier to remove
+ * @cancellable: a #GCancellable; can be %NULL
+ * @callback: callback to call when a result is ready
+ * @user_data: user data for the @callback
+ *
+ * Removes alarm @auid from a given component identified by @uid and @rid.
+ * The call is finished by e_cal_client_discard_alarm_finish() from
+ * the @callback.
+ *
+ * Since: 3.2
+ **/
+void
+e_cal_client_discard_alarm (ECalClient *client, const gchar *uid, const gchar *rid, const gchar *auid, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	gchar **strv;
+
+	g_return_if_fail (uid != NULL);
+	g_return_if_fail (auid != NULL);
+
+	strv = e_gdbus_cal_encode_discard_alarm (uid, rid, auid);
+
+	e_client_proxy_call_strv (E_CLIENT (client), (const gchar * const *) strv, cancellable, callback, user_data, e_cal_client_discard_alarm,
+			e_gdbus_cal_call_discard_alarm,
+			e_gdbus_cal_call_discard_alarm_finish, NULL, NULL, NULL, NULL);
+
+	g_strfreev (strv);
+}
+
+/**
+ * e_cal_client_discard_alarm_finish:
+ * @client: an #ECalClient
+ * @result: a #GAsyncResult
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Finishes previous call of e_cal_client_discard_alarm().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_discard_alarm_finish (ECalClient *client, GAsyncResult *result, GError **error)
+{
+	return e_client_proxy_call_finish_void (E_CLIENT (client), result, error, e_cal_client_discard_alarm);
+}
+
+/**
+ * e_cal_client_discard_alarm_sync:
+ * @client: an #ECalClient
+ * @uid: Unique identifier for a calendar component
+ * @rid: Recurrence identifier
+ * @auid: Alarm identifier to remove
+ * @cancellable: a #GCancellable; can be %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Removes alarm @auid from a given component identified by @uid and @rid.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_discard_alarm_sync (ECalClient *client, const gchar *uid, const gchar *rid, const gchar *auid, GCancellable *cancellable, GError **error)
+{
+	gboolean res;
+	gchar **strv;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+	g_return_val_if_fail (uid != NULL, FALSE);
+	g_return_val_if_fail (auid != NULL, FALSE);
+
+	if (!client->priv->gdbus_cal) {
+		set_proxy_gone_error (error);
+		return FALSE;
+	}
+
+	strv = e_gdbus_cal_encode_discard_alarm (uid, rid, auid);
+
+	res = e_client_proxy_call_sync_strv__void (E_CLIENT (client), (const gchar * const *) strv, cancellable, error, e_gdbus_cal_call_discard_alarm_sync);
+
+	g_strfreev (strv);
+
+	return res;
+}
+
+/**
+ * e_cal_client_get_view:
+ * @client: an #ECalClient
+ * @sexp: an S-expression representing the query.
+ * @cancellable: a #GCancellable; can be %NULL
+ * @callback: callback to call when a result is ready
+ * @user_data: user data for the @callback
+ *
+ * Query @client with @sexp, creating an #ECalClientView.
+ * The call is finished by e_cal_client_get_view_finish()
+ * from the @callback.
+ *
+ * Since: 3.2
+ **/
+void
+e_cal_client_get_view (ECalClient *client, const gchar *sexp, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	gchar *gdbus_sexp = NULL;
+
+	g_return_if_fail (sexp != NULL);
+
+	e_client_proxy_call_string (E_CLIENT (client), e_util_ensure_gdbus_string (sexp, &gdbus_sexp), cancellable, callback, user_data, e_cal_client_get_view,
+			e_gdbus_cal_call_get_view,
+			NULL, NULL, e_gdbus_cal_call_get_view_finish, NULL, NULL);
+
+	g_free (gdbus_sexp);
+}
+
+static gboolean
+complete_get_view (ECalClient *client, gboolean res, gchar *view_path, ECalClientView **view, GError **error)
+{
+	g_return_val_if_fail (view != NULL, FALSE);
+
+	if (view_path && res && cal_factory_proxy) {
+		EGdbusCalView *gdbus_calview;
+		GError *local_error = NULL;
+
+		gdbus_calview = e_gdbus_cal_view_proxy_new_sync (g_dbus_proxy_get_connection (G_DBUS_PROXY (cal_factory_proxy)),
+								G_DBUS_PROXY_FLAGS_NONE,
+								CALENDAR_DBUS_SERVICE_NAME,
+								view_path,
+								NULL,
+								&local_error);
+
+		if (gdbus_calview) {
+			*view = _e_cal_client_view_new (client, gdbus_calview);
+			g_object_unref (gdbus_calview);
+		} else {
+			*view = NULL;
+			res = FALSE;
+		}
+
+		if (local_error)
+			unwrap_dbus_error (local_error, error);
+	} else {
+		*view = NULL;
+		res = FALSE;
+	}
+
+	if (!*view && error && !*error)
+		g_set_error_literal (error, E_CLIENT_ERROR, E_CLIENT_ERROR_DBUS_ERROR, _("Cannot get connection to view"));
+
+	g_free (view_path);
+
+	return res;
+}
+
+/**
+ * e_cal_client_get_view_finish:
+ * @client: an #ECalClient
+ * @result: a #GAsyncResult
+ * @view: (out) an #ECalClientView
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Finishes previous call of e_cal_client_get_view().
+ * If successful, then the @view is set to newly allocated #ECalClientView,
+ * which should be freed with g_object_unref().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_get_view_finish (ECalClient *client, GAsyncResult *result, ECalClientView **view, GError **error)
+{
+	gboolean res;
+	gchar *view_path = NULL;
+
+	g_return_val_if_fail (view != NULL, FALSE);
+
+	res = e_client_proxy_call_finish_string (E_CLIENT (client), result, &view_path, error, e_cal_client_get_view);
+
+	return complete_get_view (client, res, view_path, view, error);
+}
+
+/**
+ * e_cal_client_get_view_sync:
+ * @client: an #ECalClient
+ * @sexp: an S-expression representing the query.
+ * @view: (out) an #ECalClientView
+ * @cancellable: a #GCancellable; can be %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Query @client with @sexp, creating an #ECalClientView.
+ * If successful, then the @view is set to newly allocated #ECalClientView,
+ * which should be freed with g_object_unref().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_get_view_sync (ECalClient *client, const gchar *sexp, ECalClientView **view, GCancellable *cancellable, GError **error)
+{
+	gboolean res;
+	gchar *gdbus_sexp = NULL;
+	gchar *view_path = NULL;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+	g_return_val_if_fail (sexp != NULL, FALSE);
+	g_return_val_if_fail (view != NULL, FALSE);
+
+	if (!client->priv->gdbus_cal) {
+		set_proxy_gone_error (error);
+		return FALSE;
+	}
+
+	res = e_client_proxy_call_sync_string__string (E_CLIENT (client), e_util_ensure_gdbus_string (sexp, &gdbus_sexp), &view_path, cancellable, error, e_gdbus_cal_call_get_view_sync);
+
+	g_free (gdbus_sexp);
+
+	return complete_get_view (client, res, view_path, view, error);
+}
+
+static icaltimezone *
+cal_client_get_timezone_from_cache (ECalClient *client, const gchar *tzid)
+{
+	icaltimezone *zone = NULL;
+
+	g_return_val_if_fail (client != NULL, NULL);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (client), NULL);
+	g_return_val_if_fail (client->priv != NULL, NULL);
+	g_return_val_if_fail (tzid != NULL, NULL);
+	g_return_val_if_fail (client->priv->zone_cache != NULL, NULL);
+	g_return_val_if_fail (client->priv->zone_cache_lock != NULL, NULL);
+
+	if (!*tzid)
+		return NULL;
+
+	g_mutex_lock (client->priv->zone_cache_lock);
+	if (g_str_equal (tzid, "UTC")) {
+		zone = icaltimezone_get_utc_timezone ();
+	} else {
+		/* See if we already have it in the cache. */
+		zone = g_hash_table_lookup (client->priv->zone_cache, tzid);
+	}
+
+	if (!zone) {
+		/*
+		 * Try to replace the original time zone with a more complete
+		 * and/or potentially updated system time zone. Note that this
+		 * also applies to TZIDs which match system time zones exactly:
+		 * they are extracted via icaltimezone_get_builtin_timezone_from_tzid()
+		 * below without a roundtrip to the backend.
+		 */
+		const gchar *systzid = e_cal_match_tzid (tzid);
+		if (systzid) {
+			/*
+			 * Use built-in time zone *and* rename it:
+			 * if the caller is asking for a TZID=FOO,
+			 * then likely because it has an event with
+			 * such a TZID. Returning a different TZID
+			 * would lead to broken VCALENDARs in the
+			 * caller.
+			 */
+			icaltimezone *syszone = icaltimezone_get_builtin_timezone_from_tzid (systzid);
+			if (syszone) {
+				gboolean found = FALSE;
+				icalcomponent *icalcomp = NULL;
+				icalproperty *prop;
+
+				icalcomp = icalcomponent_new_clone (icaltimezone_get_component (syszone));
+				prop = icalcomponent_get_first_property (icalcomp, ICAL_ANY_PROPERTY);
+				while (!found && prop) {
+					if (icalproperty_isa (prop) == ICAL_TZID_PROPERTY) {
+						icalproperty_set_value_from_string (prop, tzid, "NO");
+						found = TRUE;
+					}
+
+					prop = icalcomponent_get_next_property (icalcomp, ICAL_ANY_PROPERTY);
+				}
+
+				if (icalcomp) {
+					zone = icaltimezone_new ();
+					if (!icaltimezone_set_component (zone, icalcomp)) {
+						icalcomponent_free (icalcomp);
+						icaltimezone_free (zone, 1);
+						zone = NULL;
+					} else {
+						g_hash_table_insert (client->priv->zone_cache, g_strdup (icaltimezone_get_tzid (zone)), zone);
+					}
+				}
+			}
+		}
+	}
+
+	g_mutex_unlock (client->priv->zone_cache_lock);
+
+	return zone;
+}
+
+static gboolean
+cal_client_get_timezone_from_cache_finish (ECalClient *client, GAsyncResult *result, icaltimezone **zone, GError **error)
+{
+	GSimpleAsyncResult *simple;
+	GError *local_error = NULL;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+	g_return_val_if_fail (result != NULL, FALSE);
+	g_return_val_if_fail (zone != NULL, FALSE);
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (client), cal_client_get_timezone_from_cache), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	if (g_simple_async_result_propagate_error (simple, &local_error)) {
+		e_client_unwrap_dbus_error (E_CLIENT (client), local_error, error);
+		return FALSE;
+	}
+
+	*zone = g_simple_async_result_get_op_res_gpointer (simple);
+
+	return *zone != NULL;
+}
+
+/**
+ * e_cal_client_get_timezone:
+ * @client: an #ECalClient
+ * @tzid: ID of the timezone to retrieve
+ * @cancellable: a #GCancellable; can be %NULL
+ * @callback: callback to call when a result is ready
+ * @user_data: user data for the @callback
+ *
+ * Retrieves a timezone object from the calendar backend.
+ * The call is finished by e_cal_client_get_timezone_finish() from
+ * the @callback.
+ *
+ * Since: 3.2
+ **/
+void
+e_cal_client_get_timezone (ECalClient *client, const gchar *tzid, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	gchar *gdbus_tzid = NULL;
+	icaltimezone *zone;
+
+	g_return_if_fail (tzid != NULL);
+
+	zone = cal_client_get_timezone_from_cache (client, tzid);
+	if (zone) {
+		GCancellable *use_cancellable = cancellable;
+		guint32 opid;
+
+		if (!use_cancellable)
+			use_cancellable = g_cancellable_new ();
+
+		opid = e_client_register_op (E_CLIENT (client), use_cancellable);
+		if (opid) {
+			GSimpleAsyncResult *simple;
+
+			simple = g_simple_async_result_new (G_OBJECT (client), callback, user_data, cal_client_get_timezone_from_cache);
+			g_simple_async_result_set_op_res_gpointer (simple, zone, NULL);
+			g_simple_async_result_complete_in_idle (simple);
+			g_object_unref (simple);
+		}
+
+		if (use_cancellable != cancellable)
+			g_object_unref (use_cancellable);
+	} else {
+		e_client_proxy_call_string (E_CLIENT (client), e_util_ensure_gdbus_string (tzid, &gdbus_tzid), cancellable, callback, user_data, e_cal_client_get_timezone,
+				e_gdbus_cal_call_get_timezone,
+				NULL, NULL, e_gdbus_cal_call_get_timezone_finish, NULL, NULL);
+
+		g_free (gdbus_tzid);
+	}
+}
+
+static gboolean
+complete_get_timezone (ECalClient *client, gboolean res, gchar *out_string, icaltimezone **zone, GError **error)
+{
+	g_return_val_if_fail (zone != NULL, FALSE);
+
+	*zone = NULL;
+
+	if (res && out_string) {
+		icalcomponent *icalcomp;
+
+		icalcomp = icalparser_parse_string (out_string);
+		if (icalcomp) {
+			*zone = icaltimezone_new ();
+			if (!icaltimezone_set_component (*zone, icalcomp)) {
+				icaltimezone_free (*zone, 1);
+				icalcomponent_free (icalcomp);
+				res = FALSE;
+				g_set_error_literal (error, E_CAL_CLIENT_ERROR, E_CAL_CLIENT_ERROR_INVALID_OBJECT, e_cal_client_error_to_string (E_CAL_CLIENT_ERROR_INVALID_OBJECT));
+			} else {
+				g_mutex_lock (client->priv->zone_cache_lock);
+				g_hash_table_insert (client->priv->zone_cache, g_strdup (icaltimezone_get_tzid (*zone)), *zone);
+				g_mutex_unlock (client->priv->zone_cache_lock);
+			}
+		} else {
+			res = FALSE;
+			g_set_error_literal (error, E_CAL_CLIENT_ERROR, E_CAL_CLIENT_ERROR_INVALID_OBJECT, e_cal_client_error_to_string (E_CAL_CLIENT_ERROR_INVALID_OBJECT));
+		}
+	} else {
+		res = FALSE;
+	}
+
+	g_free (out_string);
+
+	return res;
+}
+
+/**
+ * e_cal_client_get_timezone_finish:
+ * @client: an #ECalClient
+ * @result: a #GAsyncResult
+ * @zone: (out): Return value for the timezone
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Finishes previous call of e_cal_client_get_timezone() and
+ * sets @zone to a retrieved timezone object from the calendar backend.
+ * This object is owned by the @client, thus do not free it.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_get_timezone_finish (ECalClient *client, GAsyncResult *result, icaltimezone **zone, GError **error)
+{
+	gboolean res;
+	gchar *out_string = NULL;
+
+	g_return_val_if_fail (zone != NULL, FALSE);
+
+	if (g_simple_async_result_get_source_tag (G_SIMPLE_ASYNC_RESULT (result)) == cal_client_get_timezone_from_cache) {
+		res = cal_client_get_timezone_from_cache_finish (client, result, zone, error);
+	} else {
+		res = e_client_proxy_call_finish_string (E_CLIENT (client), result, &out_string, error, e_cal_client_get_timezone);
+		res = complete_get_timezone (client, res, out_string, zone, error);
+	}
+
+	return res;
+}
+
+/**
+ * e_cal_client_get_timezone_sync:
+ * @client: an #ECalClient
+ * @tzid: ID of the timezone to retrieve
+ * @zone: (out): Return value for the timezone
+ * @cancellable: a #GCancellable; can be %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Retrieves a timezone object from the calendar backend.
+ * This object is owned by the @client, thus do not free it.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_get_timezone_sync (ECalClient *client, const gchar *tzid, icaltimezone **zone, GCancellable *cancellable, GError **error)
+{
+	gboolean res;
+	gchar *gdbus_tzid = NULL, *out_string = NULL;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+	g_return_val_if_fail (tzid != NULL, FALSE);
+	g_return_val_if_fail (zone != NULL, FALSE);
+
+	if (!client->priv->gdbus_cal) {
+		set_proxy_gone_error (error);
+		return FALSE;
+	}
+
+	*zone = cal_client_get_timezone_from_cache (client, tzid);
+	if (*zone)
+		return TRUE;
+
+	res = e_client_proxy_call_sync_string__string (E_CLIENT (client), e_util_ensure_gdbus_string (tzid, &gdbus_tzid), &out_string, cancellable, error, e_gdbus_cal_call_get_timezone_sync);
+
+	g_free (gdbus_tzid);
+
+	return complete_get_timezone (client, res, out_string, zone, error);
+}
+
+/**
+ * e_cal_client_add_timezone:
+ * @client: an #ECalClient
+ * @zone: The timezone to add
+ * @cancellable: a #GCancellable; can be %NULL
+ * @callback: callback to call when a result is ready
+ * @user_data: user data for the @callback
+ *
+ * Add a VTIMEZONE object to the given calendar client.
+ * The call is finished by e_cal_client_add_timezone_finish() from
+ * the @callback.
+ *
+ * Since: 3.2
+ **/
+void
+e_cal_client_add_timezone (ECalClient *client, /* const */ icaltimezone *zone, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	icalcomponent *icalcomp;
+	gchar *zone_str, *gdbus_zone = NULL;
+
+	g_return_if_fail (zone != NULL);
+
+	if (zone == icaltimezone_get_utc_timezone ())
+		return;
+
+	icalcomp = icaltimezone_get_component (zone);
+	g_return_if_fail (icalcomp != NULL);
+
+	zone_str = icalcomponent_as_ical_string_r (icalcomp);
+
+	e_client_proxy_call_string (E_CLIENT (client), e_util_ensure_gdbus_string (zone_str, &gdbus_zone), cancellable, callback, user_data, e_cal_client_add_timezone,
+			e_gdbus_cal_call_add_timezone,
+			e_gdbus_cal_call_add_timezone_finish, NULL, NULL, NULL, NULL);
+
+	g_free (zone_str);
+	g_free (gdbus_zone);
+}
+
+/**
+ * e_cal_client_add_timezone_finish:
+ * @client: an #ECalClient
+ * @result: a #GAsyncResult
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Finishes previous call of e_cal_client_add_timezone().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_add_timezone_finish (ECalClient *client, GAsyncResult *result, GError **error)
+{
+	return e_client_proxy_call_finish_void (E_CLIENT (client), result, error, e_cal_client_add_timezone);
+}
+
+/**
+ * e_cal_client_add_timezone_sync:
+ * @client: an #ECalClient
+ * @zone: The timezone to add
+ * @cancellable: a #GCancellable; can be %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Add a VTIMEZONE object to the given calendar client.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_client_add_timezone_sync (ECalClient *client, /* const */ icaltimezone *zone, GCancellable *cancellable, GError **error)
+{
+	gboolean res;
+	icalcomponent *icalcomp;
+	gchar *zone_str, *gdbus_zone = NULL;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+	g_return_val_if_fail (zone != NULL, FALSE);
+
+	if (zone == icaltimezone_get_utc_timezone ())
+		return TRUE;
+
+	icalcomp = icaltimezone_get_component (zone);
+	if (!icalcomp) {
+		g_set_error_literal (error, E_CLIENT_ERROR, E_CLIENT_ERROR_INVALID_ARG, e_client_error_to_string (E_CLIENT_ERROR_INVALID_ARG));
+		return FALSE;
+	}
+
+	if (!client->priv->gdbus_cal) {
+		set_proxy_gone_error (error);
+		return FALSE;
+	}
+
+	zone_str = icalcomponent_as_ical_string_r (icalcomp);
+
+	res = e_client_proxy_call_sync_string__void (E_CLIENT (client), e_util_ensure_gdbus_string (zone_str, &gdbus_zone), cancellable, error, e_gdbus_cal_call_add_timezone_sync);
+
+	g_free (zone_str);
+	g_free (gdbus_zone);
+
+	return res;
+}
+
+static GDBusProxy *
+cal_client_get_dbus_proxy (EClient *client)
+{
+	ECalClient *cal_client;
+
+	g_return_val_if_fail (client != NULL, NULL);
+
+	cal_client = E_CAL_CLIENT (client);
+	g_return_val_if_fail (cal_client != NULL, NULL);
+	g_return_val_if_fail (cal_client->priv != NULL, NULL);
+
+	return cal_client->priv->gdbus_cal;
+}
+
+static void
+cal_client_unwrap_dbus_error (EClient *client, GError *dbus_error, GError **out_error)
+{
+	unwrap_dbus_error (dbus_error, out_error);
+}
+
+static void
+cal_client_handle_authentication (EClient *client, const ECredentials *credentials)
+{
+	ECalClient *cal_client;
+	GError *error = NULL;
+	gchar **strv;
+
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (credentials != NULL);
+
+	cal_client = E_CAL_CLIENT (client);
+	g_return_if_fail (cal_client != NULL);
+	g_return_if_fail (cal_client->priv != NULL);
+
+	if (!cal_client->priv->gdbus_cal)
+		return;
+
+	strv = e_credentials_to_strv (credentials);
+	g_return_if_fail (strv != NULL);
+
+	e_gdbus_cal_call_authenticate_user_sync (cal_client->priv->gdbus_cal, (const gchar * const *) strv, NULL, &error);
+
+	g_strfreev (strv);
+
+	if (error) {
+		g_debug ("%s: Failed to authenticate user: %s", G_STRFUNC, error->message);
+		g_error_free (error);
+	}
+}
+
+static gchar *
+cal_client_retrieve_capabilities (EClient *client)
+{
+	ECalClient *cal_client;
+	GError *error = NULL;
+	gchar *capabilities = NULL;
+
+	g_return_val_if_fail (client != NULL, NULL);
+
+	cal_client = E_CAL_CLIENT (client);
+	g_return_val_if_fail (cal_client != NULL, NULL);
+	g_return_val_if_fail (cal_client->priv != NULL, NULL);
+
+	if (!cal_client->priv->gdbus_cal)
+		return NULL;
+
+	e_gdbus_cal_call_get_backend_property_sync (cal_client->priv->gdbus_cal, CLIENT_BACKEND_PROPERTY_CAPABILITIES, &capabilities, NULL, &error);
+
+	if (error) {
+		g_debug ("%s: Failed to retrieve capabilitites: %s", G_STRFUNC, error->message);
+		g_error_free (error);
+	}
+
+	return capabilities;
+}
+
+static void
+free_zone_cb (gpointer zone)
+{
+	icaltimezone_free (zone, 1);
+}
+
+static void
+e_cal_client_init (ECalClient *client)
+{
+	LOCK_FACTORY ();
+	active_cal_clients++;
+	UNLOCK_FACTORY ();
+
+	client->priv = G_TYPE_INSTANCE_GET_PRIVATE (client, E_TYPE_CAL_CLIENT, ECalClientPrivate);
+	client->priv->source_type = E_CAL_CLIENT_SOURCE_TYPE_LAST;
+	client->priv->default_zone = icaltimezone_copy (icaltimezone_get_utc_timezone ());
+	client->priv->cache_dir = NULL;
+	client->priv->zone_cache_lock = g_mutex_new ();
+	client->priv->zone_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, free_zone_cb);
+}
+
+static void
+cal_client_dispose (GObject *object)
+{
+	EClient *client;
+
+	client = E_CLIENT (object);
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (client->priv != NULL);
+
+	e_client_cancel_all (client);
+
+	gdbus_cal_client_disconnect (E_CAL_CLIENT (client));
+
+	/* Chain up to parent's dispose() method. */
+	G_OBJECT_CLASS (e_cal_client_parent_class)->dispose (object);
+}
+
+static void
+cal_client_finalize (GObject *object)
+{
+	ECalClient *client;
+	ECalClientPrivate *priv;
+
+	client = E_CAL_CLIENT (object);
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (client->priv != NULL);
+
+	priv = client->priv;
+
+	g_free (priv->cache_dir);
+	priv->cache_dir = NULL;
+
+	if (priv->default_zone)
+		icaltimezone_free (priv->default_zone, 1);
+	priv->default_zone = NULL;
+
+	g_mutex_lock (priv->zone_cache_lock);
+	g_hash_table_destroy (priv->zone_cache);
+	priv->zone_cache = NULL;
+	g_mutex_unlock (priv->zone_cache_lock);
+	g_mutex_free (priv->zone_cache_lock);
+	priv->zone_cache_lock = NULL;
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (e_cal_client_parent_class)->finalize (object);
+
+	LOCK_FACTORY ();
+	active_cal_clients--;
+	if (!active_cal_clients)
+		gdbus_cal_factory_proxy_disconnect (NULL);
+	UNLOCK_FACTORY ();
+}
+
+static void
+e_cal_client_class_init (ECalClientClass *klass)
+{
+	GObjectClass *object_class;
+	EClientClass *client_class;
+
+	g_type_class_add_private (klass, sizeof (ECalClientPrivate));
+
+	object_class = G_OBJECT_CLASS (klass);
+	object_class->dispose = cal_client_dispose;
+	object_class->finalize = cal_client_finalize;
+
+	client_class = E_CLIENT_CLASS (klass);
+	client_class->get_dbus_proxy			= cal_client_get_dbus_proxy;
+	client_class->unwrap_dbus_error			= cal_client_unwrap_dbus_error;
+	client_class->handle_authentication		= cal_client_handle_authentication;
+	client_class->retrieve_capabilities		= cal_client_retrieve_capabilities;
+	client_class->get_backend_property		= cal_client_get_backend_property;
+	client_class->get_backend_property_finish	= cal_client_get_backend_property_finish;
+	client_class->get_backend_property_sync		= cal_client_get_backend_property_sync;
+	client_class->set_backend_property		= cal_client_set_backend_property;
+	client_class->set_backend_property_finish	= cal_client_set_backend_property_finish;
+	client_class->set_backend_property_sync		= cal_client_set_backend_property_sync;
+	client_class->open				= cal_client_open;
+	client_class->open_finish			= cal_client_open_finish;
+	client_class->open_sync				= cal_client_open_sync;
+	client_class->remove				= cal_client_remove;
+	client_class->remove_finish			= cal_client_remove_finish;
+	client_class->remove_sync			= cal_client_remove_sync;
+	client_class->refresh				= cal_client_refresh;
+	client_class->refresh_finish			= cal_client_refresh_finish;
+	client_class->refresh_sync			= cal_client_refresh_sync;
+
+	signals[FREE_BUSY_DATA] = g_signal_new (
+		"free-busy-data",
+		G_OBJECT_CLASS_TYPE (klass),
+		G_SIGNAL_RUN_FIRST,
+		G_STRUCT_OFFSET (ECalClientClass, free_busy_data),
+		NULL, NULL,
+		g_cclosure_marshal_VOID__POINTER,
+		G_TYPE_NONE, 1,
+		G_TYPE_POINTER);
+}
diff --git a/calendar/libecal/e-cal-client.h b/calendar/libecal/e-cal-client.h
new file mode 100644
index 0000000..8f2f726
--- /dev/null
+++ b/calendar/libecal/e-cal-client.h
@@ -0,0 +1,193 @@
+/*
+ * e-cal-client.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 2011 Red Hat, Inc. (www.redhat.com)
+ *
+ */
+
+#ifndef E_CAL_CLIENT_H
+#define E_CAL_CLIENT_H
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#include <libedataserver/e-client.h>
+#include <libecal/e-cal-client-view.h>
+#include <libecal/e-cal-recur.h>
+#include <libecal/e-cal-util.h>
+
+G_BEGIN_DECLS
+
+#define E_TYPE_CAL_CLIENT		(e_cal_client_get_type ())
+#define E_CAL_CLIENT(o)			(G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_CAL_CLIENT, ECalClient))
+#define E_CAL_CLIENT_CLASS(k)		(G_TYPE_CHECK_CLASS_CAST ((k), E_TYPE_CAL_CLIENT, ECalClientClass))
+#define E_IS_CAL_CLIENT(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_CAL_CLIENT))
+#define E_IS_CAL_CLIENT_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_CAL_CLIENT))
+#define E_CAL_CLIENT_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_CAL_CLIENT, ECalClientClass))
+
+#define CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS		"cal-email-address"
+#define CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS	"alarm-email-address"
+#define CAL_BACKEND_PROPERTY_DEFAULT_OBJECT		"default-object"
+
+typedef enum {
+	E_CAL_CLIENT_SOURCE_TYPE_EVENTS,
+	E_CAL_CLIENT_SOURCE_TYPE_TASKS,
+	E_CAL_CLIENT_SOURCE_TYPE_MEMOS,
+	E_CAL_CLIENT_SOURCE_TYPE_LAST
+} ECalClientSourceType;
+
+GType e_cal_client_source_type_enum_get_type (void);
+
+#define E_CAL_CLIENT_ERROR e_cal_client_error_quark ()
+
+GQuark e_cal_client_error_quark (void) G_GNUC_CONST;
+
+typedef enum {
+	E_CAL_CLIENT_ERROR_NO_SUCH_CALENDAR,
+	E_CAL_CLIENT_ERROR_OBJECT_NOT_FOUND,
+	E_CAL_CLIENT_ERROR_INVALID_OBJECT,
+	E_CAL_CLIENT_ERROR_UNKNOWN_USER,
+	E_CAL_CLIENT_ERROR_OBJECT_ID_ALREADY_EXISTS
+} ECalClientError;
+
+const gchar *e_cal_client_error_to_string (ECalClientError code);
+
+typedef struct _ECalClient        ECalClient;
+typedef struct _ECalClientClass   ECalClientClass;
+typedef struct _ECalClientPrivate ECalClientPrivate;
+
+struct _ECalClient {
+	EClient parent;
+
+	/*< private >*/
+	ECalClientPrivate *priv;
+};
+
+struct _ECalClientClass {
+	EClientClass parent;
+
+	/* Signals */
+	void (* free_busy_data) (ECalClient *client, const GSList *free_busy_ecalcomps);
+};
+
+GType			e_cal_client_get_type			(void);
+
+/* Creating a new calendar */
+ECalClient *		e_cal_client_new			(ESource *source, ECalClientSourceType source_type, GError **error);
+ECalClient *		e_cal_client_new_from_uri		(const gchar *uri, ECalClientSourceType source_type, GError **error);
+ECalClient *		e_cal_client_new_system			(ECalClientSourceType source_type, GError **error);
+ECalClient *		e_cal_client_new_default		(ECalClientSourceType source_type, GError **error);
+
+/* Calendar discovery */
+gboolean		e_cal_client_set_default		(ECalClient *client, GError **error);
+gboolean		e_cal_client_set_default_source		(ESource *source, ECalClientSourceType source_type, GError **error);
+gboolean		e_cal_client_get_sources		(ESourceList **sources, ECalClientSourceType source_type, GError **error);
+
+/* Calendar properties not managed by EClient */
+ECalClientSourceType	e_cal_client_get_source_type		(ECalClient *client);
+const gchar *		e_cal_client_get_local_attachment_store	(ECalClient *client);
+void			e_cal_client_set_default_timezone	(ECalClient *client, /* const */ icaltimezone *zone);
+/*const*/ icaltimezone *e_cal_client_get_default_timezone	(ECalClient *client);
+
+/* Check predefined capabilities */
+gboolean		e_cal_client_check_one_alarm_only	(ECalClient *client);
+gboolean		e_cal_client_check_save_schedules	(ECalClient *client);
+gboolean		e_cal_client_check_organizer_must_attend(ECalClient *client);
+gboolean		e_cal_client_check_organizer_must_accept(ECalClient *client);
+gboolean		e_cal_client_check_recurrences_no_master(ECalClient *client);
+
+/* Utility functions */
+void		e_cal_client_free_icalcomp_slist		(GSList *icalcomps);
+void		e_cal_client_free_ecalcomp_slist		(GSList *ecalcomps);
+
+icaltimezone *	e_cal_client_resolve_tzid_cb			(const gchar *tzid, gpointer data);
+void		e_cal_client_generate_instances			(ECalClient *client, time_t start, time_t end, ECalRecurInstanceFn cb, gpointer cb_data);
+void		e_cal_client_generate_instances_for_object	(ECalClient *client, icalcomponent *icalcomp, time_t start, time_t end, ECalRecurInstanceFn cb, gpointer cb_data);
+gchar *		e_cal_client_get_component_as_string		(ECalClient *client, icalcomponent *icalcomp);
+
+/* Calendar methods */
+void		e_cal_client_get_default_object			(ECalClient *client, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_cal_client_get_default_object_finish		(ECalClient *client, GAsyncResult *result, icalcomponent **icalcomp, GError **error);
+gboolean	e_cal_client_get_default_object_sync		(ECalClient *client, icalcomponent **icalcomp, GCancellable *cancellable, GError **error);
+
+void		e_cal_client_refresh				(ECalClient *client, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_cal_client_refresh_finish			(ECalClient *client, GAsyncResult *result, GError **error);
+gboolean	e_cal_client_refresh_sync			(ECalClient *client, GCancellable *cancellable, GError **error);
+
+void		e_cal_client_get_object				(ECalClient *client, const gchar *uid, const gchar *rid, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_cal_client_get_object_finish			(ECalClient *client, GAsyncResult *result, icalcomponent **icalcomp, GError **error);
+gboolean	e_cal_client_get_object_sync			(ECalClient *client, const gchar *uid, const gchar *rid, icalcomponent **icalcomp, GCancellable *cancellable, GError **error);
+
+void		e_cal_client_get_objects_for_uid		(ECalClient *client, const gchar *uid, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_cal_client_get_objects_for_uid_finish		(ECalClient *client, GAsyncResult *result, GSList **ecalcomps, GError **error);
+gboolean	e_cal_client_get_objects_for_uid_sync		(ECalClient *client, const gchar *uid, GSList **ecalcomps, GCancellable *cancellable, GError **error);
+
+void		e_cal_client_get_object_list			(ECalClient *client, const gchar *sexp, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_cal_client_get_object_list_finish		(ECalClient *client, GAsyncResult *result, GSList **icalcomps, GError **error);
+gboolean	e_cal_client_get_object_list_sync		(ECalClient *client, const gchar *sexp, GSList **icalcomps, GCancellable *cancellable, GError **error);
+
+void		e_cal_client_get_object_list_as_comps		(ECalClient *client, const gchar *sexp, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_cal_client_get_object_list_as_comps_finish	(ECalClient *client, GAsyncResult *result, GSList **ecalcomps, GError **error);
+gboolean	e_cal_client_get_object_list_as_comps_sync	(ECalClient *client, const gchar *sexp, GSList **ecalcomps, GCancellable *cancellable, GError **error);
+
+void		e_cal_client_get_free_busy			(ECalClient *client, time_t start, time_t end, const GSList *users, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_cal_client_get_free_busy_finish		(ECalClient *client, GAsyncResult *result, GError **error);
+gboolean	e_cal_client_get_free_busy_sync			(ECalClient *client, time_t start, time_t end, const GSList *users, GCancellable *cancellable, GError **error);
+
+void		e_cal_client_create_object			(ECalClient *client, /* const */ icalcomponent *icalcomp, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_cal_client_create_object_finish		(ECalClient *client, GAsyncResult *result, gchar **uid, GError **error);
+gboolean	e_cal_client_create_object_sync			(ECalClient *client, /* const */ icalcomponent *icalcomp, gchar **uid, GCancellable *cancellable, GError **error);
+
+void		e_cal_client_modify_object			(ECalClient *client, /* const */ icalcomponent *icalcomp, CalObjModType mod, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_cal_client_modify_object_finish		(ECalClient *client, GAsyncResult *result, GError **error);
+gboolean	e_cal_client_modify_object_sync			(ECalClient *client, /* const */ icalcomponent *icalcomp, CalObjModType mod, GCancellable *cancellable, GError **error);
+
+void		e_cal_client_remove_object			(ECalClient *client, const gchar *uid, const gchar *rid, CalObjModType mod, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_cal_client_remove_object_finish		(ECalClient *client, GAsyncResult *result, GError **error);
+gboolean	e_cal_client_remove_object_sync			(ECalClient *client, const gchar *uid, const gchar *rid, CalObjModType mod, GCancellable *cancellable, GError **error);
+
+void		e_cal_client_receive_objects			(ECalClient *client, /* const */ icalcomponent *icalcomp, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_cal_client_receive_objects_finish		(ECalClient *client, GAsyncResult *result, GError **error);
+gboolean	e_cal_client_receive_objects_sync		(ECalClient *client, /* const */ icalcomponent *icalcomp, GCancellable *cancellable, GError **error);
+
+void		e_cal_client_send_objects			(ECalClient *client, /* const */ icalcomponent *icalcomp, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_cal_client_send_objects_finish		(ECalClient *client, GAsyncResult *result, GSList **users, icalcomponent **modified_icalcomp, GError **error);
+gboolean	e_cal_client_send_objects_sync			(ECalClient *client, /* const */ icalcomponent *icalcomp, GSList **users, icalcomponent **modified_icalcomp, GCancellable *cancellable, GError **error);
+
+void		e_cal_client_get_attachment_uris		(ECalClient *client, const gchar *uid, const gchar *rid, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_cal_client_get_attachment_uris_finish		(ECalClient *client, GAsyncResult *result, GSList **attachment_uris, GError **error);
+gboolean	e_cal_client_get_attachment_uris_sync		(ECalClient *client, const gchar *uid, const gchar *rid, GSList **attachment_uris, GCancellable *cancellable, GError **error);
+
+void		e_cal_client_discard_alarm			(ECalClient *client, const gchar *uid, const gchar *rid, const gchar *auid, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_cal_client_discard_alarm_finish		(ECalClient *client, GAsyncResult *result, GError **error);
+gboolean	e_cal_client_discard_alarm_sync			(ECalClient *client, const gchar *uid, const gchar *rid, const gchar *auid, GCancellable *cancellable, GError **error);
+
+void		e_cal_client_get_view				(ECalClient *client, const gchar *sexp, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_cal_client_get_view_finish			(ECalClient *client, GAsyncResult *result, ECalClientView **view, GError **error);
+gboolean	e_cal_client_get_view_sync			(ECalClient *client, const gchar *sexp, ECalClientView **view, GCancellable *cancellable, GError **error);
+
+void		e_cal_client_get_timezone			(ECalClient *client, const gchar *tzid, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_cal_client_get_timezone_finish		(ECalClient *client, GAsyncResult *result, icaltimezone **zone, GError **error);
+gboolean	e_cal_client_get_timezone_sync			(ECalClient *client, const gchar *tzid, icaltimezone **zone, GCancellable *cancellable, GError **error);
+
+void		e_cal_client_add_timezone			(ECalClient *client, /* const */ icaltimezone *zone, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_cal_client_add_timezone_finish		(ECalClient *client, GAsyncResult *result, GError **error);
+gboolean	e_cal_client_add_timezone_sync			(ECalClient *client, /* const */ icaltimezone *zone, GCancellable *cancellable, GError **error);
+
+G_END_DECLS
+
+#endif /* E_CAL_CLIENT_H */
diff --git a/calendar/libecal/e-cal-types.h b/calendar/libecal/e-cal-types.h
index a9dca51..bd9be80 100644
--- a/calendar/libecal/e-cal-types.h
+++ b/calendar/libecal/e-cal-types.h
@@ -28,6 +28,8 @@ G_BEGIN_DECLS
 
 
 
+#ifndef E_CAL_DISABLE_DEPRECATED
+
 #define E_CALENDAR_ERROR e_calendar_error_quark()
 
 GQuark e_calendar_error_quark (void) G_GNUC_CONST;
@@ -68,7 +70,6 @@ typedef enum {
 	E_CALENDAR_STATUS_NOT_SUPPORTED
 } ECalendarStatus;
 
-#ifndef E_CAL_DISABLE_DEPRECATED
 #define E_CALENDAR_STATUS_CORBA_EXCEPTION E_CALENDAR_STATUS_DBUS_EXCEPTION
 #endif
 
diff --git a/calendar/libecal/e-cal-view.c b/calendar/libecal/e-cal-view.c
index 98f6df7..0ca1437 100644
--- a/calendar/libecal/e-cal-view.c
+++ b/calendar/libecal/e-cal-view.c
@@ -30,13 +30,13 @@
 #include "e-cal.h"
 #include "e-cal-view.h"
 #include "e-cal-view-private.h"
-#include "e-gdbus-egdbuscalview.h"
+#include "e-gdbus-cal-view.h"
 
 G_DEFINE_TYPE (ECalView, e_cal_view, G_TYPE_OBJECT);
 
 /* Private part of the ECalView structure */
 struct _ECalViewPrivate {
-	EGdbusCalView *gdbus_calview;
+	GDBusProxy *gdbus_calview;
 	ECal *client;
 };
 
@@ -155,7 +155,7 @@ objects_removed_cb (EGdbusCalView *gdbus_calview, const gchar * const *uids, ECa
 }
 
 static void
-progress_cb (EGdbusCalView *gdbus_calview, const gchar *message, guint percent, ECalView *view)
+progress_cb (EGdbusCalView *gdbus_calview, guint percent, const gchar *message, ECalView *view)
 {
 	g_return_if_fail (E_IS_CAL_VIEW (view));
 
@@ -163,15 +163,22 @@ progress_cb (EGdbusCalView *gdbus_calview, const gchar *message, guint percent,
 }
 
 static void
-done_cb (EGdbusCalView *gdbus_calview, /* ECalendarStatus */ guint status, const gchar *message, ECalView *view)
+complete_cb (EGdbusCalView *gdbus_calview, const gchar * const *arg_error, ECalView *view)
 {
+	GError *error = NULL;
+
 	g_return_if_fail (E_IS_CAL_VIEW (view));
 
+	g_return_if_fail (e_gdbus_templates_decode_error (arg_error, &error));
+
 	#ifndef E_CAL_DISABLE_DEPRECATED
-	g_signal_emit (G_OBJECT (view), signals[VIEW_DONE], 0, status);
+	g_signal_emit (G_OBJECT (view), signals[VIEW_DONE], 0, error ? error->code : 0);
 	#endif
 
-	g_signal_emit (G_OBJECT (view), signals[VIEW_COMPLETE], 0, status, message);
+	g_signal_emit (G_OBJECT (view), signals[VIEW_COMPLETE], 0, error ? error->code : 0, error ? error->message : "");
+
+	if (error)
+		g_error_free (error);
 }
 
 /* Object initialization function for the calendar view */
@@ -201,7 +208,7 @@ e_cal_view_set_property (GObject *object, guint property_id, const GValue *value
 		g_signal_connect (priv->gdbus_calview, "objects-modified", G_CALLBACK (objects_modified_cb), view);
 		g_signal_connect (priv->gdbus_calview, "objects-removed", G_CALLBACK (objects_removed_cb), view);
 		g_signal_connect (priv->gdbus_calview, "progress", G_CALLBACK (progress_cb), view);
-		g_signal_connect (priv->gdbus_calview, "done", G_CALLBACK (done_cb), view);
+		g_signal_connect (priv->gdbus_calview, "complete", G_CALLBACK (complete_cb), view);
 		break;
 	case PROP_CLIENT:
 		priv->client = E_CAL (g_value_dup_object (value));
@@ -261,7 +268,10 @@ e_cal_view_finalize (GObject *object)
 		}
 	}
 
-	g_object_unref (priv->client);
+	if (priv->client) {
+		g_object_unref (priv->client);
+		priv->client = NULL;
+	}
 
 	/* Chain up to parent's finalize() method. */
 	G_OBJECT_CLASS (e_cal_view_parent_class)->finalize (object);
@@ -358,7 +368,7 @@ e_cal_view_class_init (ECalViewClass *klass)
 }
 
 /**
- * _e_cal_view_new:
+ * _e_cal_view_new_for_ecal:
  * @client: An #ECal object.
  * @gdbuc_calview: The GDBus object for the view.
  *
@@ -366,14 +376,16 @@ e_cal_view_class_init (ECalViewClass *klass)
  * calendar server.
  *
  * Returns: A newly-created view object, or NULL if the request failed.
+ *
+ * Deprecated: 3.2: Use #ECalClientView
  **/
 ECalView *
-_e_cal_view_new (ECal *client, EGdbusCalView *gdbus_calview)
+_e_cal_view_new (ECal *ecal, EGdbusCalView *gdbus_calview)
 {
 	ECalView *view;
 
 	view = g_object_new (E_TYPE_CAL_VIEW,
-		"client", client,
+		"client", ecal,
 		"view", gdbus_calview,
 		NULL);
 
@@ -389,6 +401,8 @@ _e_cal_view_new (ECal *client, EGdbusCalView *gdbus_calview)
  * Returns: the associated client.
  *
  * Since: 2.22
+ *
+ * Deprecated: 3.2: Use #ECalClientView
  */
 ECal *
 e_cal_view_get_client (ECalView *view)
@@ -405,6 +419,8 @@ e_cal_view_get_client (ECalView *view)
  * Starts a live query to the calendar/tasks backend.
  *
  * Since: 2.22
+ *
+ * Deprecated: 3.2: Use #ECalClientView
  */
 void
 e_cal_view_start (ECalView *view)
@@ -441,6 +457,8 @@ e_cal_view_start (ECalView *view)
  * Stops a live query to the calendar/tasks backend.
  *
  * Since: 2.32
+ *
+ * Deprecated: 3.2: Use #ECalClientView
  */
 void
 e_cal_view_stop (ECalView *view)
diff --git a/calendar/libecal/e-cal-view.h b/calendar/libecal/e-cal-view.h
index 0a3a5a0..a090a1c 100644
--- a/calendar/libecal/e-cal-view.h
+++ b/calendar/libecal/e-cal-view.h
@@ -21,6 +21,8 @@
 #ifndef E_CAL_VIEW_H
 #define E_CAL_VIEW_H
 
+#ifndef E_CAL_DISABLE_DEPRECATED
+
 #include <glib-object.h>
 #include <libecal/e-cal-types.h>
 
@@ -35,6 +37,7 @@ G_BEGIN_DECLS
 typedef struct _ECalView ECalView;
 typedef struct _ECalViewClass ECalViewClass;
 typedef struct _ECalViewPrivate ECalViewPrivate;
+
 struct _ECal;
 
 struct _ECalView {
@@ -61,9 +64,12 @@ struct _ECalViewClass {
 GType      e_cal_view_get_type (void);
 
 struct _ECal *e_cal_view_get_client (ECalView *view);
+
 void e_cal_view_start (ECalView *view);
 void e_cal_view_stop (ECalView *view);
 
 G_END_DECLS
 
+#endif /* E_CAL_DISABLE_DEPRECATED */
+
 #endif
diff --git a/calendar/libecal/e-cal.c b/calendar/libecal/e-cal.c
index b7d0e70..0dd0e10 100644
--- a/calendar/libecal/e-cal.c
+++ b/calendar/libecal/e-cal.c
@@ -28,6 +28,8 @@
  * The old signal "cal-opened" is deprecated since 3.0 and is replaced with
  * its equivalent "cal_opened_ex", which has a detailed #GError structure
  * as a parameter, instead of a status code only.
+ *
+ * Deprecated: 3.2: Use #ECalClient instead.
  */
 
 #ifdef HAVE_CONFIG_H
@@ -40,6 +42,7 @@
 
 #include <libical/ical.h>
 #include <libedataserver/e-url.h>
+#include <libedataserver/e-credentials.h>
 #include <libedataserver/e-data-server-util.h>
 
 #include <glib-object.h>
@@ -52,9 +55,15 @@
 #include "e-cal-view-private.h"
 #include "e-cal.h"
 
-#include "e-gdbus-egdbuscalfactory.h"
-#include "e-gdbus-egdbuscal.h"
-#include "e-gdbus-egdbuscalview.h"
+#include "e-gdbus-cal.h"
+#include "e-gdbus-cal-view.h"
+#include "e-gdbus-cal-factory.h"
+
+#define CLIENT_BACKEND_PROPERTY_CACHE_DIR		"cache-dir"
+#define CLIENT_BACKEND_PROPERTY_CAPABILITIES		"capabilities"
+#define CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS		"cal-email-address"
+#define CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS	"alarm-email-address"
+#define CAL_BACKEND_PROPERTY_DEFAULT_OBJECT		"default-object"
 
 static guint active_cals = 0, cal_connection_closed_id = 0;
 static EGdbusCalFactory *cal_factory_proxy = NULL;
@@ -77,7 +86,7 @@ static void e_cal_finalize (GObject *object);
 
 /* Private part of the ECal structure */
 struct _ECalPrivate {
-	EGdbusCal *gdbus_cal;
+	GDBusProxy *gdbus_cal;
 	guint gone_signal_id;
 
 	/* Load state to avoid multiple loads */
@@ -99,6 +108,7 @@ struct _ECalPrivate {
 	gchar *capabilities;
 
 	gint mode;
+	gboolean requires_auth;
 
 	gboolean read_only;
 
@@ -119,6 +129,9 @@ struct _ECalPrivate {
 	/* For locking the operation while localling cache values like 
 	   static capabilities, cal address etc. */
 	GStaticRecMutex cache_lock;
+
+	GList **free_busy_data;
+	GMutex *free_busy_data_lock;
 };
 
 
@@ -217,6 +230,7 @@ get_status_from_error (const GError *error)
 		ECalendarStatus err_code;
 	} errors[] = {
 		{ err ("Success",				E_CALENDAR_STATUS_OK) },
+		{ err ("Busy",					E_CALENDAR_STATUS_BUSY) },
 		{ err ("RepositoryOffline",			E_CALENDAR_STATUS_REPOSITORY_OFFLINE) },
 		{ err ("PermissionDenied",			E_CALENDAR_STATUS_PERMISSION_DENIED) },
 		{ err ("InvalidRange",				E_CALENDAR_STATUS_OTHER_ERROR) },
@@ -305,6 +319,8 @@ unwrap_gerror (GError **error)
  * Registers the #ECalSourceTypeEnum type with glib.
  *
  * Returns: the ID of the #ECalSourceTypeEnum type.
+ *
+ * Deprecated: 3.2: Use e_cal_client_source_type_enum_get_type() instead.
  */
 GType
 e_cal_source_type_enum_get_type (void)
@@ -334,6 +350,8 @@ e_cal_source_type_enum_get_type (void)
  * Registers the #ECalSetModeStatusEnum type with glib.
  *
  * Returns: the ID of the #ECalSetModeStatusEnum type.
+ *
+ * Deprecated: 3.2: This type has been dropped completely.
  */
 GType
 e_cal_set_mode_status_enum_get_type (void)
@@ -362,6 +380,8 @@ e_cal_set_mode_status_enum_get_type (void)
  * Registers the #CalModeEnum type with glib.
  *
  * Returns: the ID of the #CalModeEnum type.
+ *
+ * Deprecated: 3.2: This type has been dropped completely.
  */
 GType
 cal_mode_enum_get_type (void)
@@ -401,6 +421,7 @@ convert_type (ECalSourceType type)
 
 	return AnyType;
 }
+
 static void
 e_cal_init (ECal *ecal)
 {
@@ -424,6 +445,7 @@ e_cal_init (ECal *ecal)
 	priv->gdbus_cal = NULL;
 	priv->timezones = g_hash_table_new (g_str_hash, g_str_equal);
 	priv->default_zone = icaltimezone_get_utc_timezone ();
+	priv->free_busy_data_lock = g_mutex_new ();
 	g_static_rec_mutex_init (&priv->cache_lock);
 }
 
@@ -559,10 +581,20 @@ e_cal_finalize (GObject *object)
 		priv->capabilities = NULL;
 	}
 
+	if (priv->free_busy_data) {
+		g_mutex_lock (priv->free_busy_data_lock);
+		g_list_foreach (*priv->free_busy_data, (GFunc) g_object_unref, NULL);
+		g_list_free (*priv->free_busy_data);
+		*priv->free_busy_data = NULL;
+		priv->free_busy_data = NULL;
+		g_mutex_unlock (priv->free_busy_data_lock);
+	}
+
 	g_hash_table_foreach (priv->timezones, free_timezone, NULL);
 	g_hash_table_destroy (priv->timezones);
 	priv->timezones = NULL;
 	g_static_rec_mutex_free (&priv->cache_lock);
+	g_mutex_free (priv->free_busy_data_lock);
 
 	(* G_OBJECT_CLASS (parent_class)->finalize) (object);
 
@@ -729,6 +761,176 @@ e_cal_activate (GError **error)
 	return TRUE;
 }
 
+static gchar *
+build_proxy_pass_key (ECal *ecal, const gchar * parent_user)
+{
+	gchar *euri_str;
+	const gchar *uri;
+	EUri *euri;
+
+	uri = e_cal_get_uri (ecal);
+
+	euri = e_uri_new (uri);
+	g_free (euri->user);
+	euri->user = g_strdup (parent_user);
+
+	euri_str = e_uri_to_string (euri, FALSE);
+
+	e_uri_free (euri);
+	return euri_str;
+}
+
+static gchar *
+build_pass_key (ECal *ecal)
+{
+	gchar *euri_str;
+	const gchar *uri;
+	EUri *euri;
+
+	uri = e_cal_get_uri (ecal);
+
+	euri = e_uri_new (uri);
+	euri_str = e_uri_to_string (euri, FALSE);
+
+	e_uri_free (euri);
+	return euri_str;
+}
+
+static void async_open_report_result (ECal *ecal, const GError *error);
+
+static void
+authenticate_user_ready_cb (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	ECal *cal = user_data;
+	GError *error = NULL;
+
+	g_return_if_fail (cal != NULL);
+
+	if (!e_gdbus_cal_call_authenticate_user_finish (G_DBUS_PROXY (source_object), result, &error))
+		cal->priv->load_state = E_CAL_LOAD_NOT_LOADED;
+	else
+		cal->priv->load_state = E_CAL_LOAD_LOADED;
+
+	if (cal->priv->requires_auth && !error) {
+		cal->priv->load_state = E_CAL_LOAD_NOT_LOADED;
+		g_set_error_literal (&error, E_CALENDAR_ERROR, E_CALENDAR_STATUS_AUTHENTICATION_FAILED, e_cal_get_error_message (E_CALENDAR_STATUS_AUTHENTICATION_FAILED));
+	}
+
+	unwrap_gerror (&error);
+	async_open_report_result (cal, error);
+
+	if (error)
+		g_error_free (error);
+}
+
+static gboolean
+call_authenticate_user (ECal *cal, gboolean async, GError **error)
+{
+	gchar *username = NULL, *password = NULL;
+	ECredentials *credentials = NULL;
+	ECalPrivate *priv;
+
+	g_return_val_if_fail (cal != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL (cal), FALSE);
+
+	priv = cal->priv;
+
+	if (!priv->gdbus_cal) {
+		E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
+	}
+
+	/* see if the backend needs authentication */
+	if ((priv->mode != CAL_MODE_LOCAL) && (e_source_get_property (priv->source, "auth") || priv->requires_auth)) {
+		gchar *prompt, *key, *auth_type = NULL;
+		gchar *parent_user;
+
+		priv->load_state = E_CAL_LOAD_AUTHENTICATING;
+
+		if (priv->auth_func == NULL) {
+			priv->load_state = E_CAL_LOAD_NOT_LOADED;
+			E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED, error);
+		}
+
+		username = e_source_get_duped_property (priv->source, "username");
+		if (!username) {
+			priv->load_state = E_CAL_LOAD_NOT_LOADED;
+			E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED, error);
+		}
+
+		prompt = g_strdup_printf (_("Enter password for %s (user %s)"),
+				e_source_peek_name (priv->source), username);
+
+		auth_type = e_source_get_duped_property (priv->source, "auth-type");
+		if (auth_type)
+			key = build_pass_key (cal);
+		else {
+			parent_user = e_source_get_duped_property (priv->source, "parent_id_name");
+			if (parent_user) {
+				key = build_proxy_pass_key (cal, parent_user);
+				/*
+				   This password prompt will be prompted rarely. Since the key that is passed to
+				   the auth_func corresponds to the parent user.
+				 */
+				prompt = g_strdup_printf (_("Enter password for %s to enable proxy for user %s"), e_source_peek_name (priv->source), parent_user);
+				g_free (parent_user);
+			} else
+				key = g_strdup (e_cal_get_uri (cal));
+		}
+		g_free (auth_type);
+
+		if (!key) {
+			priv->load_state = E_CAL_LOAD_NOT_LOADED;
+			g_free (username);
+			E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED, error);
+		}
+
+		password = priv->auth_func (cal, prompt, key, priv->auth_user_data);
+
+		if (!password) {
+			priv->load_state = E_CAL_LOAD_NOT_LOADED;
+			g_free (username);
+			E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED, error);
+		}
+
+		g_free (prompt);
+		g_free (key);
+	}
+
+	if (username)
+		credentials = e_credentials_new_args (
+			E_CREDENTIALS_KEY_USERNAME, username,
+			E_CREDENTIALS_KEY_PASSWORD, password,
+			NULL);
+	else
+		priv->load_state = E_CAL_LOAD_NOT_LOADED;
+
+	g_free (username);
+	e_credentials_util_safe_free_string (password);
+
+	if (credentials) {
+		gchar **strv = e_credentials_to_strv (credentials);
+
+		if (async) {
+			cal->priv->requires_auth = FALSE;
+			e_gdbus_cal_call_authenticate_user (cal->priv->gdbus_cal, (const gchar * const *) strv, NULL, authenticate_user_ready_cb, cal);
+		} else if (e_gdbus_cal_call_authenticate_user_sync (cal->priv->gdbus_cal, (const gchar * const *) strv, NULL, error))
+			priv->load_state = E_CAL_LOAD_LOADED;
+		else
+			priv->load_state = E_CAL_LOAD_NOT_LOADED;
+
+		g_strfreev (strv);
+		e_credentials_free (credentials);
+
+		if (error && *error)
+			unwrap_gerror (error);
+	} else if (priv->requires_auth) {
+		priv->load_state = E_CAL_LOAD_NOT_LOADED;
+		g_set_error_literal (error, E_CALENDAR_ERROR, E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED, e_cal_get_error_message (E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED));
+	}
+
+	return credentials && (!error || !*error);
+}
+
 static gboolean
 reopen_with_auth (gpointer data)
 {
@@ -750,11 +952,62 @@ reopen_with_auth (gpointer data)
 }
 
 static void
-auth_required_cb (EGdbusCal *gdbus_cal, ECal *cal)
+auth_required_cb (EGdbusCal *gdbus_cal, const gchar * const *credentials_strv, ECal *cal)
+{
+	ECalPrivate *priv;
+	g_return_if_fail (E_IS_CAL (cal));
+
+	priv = cal->priv;
+
+	priv->requires_auth = TRUE;
+
+	if (priv->load_state != E_CAL_LOAD_AUTHENTICATING)
+		g_idle_add (reopen_with_auth, (gpointer) cal);
+}
+
+static void
+free_busy_data_cb (EGdbusCal *gdbus_cal, const gchar * const *free_busy_strv, ECal *cal)
 {
+	ECalPrivate *priv;
+
 	g_return_if_fail (E_IS_CAL (cal));
 
-	g_idle_add (reopen_with_auth, (gpointer) cal);
+	priv = cal->priv;
+
+	g_mutex_lock (priv->free_busy_data_lock);
+
+	if (priv->free_busy_data) {
+		gint ii;
+		GList *list = *priv->free_busy_data;
+
+		for (ii = 0; free_busy_strv[ii]; ii++) {
+			ECalComponent *comp;
+			icalcomponent *icalcomp;
+			icalcomponent_kind kind;
+
+			icalcomp = icalcomponent_new_from_string (free_busy_strv[ii]);
+			if (!icalcomp)
+				continue;
+
+			kind = icalcomponent_isa (icalcomp);
+			if (kind == ICAL_VFREEBUSY_COMPONENT) {
+				comp = e_cal_component_new ();
+				if (!e_cal_component_set_icalcomponent (comp, icalcomp)) {
+					icalcomponent_free (icalcomp);
+					g_object_unref (G_OBJECT (comp));
+					continue;
+				}
+
+				list = g_list_append (list, comp);
+			} else {
+				icalcomponent_free (icalcomp);
+			}
+		}
+
+		*priv->free_busy_data = list;
+	}
+
+	g_mutex_unlock (priv->free_busy_data_lock);
 }
 
 typedef struct
@@ -805,13 +1058,12 @@ readonly_cb (EGdbusCal *gdbus_cal, gboolean read_only, ECal *cal)
 }
 
 static void
-mode_cb (EGdbusCal *gdbus_cal, EDataCalMode mode, ECal *cal)
+online_cb (EGdbusCal *gdbus_cal, gboolean is_online, ECal *cal)
 {
 	g_return_if_fail (E_IS_CAL (cal));
-	g_return_if_fail (mode & AnyMode);
 
 	g_signal_emit (G_OBJECT (cal), e_cal_signals[CAL_SET_MODE],
-		       0, E_CALENDAR_STATUS_OK, mode);
+		       0, E_CALENDAR_STATUS_OK, is_online ? Remote : Local);
 }
 
 /*
@@ -832,8 +1084,8 @@ set_local_attachment_store (ECal *ecal)
 	gchar *cache_dir = NULL;
 	GError *error = NULL;
 
-	e_gdbus_cal_call_get_cache_dir_sync (
-		ecal->priv->gdbus_cal, &cache_dir, NULL, &error);
+	e_gdbus_cal_call_get_backend_property_sync (
+		ecal->priv->gdbus_cal, CLIENT_BACKEND_PROPERTY_CACHE_DIR, &cache_dir, NULL, &error);
 
 	if (error == NULL)
 		ecal->priv->local_attachment_store = cache_dir;
@@ -854,13 +1106,15 @@ set_local_attachment_store (ECal *ecal)
  *
  * Returns: A newly-created calendar client, or NULL if the client could
  * not be constructed because it could not contact the calendar server.
+ *
+ * Deprecated: 3.2: Use e_cal_client_new() instead.
  **/
 ECal *
 e_cal_new (ESource *source, ECalSourceType type)
 {
 	ECal *ecal;
 	ECalPrivate *priv;
-	gchar *path, *xml;
+	gchar *path, *xml, **strv;
 	GError *error = NULL;
 	GDBusConnection *connection;
 
@@ -883,7 +1137,9 @@ e_cal_new (ESource *source, ECalSourceType type)
 	priv->type = type;
 
 	xml = e_source_to_standalone_xml (priv->source);
-	if (!e_gdbus_cal_factory_call_get_cal_sync (cal_factory_proxy, xml, convert_type (priv->type), &path, NULL, &error)) {
+	strv = e_gdbus_cal_factory_encode_get_cal (xml, convert_type (priv->type));
+	if (!e_gdbus_cal_factory_call_get_cal_sync (G_DBUS_PROXY (cal_factory_proxy), (const gchar * const *) strv, &path, NULL, &error)) {
+		g_strfreev (strv);
 		g_free (xml);
 		unwrap_gerror (&error);
 		g_warning ("Cannot get cal from factory: %s", error ? error->message : "Unknown error");
@@ -892,14 +1148,15 @@ e_cal_new (ESource *source, ECalSourceType type)
 		g_object_unref (ecal);
 		return NULL;
 	}
+	g_strfreev (strv);
 	g_free (xml);
 
-	priv->gdbus_cal = e_gdbus_cal_proxy_new_sync (g_dbus_proxy_get_connection (G_DBUS_PROXY (cal_factory_proxy)),
+	priv->gdbus_cal = G_DBUS_PROXY (e_gdbus_cal_proxy_new_sync (g_dbus_proxy_get_connection (G_DBUS_PROXY (cal_factory_proxy)),
 						      G_DBUS_PROXY_FLAGS_NONE,
 						      CALENDAR_DBUS_SERVICE_NAME,
 						      path,
 						      NULL,
-						      &error);
+						      &error));
 
 	if (!priv->gdbus_cal) {
 		g_free (path);
@@ -925,7 +1182,8 @@ e_cal_new (ESource *source, ECalSourceType type)
 	g_signal_connect (priv->gdbus_cal, "auth-required", G_CALLBACK (auth_required_cb), ecal);
 	g_signal_connect (priv->gdbus_cal, "backend-error", G_CALLBACK (backend_error_cb), ecal);
 	g_signal_connect (priv->gdbus_cal, "readonly", G_CALLBACK (readonly_cb), ecal);
-	g_signal_connect (priv->gdbus_cal, "mode", G_CALLBACK (mode_cb), ecal);
+	g_signal_connect (priv->gdbus_cal, "online", G_CALLBACK (online_cb), ecal);
+	g_signal_connect (priv->gdbus_cal, "free-busy-data", G_CALLBACK (free_busy_data_cb), ecal);
 
 	/* Set the local attachment store path for the calendar */
 	set_local_attachment_store (ecal);
@@ -1010,6 +1268,8 @@ check_uri (ESource *source, gpointer uri)
  *
  * Returns: A newly-created calendar client, or NULL if the client could
  * not be constructed because it could not contact the calendar server.
+ *
+ * Deprecated: 3.2: Use e_cal_client_new_from_uri() instead.
  **/
 ECal *
 e_cal_new_from_uri (const gchar *uri, ECalSourceType type)
@@ -1090,6 +1350,8 @@ get_local_source (ECalSourceType type)
  *
  * Returns: A newly-created calendar client, or %NULL if the client could
  * not be constructed.
+ *
+ * Deprecated: 3.2: Use e_cal_client_new_system() instead.
  */
 ECal *
 e_cal_new_system_calendar (void)
@@ -1106,6 +1368,8 @@ e_cal_new_system_calendar (void)
  *
  * Returns: A newly-created calendar client, or %NULL if the client could
  * not be constructed.
+ *
+ * Deprecated: 3.2: Use e_cal_client_new_system() instead.
  */
 ECal *
 e_cal_new_system_tasks (void)
@@ -1122,6 +1386,8 @@ e_cal_new_system_tasks (void)
  *
  * Returns: A newly-created calendar client, or %NULL if the client could
  * not be constructed.
+ *
+ * Deprecated: 3.2: Use e_cal_client_new_system() instead.
  */
 ECal *
 e_cal_new_system_memos (void)
@@ -1154,6 +1420,8 @@ e_cal_new_system_memos (void)
  *			  const gchar *prompt,
  *			  const gchar *key,
  *			  gpointer user_data)
+ *
+ * Deprecated: 3.2: Use EClient::authenticate() signal on an #ECalClient instead.
  */
 void
 e_cal_set_auth_func (ECal *ecal, ECalAuthFunc func, gpointer data)
@@ -1165,41 +1433,6 @@ e_cal_set_auth_func (ECal *ecal, ECalAuthFunc func, gpointer data)
 	ecal->priv->auth_user_data = data;
 }
 
-static gchar *
-build_proxy_pass_key (ECal *ecal, const gchar * parent_user)
-{
-	gchar *euri_str;
-	const gchar *uri;
-	EUri *euri;
-
-	uri = e_cal_get_uri (ecal);
-
-	euri = e_uri_new (uri);
-	g_free (euri->user);
-	euri->user = g_strdup (parent_user);
-
-	euri_str = e_uri_to_string (euri, FALSE);
-
-	e_uri_free (euri);
-	return euri_str;
-}
-
-static gchar *
-build_pass_key (ECal *ecal)
-{
-	gchar *euri_str;
-	const gchar *uri;
-	EUri *euri;
-
-	uri = e_cal_get_uri (ecal);
-
-	euri = e_uri_new (uri);
-	euri_str = e_uri_to_string (euri, FALSE);
-
-	e_uri_free (euri);
-	return euri_str;
-}
-
 static void
 async_open_report_result (ECal *ecal, const GError *error)
 {
@@ -1220,7 +1453,6 @@ async_open_report_result (ECal *ecal, const GError *error)
 	#else
 	} else {
 	#endif
-		e_gdbus_cal_call_is_read_only_sync (ecal->priv->gdbus_cal, NULL, NULL);
 	}
 
 	#ifndef E_CAL_DISABLE_DEPRECATED
@@ -1229,14 +1461,43 @@ async_open_report_result (ECal *ecal, const GError *error)
 	g_signal_emit (G_OBJECT (ecal), e_cal_signals[CAL_OPENED_EX], 0, error);
 }
 
+static gboolean
+reschedule_authenticate_cb (gpointer user_data)
+{
+	GError *error = NULL;
+	ECal *ecal = user_data;
+
+	g_return_val_if_fail (ecal && E_IS_CAL (ecal), FALSE);
+
+	if (g_main_depth () > 1)
+		return TRUE;
+
+	if (call_authenticate_user (ecal, TRUE, &error))
+		return FALSE;
+
+	unwrap_gerror (&error);
+	async_open_report_result (ecal, error);
+
+	if (error)
+		g_error_free (error);
+
+	return FALSE;
+}
+
 static void
-async_open_ready_cb (EGdbusCal *gdbus_cal, GAsyncResult *res, ECal *ecal)
+async_open_ready_cb (GDBusProxy *gdbus_cal, GAsyncResult *res, ECal *ecal)
 {
 	GError *error = NULL;
 
 	g_return_if_fail (ecal && E_IS_CAL (ecal));
 
-	e_gdbus_cal_call_open_finish (gdbus_cal, res, &error);
+	if (e_gdbus_cal_call_open_finish (gdbus_cal, res, &error)) {
+		if (g_main_depth () > 1) {
+			g_idle_add (reschedule_authenticate_cb, ecal);
+			return;
+		} else if (call_authenticate_user (ecal, TRUE, &error))
+			return;
+	}
 
 	unwrap_gerror (&error);
 
@@ -1254,7 +1515,6 @@ open_calendar (ECal *ecal, gboolean only_if_exists, GError **error,
 	gboolean needs_auth, gboolean async)
 {
 	ECalPrivate *priv;
-	gchar *username = NULL, *auth_type = NULL, *password = NULL;
 
 	g_return_val_if_fail (error != NULL, FALSE);
 
@@ -1267,11 +1527,9 @@ open_calendar (ECal *ecal, gboolean only_if_exists, GError **error,
 		return TRUE;
 	}
 
-	/* see if the backend needs authentication */
-	if ( (priv->mode !=  CAL_MODE_LOCAL) && e_source_get_property (priv->source, "auth")) {
-		gchar *prompt, *key;
-		gchar *parent_user;
+	priv->load_state = E_CAL_LOAD_LOADING;
 
+	if ((priv->mode != CAL_MODE_LOCAL) && e_source_get_property (priv->source, "auth")) {
 		priv->load_state = E_CAL_LOAD_AUTHENTICATING;
 
 		if (priv->auth_func == NULL) {
@@ -1282,8 +1540,7 @@ open_calendar (ECal *ecal, gboolean only_if_exists, GError **error,
 			E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED, error);
 		}
 
-		username = e_source_get_duped_property (priv->source, "username");
-		if (!username) {
+		if (!e_source_get_property (priv->source, "username")) {
 			priv->load_state = E_CAL_LOAD_NOT_LOADED;
 			#ifndef E_CAL_DISABLE_DEPRECATED
 			*status = E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED;
@@ -1291,89 +1548,29 @@ open_calendar (ECal *ecal, gboolean only_if_exists, GError **error,
 			E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED, error);
 		}
 
-		prompt = g_strdup_printf (_("Enter password for %s (user %s)"),
-				e_source_peek_name (priv->source), username);
-
-		auth_type = e_source_get_duped_property (priv->source, "auth-type");
-		if (auth_type)
-			key = build_pass_key (ecal);
-		else {
-			parent_user = e_source_get_duped_property (priv->source, "parent_id_name");
-			if (parent_user) {
-				key = build_proxy_pass_key (ecal, parent_user);
-				/*
-				   This password prompt will be prompted rarely. Since the key that is passed to
-				   the auth_func corresponds to the parent user.
-				 */
-				prompt = g_strdup_printf (_("Enter password for %s to enable proxy for user %s"), e_source_peek_name (priv->source), parent_user);
-				g_free (parent_user);
-			} else
-				key = g_strdup (e_cal_get_uri (ecal));
-		}
-		g_free (auth_type);
-
-		if (!key) {
-			priv->load_state = E_CAL_LOAD_NOT_LOADED;
-			#ifndef E_CAL_DISABLE_DEPRECATED
-			*status = E_CALENDAR_STATUS_URI_NOT_LOADED;
-			#endif
-			E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED, error);
-		}
-
-		password = priv->auth_func (ecal, prompt, key, priv->auth_user_data);
-
-		if (!password) {
-			priv->load_state = E_CAL_LOAD_NOT_LOADED;
-			#ifndef E_CAL_DISABLE_DEPRECATED
-			*status = E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED;
-			#endif
-			E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_AUTHENTICATION_REQUIRED, error);
-		}
-
-		g_free (prompt);
-		g_free (key);
+		needs_auth = TRUE;
 	}
 
-	priv->load_state = E_CAL_LOAD_LOADING;
-
 	#ifndef E_CAL_DISABLE_DEPRECATED
 	*status = E_CALENDAR_STATUS_OK;
 	#endif
 	if (!async) {
-		gchar *gdbus_username = NULL, *gdbus_password = NULL;
-
-		if (!e_gdbus_cal_call_open_sync (priv->gdbus_cal, only_if_exists, e_util_ensure_gdbus_string (username, &gdbus_username), e_util_ensure_gdbus_string (password, &gdbus_password), NULL, error)) {
+		if (!e_gdbus_cal_call_open_sync (priv->gdbus_cal, only_if_exists, NULL, error)) {
 			#ifndef E_CAL_DISABLE_DEPRECATED
 			*status = E_CALENDAR_STATUS_DBUS_EXCEPTION;
 			#endif
+		} else if (needs_auth && !call_authenticate_user (ecal, FALSE, error)) {
+			#ifndef E_CAL_DISABLE_DEPRECATED
+			*status = error && *error ? (*error)->code : E_CALENDAR_STATUS_AUTHENTICATION_FAILED;
+			#endif
 		}
 		if (!*error)
 			priv->load_state = E_CAL_LOAD_LOADED;
-
-		g_free (gdbus_username);
-		g_free (gdbus_password);
 	} else {
-		gchar *gdbus_username = NULL, *gdbus_password = NULL;
-
-		e_gdbus_cal_call_open (priv->gdbus_cal, only_if_exists, e_util_ensure_gdbus_string (username, &gdbus_username), e_util_ensure_gdbus_string (password, &gdbus_password), NULL, (GAsyncReadyCallback) async_open_ready_cb, ecal);
-
-		g_free (gdbus_username);
-		g_free (gdbus_password);
+		e_gdbus_cal_call_open (priv->gdbus_cal, only_if_exists, NULL, (GAsyncReadyCallback) async_open_ready_cb, ecal);
 	}
 
-	g_free (password);
-	g_free (username);
-
-	if (!*error) {
-		if (!async) {
-			GError *err = NULL;
-
-			e_gdbus_cal_call_is_read_only_sync (ecal->priv->gdbus_cal, NULL, &err);
-
-			if (err)
-				g_error_free (err);
-		}
-	} else {
+	if (*error) {
 		unwrap_gerror (error);
 		priv->load_state = E_CAL_LOAD_NOT_LOADED;
 	}
@@ -1397,6 +1594,8 @@ open_calendar (ECal *ecal, gboolean only_if_exists, GError **error,
  * New signal deprecates the old "cal_opened" signal.
  *
  * Returns: TRUE on success, FALSE on failure to issue the open request.
+ *
+ * Deprecated: 3.2: Use e_client_open_sync() on an #ECalClient object instead.
  **/
 gboolean
 e_cal_open (ECal *ecal, gboolean only_if_exists, GError **error)
@@ -1478,6 +1677,9 @@ async_report_idle (ECal *ecal, GError *error)
  * Because this operation runs in another thread, any authentication
  * callback set on the calendar will be called from this other thread.
  * See #e_cal_set_auth_func() for details.
+ *
+ * Deprecated: 3.2: Use e_client_open()/e_client_open_finish()
+ * on an #ECalClient object instead.
  **/
 void
 e_cal_open_async (ECal *ecal, gboolean only_if_exists)
@@ -1526,6 +1728,8 @@ e_cal_open_async (ECal *ecal, gboolean only_if_exists)
  * Returns: TRUE if calendar supports refresh and it was invoked, FALSE otherwise.
  *
  * Since: 2.30
+ *
+ * Deprecated: 3.2: Use e_cal_client_refresh_sync() instead.
  **/
 gboolean
 e_cal_refresh (ECal *ecal, GError **error)
@@ -1551,6 +1755,8 @@ e_cal_refresh (ECal *ecal, GError **error)
  * Removes a calendar.
  *
  * Returns: TRUE if the calendar was removed, FALSE if there was an error.
+ *
+ * Deprecated: 3.2: Use e_client_remove_sync() on an #ECalClient object instead.
  */
 gboolean
 e_cal_remove (ECal *ecal, GError **error)
@@ -1591,6 +1797,8 @@ build_uri_list (GNOME_Evolution_Calendar_StringSeq *seq)
  * Retrieves a list of all calendar clients for the given mode.
  *
  * Returns: list of uris.
+ *
+ * Deprecated: 3.2: This function has been dropped completely.
  */
 GList *
 e_cal_uri_list (ECal *ecal, CalMode mode)
@@ -1642,6 +1850,8 @@ e_cal_uri_list (ECal *ecal, CalMode mode)
  *
  * Returns: an #ECalSourceType value corresponding to the type
  * of the calendar client.
+ *
+ * Deprecated: 3.2: Use e_cal_client_get_source_type() instead.
  */
 ECalSourceType
 e_cal_get_source_type (ECal *ecal)
@@ -1665,6 +1875,8 @@ e_cal_get_source_type (ECal *ecal)
  * Returns: A #ECalLoadState value indicating whether the client has
  * not been loaded with #e_cal_open yet, whether it is being
  * loaded, or whether it is already loaded.
+ *
+ * Deprecated: 3.2: Use e_client_is_opened() on an #ECalClient instead.
  **/
 ECalLoadState
 e_cal_get_load_state (ECal *ecal)
@@ -1686,6 +1898,8 @@ e_cal_get_load_state (ECal *ecal)
  *
  * Returns: The source of the calendar that is already loaded or is being
  * loaded, or NULL if the ecal has not started a load request yet.
+ *
+ * Deprecated: 3.2: Use e_client_get_source() on an #ECalClient object instead.
  **/
 ESource *
 e_cal_get_source (ECal *ecal)
@@ -1707,6 +1921,8 @@ e_cal_get_source (ECal *ecal)
  *
  * Returns: The URI of the calendar that is already loaded or is being
  * loaded, or NULL if the client has not started a load request yet.
+ *
+ * Deprecated: 3.2: Use e_client_get_uri() on an #ECalClient object instead.
  **/
 const gchar *
 e_cal_get_uri (ECal *ecal)
@@ -1732,6 +1948,8 @@ e_cal_get_uri (ECal *ecal)
  *
  * Returns: The URL where the attachments are serialized in the
  * local filesystem.
+ *
+ * Deprecated: 3.2: Use e_cal_client_get_local_attachment_store() instead.
  **/
 const gchar *
 e_cal_get_local_attachment_store (ECal *ecal)
@@ -1756,6 +1974,8 @@ e_cal_get_local_attachment_store (ECal *ecal)
  * is specified, on exit, in the @read_only argument.
  *
  * Returns: TRUE if the call was successful, FALSE if there was an error.
+ *
+ * Deprecated: 3.2: Use e_cal_client_is_readonly() on an #ECalClient object instead.
  */
 gboolean
 e_cal_is_read_only (ECal *ecal, gboolean *read_only, GError **error)
@@ -1781,6 +2001,9 @@ e_cal_is_read_only (ECal *ecal, gboolean *read_only, GError **error)
  *
  * Returns: TRUE if the operation was successful, FALSE if there
  * was an error.
+ *
+ * Deprecated: 3.2: Use e_client_get_backend_property_sync()
+ * with #CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS instead.
  **/
 gboolean
 e_cal_get_cal_address (ECal *ecal, gchar **cal_address, GError **error)
@@ -1801,7 +2024,7 @@ e_cal_get_cal_address (ECal *ecal, gchar **cal_address, GError **error)
 			E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
 		}
 
-		if (!e_gdbus_cal_call_get_cal_address_sync (priv->gdbus_cal, &priv->cal_address, NULL, error)) {
+		if (!e_gdbus_cal_call_get_backend_property_sync (priv->gdbus_cal, CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS, &priv->cal_address, NULL, error)) {
 			UNLOCK_CACHE ();
 			E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
 		}
@@ -1823,6 +2046,9 @@ e_cal_get_cal_address (ECal *ecal, gchar **cal_address, GError **error)
  *
  * Returns: TRUE if the operation was successful, FALSE if there was
  * an error while contacting the backend.
+ *
+ * Deprecated: 3.2: Use e_client_get_backend_property_sync()
+ * with #CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS instead.
  */
 gboolean
 e_cal_get_alarm_email_address (ECal *ecal, gchar **alarm_address, GError **error)
@@ -1839,7 +2065,7 @@ e_cal_get_alarm_email_address (ECal *ecal, gchar **alarm_address, GError **error
 		E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
 	}
 
-	if (!e_gdbus_cal_call_get_alarm_email_address_sync (priv->gdbus_cal, alarm_address, NULL, error)) {
+	if (!e_gdbus_cal_call_get_backend_property_sync (priv->gdbus_cal, CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS, alarm_address, NULL, error)) {
 		E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
 	}
 
@@ -1856,6 +2082,8 @@ e_cal_get_alarm_email_address (ECal *ecal, gchar **alarm_address, GError **error
  *
  * Returns: TRUE if the call was successful, FALSE if there was an
  * error contacting the backend.
+ *
+ * Deprecated: 3.2: This function has been dropped completely.
  */
 gboolean
 e_cal_get_ldap_attribute (ECal *ecal, gchar **ldap_attribute, GError **error)
@@ -1868,19 +2096,11 @@ e_cal_get_ldap_attribute (ECal *ecal, gchar **ldap_attribute, GError **error)
 	e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
 	*ldap_attribute = NULL;
 
-	if (priv->load_state != E_CAL_LOAD_LOADED) {
-		E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
-	}
-
-	if (!e_gdbus_cal_call_get_ldap_attribute_sync (priv->gdbus_cal, ldap_attribute, NULL, error)) {
-		E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
-	}
-
-	return TRUE;
+	E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_NOT_SUPPORTED, error);
 }
 
 static gboolean
-load_static_capabilities (ECal *ecal, GError **error)
+load_capabilities (ECal *ecal, GError **error)
 {
 	ECalPrivate *priv;
 
@@ -1898,7 +2118,7 @@ load_static_capabilities (ECal *ecal, GError **error)
 		E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
 	}
 
-	if (!e_gdbus_cal_call_get_scheduling_information_sync (priv->gdbus_cal, &priv->capabilities, NULL, error)) {
+	if (!e_gdbus_cal_call_get_backend_property_sync (priv->gdbus_cal, CLIENT_BACKEND_PROPERTY_CAPABILITIES, &priv->capabilities, NULL, error)) {
 		UNLOCK_CACHE ();
 		E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
 	}
@@ -1916,7 +2136,7 @@ check_capability (ECal *ecal, const gchar *cap)
 	priv = ecal->priv;
 
 	/* FIXME Check result */
-	load_static_capabilities (ecal, NULL);
+	load_capabilities (ecal, NULL);
 	if (priv->capabilities && strstr (priv->capabilities, cap))
 		return TRUE;
 
@@ -1930,6 +2150,8 @@ check_capability (ECal *ecal, const gchar *cap)
  * Checks if a calendar supports only one alarm per component.
  *
  * Returns: TRUE if the calendar allows only one alarm, FALSE otherwise.
+ *
+ * Deprecated: 3.2: Use e_cal_client_check_one_alarm_only() instead.
  */
 gboolean
 e_cal_get_one_alarm_only (ECal *ecal)
@@ -1948,6 +2170,8 @@ e_cal_get_one_alarm_only (ECal *ecal)
  *
  * Returns: TRUE if the calendar forces organizers to attend meetings,
  * FALSE otherwise.
+ *
+ * Deprecated: 3.2: Use e_cal_client_check_organizer_must_attend() instead.
  */
 gboolean
 e_cal_get_organizer_must_attend (ECal *ecal)
@@ -1966,6 +2190,8 @@ e_cal_get_organizer_must_attend (ECal *ecal)
  *
  * Returns: TRUE if the calendar has a master object for recurrences,
  * FALSE otherwise.
+ *
+ * Deprecated: 3.2: Use e_cal_client_check_recurrences_no_master() instead.
  */
 gboolean
 e_cal_get_recurrences_no_master (ECal *ecal)
@@ -1984,6 +2210,8 @@ e_cal_get_recurrences_no_master (ECal *ecal)
  * Queries the calendar for static capabilities.
  *
  * Returns: TRUE if the capability is supported, FALSE otherwise.
+ *
+ * Deprecated: 3.2: Use e_client_check_capability() on an #ECalClient object instead.
  */
 gboolean
 e_cal_get_static_capability (ECal *ecal, const gchar *cap)
@@ -2001,6 +2229,8 @@ e_cal_get_static_capability (ECal *ecal, const gchar *cap)
  * Checks whether the calendar saves schedules.
  *
  * Returns: TRUE if it saves schedules, FALSE otherwise.
+ *
+ * Deprecated: 3.2: Use e_cal_client_check_save_schedules() instead.
  */
 gboolean
 e_cal_get_save_schedules (ECal *ecal)
@@ -2020,6 +2250,8 @@ e_cal_get_save_schedules (ECal *ecal)
  *
  * Returns: TRUE if the calendar requires organizers to accept, FALSE
  * otherwise.
+ *
+ * Deprecated: 3.2: Use e_cal_client_check_organizer_must_accept() instead.
  */
 gboolean
 e_cal_get_organizer_must_accept (ECal *ecal)
@@ -2039,6 +2271,8 @@ e_cal_get_organizer_must_accept (ECal *ecal)
  * Returns: TRUE if the calendar supports refreshing, FALSE otherwise.
  *
  * Since: 2.30
+ *
+ * Deprecated: 3.2: Use e_client_check_refresh_supported() instead.
  */
 gboolean
 e_cal_get_refresh_supported (ECal *ecal)
@@ -2057,12 +2291,13 @@ e_cal_get_refresh_supported (ECal *ecal)
  * Switches online/offline mode on the calendar.
  *
  * Returns: TRUE if the switch was successful, FALSE if there was an error.
+ *
+ * Deprecated: 3.2: This function has been dropped completely.
  */
 gboolean
 e_cal_set_mode (ECal *ecal, CalMode mode)
 {
 	ECalPrivate *priv;
-	GError *error = NULL;
 
 	g_return_val_if_fail (ecal != NULL, FALSE);
 	g_return_val_if_fail (E_IS_CAL (ecal), FALSE);
@@ -2072,15 +2307,9 @@ e_cal_set_mode (ECal *ecal, CalMode mode)
 	g_return_val_if_fail (priv->gdbus_cal, FALSE);
 	g_return_val_if_fail (priv->load_state == E_CAL_LOAD_LOADED, FALSE);
 
-	if (!e_gdbus_cal_call_set_mode_sync (priv->gdbus_cal, mode, NULL, &error)) {
-		unwrap_gerror (&error);
-		g_printerr ("%s: %s\n", G_STRFUNC, error ? error->message : "Unknown error");
-		if (error)
-			g_error_free (error);
-		return FALSE;
-	}
+	g_debug ("%s: This function is not supported since 3.2", G_STRFUNC);
 
-	return TRUE;
+	return FALSE;
 }
 
 /* This is used in the callback which fetches all the timezones needed for an
@@ -2104,6 +2333,8 @@ struct _ECalGetTimezonesData {
  * values for properties needed.
  *
  * Returns: TRUE if the call was successful, FALSE otherwise.
+ *
+ * Deprecated: 3.2: Use e_cal_client_get_default_object_sync() instead.
  */
 gboolean
 e_cal_get_default_object (ECal *ecal, icalcomponent **icalcomp, GError **error)
@@ -2122,7 +2353,7 @@ e_cal_get_default_object (ECal *ecal, icalcomponent **icalcomp, GError **error)
 		E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
 	}
 
-	if (!e_gdbus_cal_call_get_default_object_sync (priv->gdbus_cal, &object, NULL, error)) {
+	if (!e_gdbus_cal_call_get_backend_property_sync (priv->gdbus_cal, CAL_BACKEND_PROPERTY_DEFAULT_OBJECT, &object, NULL, error)) {
 		E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
 	}
 
@@ -2154,6 +2385,8 @@ e_cal_get_default_object (ECal *ecal, icalcomponent **icalcomp, GError **error)
  * identifier and gets the attachments for the component.
  *
  * Returns: TRUE if the call was successful, FALSE otherwise.
+ *
+ * Deprecated: 3.2: Use e_cal_client_get_attachment_uris_sync() instead.
  **/
 gboolean
 e_cal_get_attachments_for_comp (ECal *ecal, const gchar *uid, const gchar *rid, GSList **list, GError **error)
@@ -2161,7 +2394,7 @@ e_cal_get_attachments_for_comp (ECal *ecal, const gchar *uid, const gchar *rid,
 	ECalPrivate *priv;
 	ECalendarStatus status;
 	gchar **list_array;
-	gchar *gdbus_uid = NULL, *gdbus_rid = NULL;
+	gchar **strv;
 
 	e_return_error_if_fail (uid != NULL, E_CALENDAR_STATUS_INVALID_ARG);
 	e_return_error_if_fail (list != NULL, E_CALENDAR_STATUS_INVALID_ARG);
@@ -2174,15 +2407,14 @@ e_cal_get_attachments_for_comp (ECal *ecal, const gchar *uid, const gchar *rid,
 		E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
 	}
 
-	if (!e_gdbus_cal_call_get_attachment_list_sync (priv->gdbus_cal, e_util_ensure_gdbus_string (uid, &gdbus_uid), e_util_ensure_gdbus_string (rid, &gdbus_rid), &list_array, NULL, error)) {
-		g_free (gdbus_uid);
-		g_free (gdbus_rid);
+	strv = e_gdbus_cal_encode_get_attachment_uris (uid, rid);
+	if (!e_gdbus_cal_call_get_attachment_uris_sync (priv->gdbus_cal, (const gchar * const *) strv, &list_array, NULL, error)) {
+		g_strfreev (strv);
 
 		E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
 	}
 
-	g_free (gdbus_uid);
-	g_free (gdbus_rid);
+	g_strfreev (strv);
 
 	if (list_array) {
 		gchar **string;
@@ -2209,13 +2441,15 @@ e_cal_get_attachments_for_comp (ECal *ecal, const gchar *uid, const gchar *rid,
  * identifier.
  *
  * Returns: TRUE if the call was successful, FALSE otherwise.
+ *
+ * Deprecated: 3.2: Use e_cal_client_get_object_sync() instead.
  **/
 gboolean
 e_cal_get_object (ECal *ecal, const gchar *uid, const gchar *rid, icalcomponent **icalcomp, GError **error)
 {
 	ECalPrivate *priv;
 	ECalendarStatus status;
-	gchar *object = NULL, *gdbus_uid = NULL, *gdbus_rid = NULL;
+	gchar *object = NULL, **strv;
 	icalcomponent *tmp_icalcomp;
 	icalcomponent_kind kind;
 
@@ -2230,15 +2464,14 @@ e_cal_get_object (ECal *ecal, const gchar *uid, const gchar *rid, icalcomponent
 		E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
 	}
 
-	if (!e_gdbus_cal_call_get_object_sync (priv->gdbus_cal, e_util_ensure_gdbus_string (uid, &gdbus_uid), e_util_ensure_gdbus_string (rid, &gdbus_rid), &object, NULL, error)) {
-		g_free (gdbus_uid);
-		g_free (gdbus_rid);
+	strv = e_gdbus_cal_encode_get_object (uid, rid);
+	if (!e_gdbus_cal_call_get_object_sync (priv->gdbus_cal, (const gchar * const *) strv, &object, NULL, error)) {
+		g_strfreev (strv);
 
 		E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
 	}
 
-	g_free (gdbus_uid);
-	g_free (gdbus_rid);
+	g_strfreev (strv);
 
 	status = E_CALENDAR_STATUS_OK;
 	tmp_icalcomp = icalparser_parse_string (object);
@@ -2294,13 +2527,15 @@ e_cal_get_object (ECal *ecal, const gchar *uid, const gchar *rid, icalcomponent
  * For non-recurring events, it will just return the object with that ID.
  *
  * Returns: TRUE if the call was successful, FALSE otherwise.
+ *
+ * Deprecated: 3.2: Use e_cal_client_get_objects_for_uid_sync() instead.
  **/
 gboolean
 e_cal_get_objects_for_uid (ECal *ecal, const gchar *uid, GList **objects, GError **error)
 {
 	ECalPrivate *priv;
 	ECalendarStatus status;
-	gchar *object = NULL, *gdbus_uid = NULL;
+	gchar *object = NULL, **strv;
 
 	e_return_error_if_fail (uid != NULL, E_CALENDAR_STATUS_INVALID_ARG);
 	e_return_error_if_fail (objects != NULL, E_CALENDAR_STATUS_INVALID_ARG);
@@ -2313,13 +2548,14 @@ e_cal_get_objects_for_uid (ECal *ecal, const gchar *uid, GList **objects, GError
 		E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
 	}
 
-	if (!e_gdbus_cal_call_get_object_sync (priv->gdbus_cal, e_util_ensure_gdbus_string (uid, &gdbus_uid), "", &object, NULL, error)) {
-		g_free (gdbus_uid);
+	strv = e_gdbus_cal_encode_get_object (uid, "");
+	if (!e_gdbus_cal_call_get_object_sync (priv->gdbus_cal, (const gchar * const *) strv, &object, NULL, error)) {
+		g_strfreev (strv);
 
 		E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
 	}
 
-	g_free (gdbus_uid);
+	g_strfreev (strv);
 
 	status = E_CALENDAR_STATUS_OK;
 	{
@@ -2384,6 +2620,8 @@ e_cal_get_objects_for_uid (ECal *ecal, const gchar *uid, GList **objects, GError
  *
  * Returns: The timezone identified by the @tzid argument, or %NULL if
  * it could not be found.
+ *
+ * Deprecated: 3.2: Use e_cal_client_resolve_tzid_cb() instead.
  */
 icaltimezone*
 e_cal_resolve_tzid_cb (const gchar *tzid, gpointer data)
@@ -2414,13 +2652,13 @@ e_cal_resolve_tzid_cb (const gchar *tzid, gpointer data)
  * compute the changes done.
  *
  * Returns: TRUE if the call was successful, FALSE otherwise.
+ *
+ * Deprecated: 3.2: This function has been dropped completely.
  */
 gboolean
 e_cal_get_changes (ECal *ecal, const gchar *change_id, GList **changes, GError **error)
 {
 	ECalPrivate *priv;
-	gchar **additions = NULL, **modifications = NULL, **removals = NULL;
-	gchar *gdbus_change_id = NULL;
 
 	e_return_error_if_fail (changes != NULL, E_CALENDAR_STATUS_INVALID_ARG);
 	e_return_error_if_fail (change_id != NULL, E_CALENDAR_STATUS_INVALID_ARG);
@@ -2429,71 +2667,7 @@ e_cal_get_changes (ECal *ecal, const gchar *change_id, GList **changes, GError *
 	e_return_error_if_fail (priv->gdbus_cal, E_CALENDAR_STATUS_REPOSITORY_OFFLINE);
 	*changes = NULL;
 
-	if (priv->load_state != E_CAL_LOAD_LOADED) {
-		E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
-	}
-
-	if (!e_gdbus_cal_call_get_changes_sync (priv->gdbus_cal, e_util_ensure_gdbus_string (change_id, &gdbus_change_id), &additions, &modifications, &removals, NULL, error)) {
-		g_free (gdbus_change_id);
-
-		E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
-	}
-
-	g_free (gdbus_change_id);
-
-	/* TODO: Be more elegant and split this into a function */
-	/* Mostly copied from the old e-cal-listener.c */
-	if ((additions)&&(modifications)&&(removals)) {
-		gint i;
-		gchar **list = NULL, **l;
-		ECalChangeType change_type = E_CAL_CHANGE_ADDED;
-		icalcomponent *icalcomp;
-		ECalChange *change;
-
-		for (i = 0; i < 3; i++) {
-			switch (i) {
-			case 0:
-				change_type = E_CAL_CHANGE_ADDED;
-				list = additions;
-				break;
-			case 1:
-				change_type = E_CAL_CHANGE_MODIFIED;
-				list = modifications;
-				break;
-			case 2:
-				change_type = E_CAL_CHANGE_DELETED;
-				list = removals;
-			}
-
-			for (l = list; *l; l++) {
-				icalcomp = icalparser_parse_string (*l);
-				if (!icalcomp)
-					continue;
-				change = g_new (ECalChange, 1);
-				change->comp = e_cal_component_new ();
-				if (!e_cal_component_set_icalcomponent (change->comp, icalcomp)) {
-					icalcomponent_free (icalcomp);
-					g_object_unref (G_OBJECT (change->comp));
-					g_free (change);
-					continue;
-				}
-				change->type = change_type;
-				*changes = g_list_append (*changes, change);
-			}
-		}
-
-		g_strfreev (additions);
-		g_strfreev (modifications);
-		g_strfreev (removals);
-	} else {
-		g_strfreev (additions);
-		g_strfreev (modifications);
-		g_strfreev (removals);
-
-		E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OTHER_ERROR, error);
-	}
-
-	E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
+	E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_NOT_SUPPORTED, error);
 }
 
 /**
@@ -2501,6 +2675,8 @@ e_cal_get_changes (ECal *ecal, const gchar *change_id, GList **changes, GError *
  * @list: List of changes to be freed.
  *
  * Free a list of changes as returned by #e_cal_get_changes.
+ *
+ * Deprecated: 3.2: Use () instead.
  */
 void
 e_cal_free_change_list (GList *list)
@@ -2534,6 +2710,8 @@ e_cal_free_change_list (GList *list)
  * should be freed by using the #e_cal_free_object_list function.
  *
  * Returns: TRUE if the operation was successful, FALSE otherwise.
+ *
+ * Deprecated: 3.2: Use e_cal_client_get_object_list_sync() instead.
  **/
 gboolean
 e_cal_get_object_list (ECal *ecal, const gchar *query, GList **objects, GError **error)
@@ -2589,6 +2767,8 @@ e_cal_get_object_list (ECal *ecal, const gchar *query, GList **objects, GError *
  * argument, which is a list of #ECalComponent.
  *
  * Returns: TRUE if the operation was successful, FALSE otherwise.
+ *
+ * Deprecated: 3.2: Use e_cal_client_get_object_list_as_comps_sync() instead.
  */
 gboolean
 e_cal_get_object_list_as_comp (ECal *ecal, const gchar *query, GList **objects, GError **error)
@@ -2623,6 +2803,8 @@ e_cal_get_object_list_as_comp (ECal *ecal, const gchar *query, GList **objects,
  * @objects: List of objects to be freed.
  *
  * Frees a list of objects as returned by #e_cal_get_object_list.
+ *
+ * Deprecated: 3.2: Use e_cal_client_free_icalcomp_slist() instead.
  */
 void
 e_cal_free_object_list (GList *objects)
@@ -2635,40 +2817,6 @@ e_cal_free_object_list (GList *objects)
 	g_list_free (objects);
 }
 
-static GList *
-build_free_busy_list (const gchar **seq)
-{
-	GList *list = NULL;
-	gint i;
-
-	/* Create the list in reverse order */
-	for (i = 0; seq[i]; i++) {
-		ECalComponent *comp;
-		icalcomponent *icalcomp;
-		icalcomponent_kind kind;
-
-		icalcomp = icalcomponent_new_from_string ((gchar *) seq[i]);
-		if (!icalcomp)
-			continue;
-
-		kind = icalcomponent_isa (icalcomp);
-		if (kind == ICAL_VFREEBUSY_COMPONENT) {
-			comp = e_cal_component_new ();
-			if (!e_cal_component_set_icalcomponent (comp, icalcomp)) {
-				icalcomponent_free (icalcomp);
-				g_object_unref (G_OBJECT (comp));
-				continue;
-			}
-
-			list = g_list_append (list, comp);
-		} else {
-			icalcomponent_free (icalcomp);
-		}
-	}
-
-	return list;
-}
-
 /**
  * e_cal_get_free_busy
  * @ecal: A calendar client.
@@ -2681,16 +2829,17 @@ build_free_busy_list (const gchar **seq)
  * Gets free/busy information from the calendar server.
  *
  * Returns: TRUE if the operation was successful, FALSE otherwise.
+ *
+ * Deprecated: 3.2: Use e_cal_client_get_free_busy_sync() instead.
  */
 gboolean
 e_cal_get_free_busy (ECal *ecal, GList *users, time_t start, time_t end,
 		     GList **freebusy, GError **error)
 {
 	ECalPrivate *priv;
-	gchar **users_list;
-	gchar **freebusy_array = NULL;
+	gchar **strv;
+	GSList *susers;
 	GList *l;
-	gint i;
 
 	e_return_error_if_fail (users != NULL, E_CALENDAR_STATUS_INVALID_ARG);
 	e_return_error_if_fail (freebusy != NULL, E_CALENDAR_STATUS_INVALID_ARG);
@@ -2703,22 +2852,33 @@ e_cal_get_free_busy (ECal *ecal, GList *users, time_t start, time_t end,
 		E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
 	}
 
-	users_list = g_new0 (gchar *, g_list_length (users) + 1);
-	for (l = users, i = 0; l; l = l->next, i++)
-		users_list[i] = e_util_utf8_make_valid (l->data);
+	susers = NULL;
+	for (l = users; l; l = l->next) {
+		susers = g_slist_prepend (susers, l->data);
+	}
+	susers = g_slist_reverse (susers);
+	strv = e_gdbus_cal_encode_get_free_busy (start, end, susers);
+	g_slist_free (susers);
+
+	g_mutex_lock (priv->free_busy_data_lock);
+	priv->free_busy_data = freebusy;
+	g_mutex_unlock (priv->free_busy_data_lock);
+
+	if (!e_gdbus_cal_call_get_free_busy_sync (priv->gdbus_cal, (const gchar * const *) strv, NULL, error)) {
+		g_strfreev (strv);
+		g_mutex_lock (priv->free_busy_data_lock);
+		priv->free_busy_data = NULL;
+		g_mutex_unlock (priv->free_busy_data_lock);
 
-	if (!e_gdbus_cal_call_get_free_busy_sync (priv->gdbus_cal, (const gchar * const *) users_list, start, end, &freebusy_array, NULL, error)) {
-		g_strfreev (users_list);
 		E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
 	}
-	g_strfreev (users_list);
+	g_strfreev (strv);
 
-	if (freebusy_array) {
-		*freebusy = build_free_busy_list ((const gchar **) freebusy_array);
-		g_strfreev (freebusy_array);
-		E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
-	} else
-		E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OTHER_ERROR, error);
+	g_mutex_lock (priv->free_busy_data_lock);
+	priv->free_busy_data = NULL;
+	g_mutex_unlock (priv->free_busy_data_lock);
+
+	E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
 }
 
 struct comp_instance {
@@ -3112,6 +3272,8 @@ try_again:
  * The callback function should do a g_object_ref() of the calendar component
  * it gets passed if it intends to keep it around, since it will be unref'ed
  * as soon as the callback returns.
+ *
+ * Deprecated: 3.2: Use e_cal_client_generate_instances() instead.
  **/
 void
 e_cal_generate_instances (ECal *ecal, time_t start, time_t end,
@@ -3148,6 +3310,8 @@ e_cal_generate_instances (ECal *ecal, time_t start, time_t end,
  * The callback function should do a g_object_ref() of the calendar component
  * it gets passed if it intends to keep it around, since it will be unref'ed
  * as soon as the callback returns.
+ *
+ * Deprecated: 3.2: Use e_cal_client_generate_instances_for_object() instead.
  **/
 void
 e_cal_generate_instances_for_object (ECal *ecal, icalcomponent *icalcomp,
@@ -3275,6 +3439,8 @@ build_component_alarms_list (ECal *ecal, GList *object_list, time_t start, time_
  * using the #e_cal_free_alarms() function, or by freeing each element
  * separately with #e_cal_component_alarms_free() and then freeing the list with
  * #g_slist_free().
+ *
+ * Deprecated: 3.2: This function has been dropped completely.
  **/
 GSList *
 e_cal_get_alarms_in_range (ECal *ecal, time_t start, time_t end)
@@ -3330,6 +3496,8 @@ e_cal_get_alarms_in_range (ECal *ecal, time_t start, time_t end)
  *
  * Frees a list of #ECalComponentAlarms structures as returned by
  * e_cal_get_alarms_in_range().
+ *
+ * Deprecated: 3.2: This function has been dropped completely.
  **/
 void
 e_cal_free_alarms (GSList *comp_alarms)
@@ -3363,6 +3531,8 @@ e_cal_free_alarms (GSList *comp_alarms)
  * specified range of time.
  *
  * Returns: TRUE on success, FALSE if the object was not found.
+ *
+ * Deprecated: 3.2: This function has been dropped completely.
  **/
 gboolean
 e_cal_get_alarms_for_object (ECal *ecal, const ECalComponentId *id,
@@ -3418,13 +3588,13 @@ e_cal_get_alarms_for_object (ECal *ecal, const ECalComponentId *id,
  * the file backend does, ignore the operation.
  *
  * Returns: TRUE if the operation was successful, FALSE otherwise.
+ *
+ * Deprecated: 3.2: Use e_cal_client_discard_alarm_sync() instead.
  */
 gboolean
 e_cal_discard_alarm (ECal *ecal, ECalComponent *comp, const gchar *auid, GError **error)
 {
 	ECalPrivate *priv;
-	const gchar *uid = NULL;
-	gchar *gdbus_uid = NULL, *gdbus_auid = NULL;
 
 	e_return_error_if_fail (ecal != NULL, E_CALENDAR_STATUS_INVALID_ARG);
 	e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
@@ -3438,19 +3608,7 @@ e_cal_discard_alarm (ECal *ecal, ECalComponent *comp, const gchar *auid, GError
 		E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
 	}
 
-	e_cal_component_get_uid (comp, &uid);
-
-	if (!e_gdbus_cal_call_discard_alarm_sync (priv->gdbus_cal, e_util_ensure_gdbus_string (uid, &gdbus_uid), e_util_ensure_gdbus_string (auid, &gdbus_auid), NULL, error)) {
-		g_free (gdbus_uid);
-		g_free (gdbus_auid);
-
-		E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
-	}
-
-	g_free (gdbus_uid);
-	g_free (gdbus_auid);
-
-	E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
+	E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_NOT_SUPPORTED, error);
 }
 
 typedef struct _ForeachTZIDCallbackData ForeachTZIDCallbackData;
@@ -3612,6 +3770,8 @@ e_cal_get_component_as_string_internal (ECal *ecal,
  *
  * Returns: the component as a complete iCalendar string, or NULL on
  * failure. The string should be freed after use.
+ *
+ * Deprecated: 3.2: Use e_cal_client_get_component_as_string() instead.
  **/
 gchar *
 e_cal_get_component_as_string (ECal *ecal, icalcomponent *icalcomp)
@@ -3631,6 +3791,8 @@ e_cal_get_component_as_string (ECal *ecal, icalcomponent *icalcomp)
  * in those cases that UID would be returned in the @uid argument.
  *
  * Returns: TRUE if the operation was successful, FALSE otherwise.
+ *
+ * Deprecated: 3.2: Use e_cal_client_create_object_sync() instead.
  */
 gboolean
 e_cal_create_object (ECal *ecal, icalcomponent *icalcomp, gchar **uid, GError **error)
@@ -3689,12 +3851,14 @@ e_cal_create_object (ECal *ecal, icalcomponent *icalcomp, gchar **uid, GError **
  * CALOBJ_MOD_THISANDFUTURE).
  *
  * Returns: TRUE if the operation was successful, FALSE otherwise.
+ *
+ * Deprecated: 3.2: Use e_cal_client_modify_object_sync() instead.
  */
 gboolean
 e_cal_modify_object (ECal *ecal, icalcomponent *icalcomp, CalObjModType mod, GError **error)
 {
 	ECalPrivate *priv;
-	gchar *obj, *gdbus_obj = NULL;
+	gchar *obj, **strv;
 
 	e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
 	e_return_error_if_fail (icalcomp, E_CALENDAR_STATUS_INVALID_ARG);
@@ -3708,15 +3872,16 @@ e_cal_modify_object (ECal *ecal, icalcomponent *icalcomp, CalObjModType mod, GEr
 	}
 
 	obj = icalcomponent_as_ical_string_r (icalcomp);
-	if (!e_gdbus_cal_call_modify_object_sync (priv->gdbus_cal, e_util_ensure_gdbus_string (obj, &gdbus_obj), mod, NULL, error)) {
+	strv = e_gdbus_cal_encode_modify_object (obj, mod);
+	if (!e_gdbus_cal_call_modify_object_sync (priv->gdbus_cal, (const gchar * const *) strv, NULL, error)) {
 		g_free (obj);
-		g_free (gdbus_obj);
+		g_strfreev (strv);
 
 		E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
 	}
 
 	g_free (obj);
-	g_free (gdbus_obj);
+	g_strfreev (strv);
 
 	E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
 }
@@ -3739,13 +3904,15 @@ e_cal_modify_object (ECal *ecal, icalcomponent *icalcomp, CalObjModType mod, GEr
  * are removed.
  *
  * Returns: TRUE if the operation was successful, FALSE otherwise.
+ *
+ * Deprecated: 3.2: Use e_cal_client_remove_object_sync() instead.
  */
 gboolean
 e_cal_remove_object_with_mod (ECal *ecal, const gchar *uid,
 			      const gchar *rid, CalObjModType mod, GError **error)
 {
 	ECalPrivate *priv;
-	gchar *gdbus_uid = NULL, *gdbus_rid = NULL;
+	gchar **strv;
 
 	e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
 	e_return_error_if_fail (uid, E_CALENDAR_STATUS_INVALID_ARG);
@@ -3757,15 +3924,14 @@ e_cal_remove_object_with_mod (ECal *ecal, const gchar *uid,
 		E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
 	}
 
-	if (!e_gdbus_cal_call_remove_object_sync (priv->gdbus_cal, e_util_ensure_gdbus_string (uid, &gdbus_uid), e_util_ensure_gdbus_string (rid, &gdbus_rid), mod, NULL, error)) {
-		g_free (gdbus_uid);
-		g_free (gdbus_rid);
+	strv = e_gdbus_cal_encode_remove_object (uid, rid, mod);
+	if (!e_gdbus_cal_call_remove_object_sync (priv->gdbus_cal, (const gchar * const *) strv, NULL, error)) {
+		g_strfreev (strv);
 
 		E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
 	}
 
-	g_free (gdbus_uid);
-	g_free (gdbus_rid);
+	g_strfreev (strv);
 
 	E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
 }
@@ -3781,6 +3947,8 @@ e_cal_remove_object_with_mod (ECal *ecal, const gchar *uid,
  * signal.
  *
  * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Deprecated: 3.2: Use e_cal_client_remove_object_sync() instead, with rid set to NULL and mod set to CALOBJ_MOD_THIS.
  **/
 gboolean
 e_cal_remove_object (ECal *ecal, const gchar *uid, GError **error)
@@ -3802,6 +3970,8 @@ e_cal_remove_object (ECal *ecal, const gchar *uid, GError **error)
  * messages for scheduled meetings.
  *
  * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Deprecated: 3.2: Use e_cal_client_receive_objects_sync() instead.
  */
 gboolean
 e_cal_receive_objects (ECal *ecal, icalcomponent *icalcomp, GError **error)
@@ -3846,14 +4016,16 @@ e_cal_receive_objects (ECal *ecal, icalcomponent *icalcomp, GError **error)
  * of users.
  *
  * Returns: TRUE if the operation was successful, FALSE otherwise.
+ *
+ * Deprecated: 3.2: Use e_cal_client_send_objects_sync() instead.
  */
 gboolean
 e_cal_send_objects (ECal *ecal, icalcomponent *icalcomp, GList **users, icalcomponent **modified_icalcomp, GError **error)
 {
 	ECalPrivate *priv;
 	ECalendarStatus status;
-	gchar **users_array = NULL;
-	gchar *object = NULL, *obj, *gdbus_obj = NULL;
+	gchar **out_array = NULL;
+	gchar *obj, *gdbus_obj = NULL;
 
 	e_return_error_if_fail (users != NULL, E_CALENDAR_STATUS_INVALID_ARG);
 	e_return_error_if_fail (modified_icalcomp != NULL, E_CALENDAR_STATUS_INVALID_ARG);
@@ -3870,7 +4042,7 @@ e_cal_send_objects (ECal *ecal, icalcomponent *icalcomp, GList **users, icalcomp
 	}
 
 	obj = icalcomponent_as_ical_string_r (icalcomp);
-	if (!e_gdbus_cal_call_send_objects_sync (priv->gdbus_cal, e_util_ensure_gdbus_string (obj, &gdbus_obj), &users_array, &object, NULL, error)) {
+	if (!e_gdbus_cal_call_send_objects_sync (priv->gdbus_cal, e_util_ensure_gdbus_string (obj, &gdbus_obj), &out_array, NULL, error)) {
 		g_free (obj);
 		g_free (gdbus_obj);
 
@@ -3881,15 +4053,24 @@ e_cal_send_objects (ECal *ecal, icalcomponent *icalcomp, GList **users, icalcomp
 	g_free (gdbus_obj);
 
 	status = E_CALENDAR_STATUS_OK;
-	if (users_array) {
-		gchar **user;
+	if (out_array) {
+		GSList *susers = NULL, *iter;
+		gchar *object = NULL;
+
+		e_return_error_if_fail (e_gdbus_cal_decode_send_objects ((const gchar * const *) out_array, &object, &susers), E_CALENDAR_STATUS_OTHER_ERROR);
+
 		*modified_icalcomp = icalparser_parse_string (object);
 		if (!(*modified_icalcomp))
 			status = E_CALENDAR_STATUS_INVALID_OBJECT;
 
-		for (user = users_array; *user; user++)
-			*users = g_list_append (*users, g_strdup (*user));
-		g_strfreev (users_array);
+		*users = NULL;
+		for (iter = susers; iter; iter = iter->next) {
+			*users = g_list_append (*users, iter->data);
+		}
+		/* do not call g_free() on item's data of susers, it's moved to *users */
+		g_slist_free (susers);
+		g_strfreev (out_array);
+		g_free (object);
 	} else
 		E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OTHER_ERROR, error);
 
@@ -3906,6 +4087,8 @@ e_cal_send_objects (ECal *ecal, icalcomponent *icalcomp, GList **users, icalcomp
  * Retrieves a timezone object from the calendar backend.
  *
  * Returns: TRUE if the operation was successful, FALSE otherwise.
+ *
+ * Deprecated: 3.2: Use e_cal_client_get_timezone_sync() instead.
  */
 gboolean
 e_cal_get_timezone (ECal *ecal, const gchar *tzid, icaltimezone **zone, GError **error)
@@ -4027,6 +4210,8 @@ e_cal_get_timezone (ECal *ecal, const gchar *tzid, icaltimezone **zone, GError *
  * Add a VTIMEZONE object to the given calendar.
  *
  * Returns: TRUE if successful, FALSE otherwise.
+ *
+ * Deprecated: 3.2: Use e_cal_client_add_timezone_sync() instead.
  */
 gboolean
 e_cal_add_timezone (ECal *ecal, icaltimezone *izone, GError **error)
@@ -4083,6 +4268,8 @@ e_cal_add_timezone (ECal *ecal, icaltimezone *izone, GError **error)
  *
  * Returns: A query object that will emit notification signals as calendar
  * components are added and removed from the query in the server.
+ *
+ * Deprecated: 3.2: Use e_cal_client_get_view_sync() instead.
  **/
 gboolean
 e_cal_get_query (ECal *ecal, const gchar *sexp, ECalView **query, GError **error)
@@ -4103,7 +4290,7 @@ e_cal_get_query (ECal *ecal, const gchar *sexp, ECalView **query, GError **error
 		E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_URI_NOT_LOADED, error);
 	}
 
-	if (!e_gdbus_cal_call_get_query_sync (priv->gdbus_cal, e_util_ensure_gdbus_string (sexp, &gdbus_sexp), &query_path, NULL, error)) {
+	if (!e_gdbus_cal_call_get_view_sync (priv->gdbus_cal, e_util_ensure_gdbus_string (sexp, &gdbus_sexp), &query_path, NULL, error)) {
 		g_free (gdbus_sexp);
 
 		E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
@@ -4143,13 +4330,13 @@ e_cal_get_query (ECal *ecal, const gchar *sexp, ECalView **query, GError **error
  * the calendar.
  *
  * Returns: TRUE if the operation was successful, FALSE otherwise.
+ *
+ * Deprecated: 3.2: Use e_cal_client_set_default_timezone() instead.
  */
 gboolean
 e_cal_set_default_timezone (ECal *ecal, icaltimezone *zone, GError **error)
 {
 	ECalPrivate *priv;
-	icalcomponent *icalcomp = NULL;
-	gchar *tzobj, *gdbus_tzobj = NULL;
 
 	e_return_error_if_fail (E_IS_CAL (ecal), E_CALENDAR_STATUS_INVALID_ARG);
 	e_return_error_if_fail (zone, E_CALENDAR_STATUS_INVALID_ARG);
@@ -4161,25 +4348,10 @@ e_cal_set_default_timezone (ECal *ecal, icaltimezone *zone, GError **error)
 		return TRUE;
 
 	/* FIXME Adding it to the server to change the tzid */
-	icalcomp = icaltimezone_get_component (zone);
-	if (!icalcomp) {
+	if (!icaltimezone_get_component (zone)) {
 		E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_INVALID_ARG, error);
 	}
 
-	/* convert icaltimezone into a string */
-	tzobj = icalcomponent_as_ical_string_r (icalcomp);
-
-	/* call the backend */
-	if (!e_gdbus_cal_call_set_default_timezone_sync (priv->gdbus_cal, e_util_ensure_gdbus_string (tzobj, &gdbus_tzobj), NULL, error)) {
-		g_free (tzobj);
-		g_free (gdbus_tzobj);
-
-		E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_DBUS_EXCEPTION, error);
-	}
-
-	g_free (tzobj);
-	g_free (gdbus_tzobj);
-
 	priv->default_zone = zone;
 
 	E_CALENDAR_CHECK_STATUS (E_CALENDAR_STATUS_OK, error);
@@ -4192,6 +4364,8 @@ e_cal_set_default_timezone (ECal *ecal, icaltimezone *zone, GError **error)
  * Gets an error message for the given status code.
  *
  * Returns: the error message.
+ *
+ * Deprecated: 3.2: Use e_cal_client_error_to_string() instead.
  */
 const gchar *
 e_cal_get_error_message (ECalendarStatus status)
@@ -4257,6 +4431,9 @@ e_cal_get_error_message (ECalendarStatus status)
  * Opens the default calendar.
  *
  * Returns: TRUE if it opened correctly, FALSE otherwise.
+ *
+ * Deprecated: 3.2: Use e_cal_client_new_default_calendar() instead
+ * and open it on your own.
  */
 gboolean
 e_cal_open_default (ECal **ecal,
@@ -4318,6 +4495,8 @@ e_cal_open_default (ECal **ecal,
  * Sets a calendar as the default one.
  *
  * Returns: TRUE if the operation was successful, FALSE otherwise.
+ *
+ * Deprecated: 3.2: Use e_cal_client_set_default() instead.
  */
 gboolean
 e_cal_set_default (ECal *ecal, GError **error)
@@ -4387,6 +4566,8 @@ set_default_source (ESourceList *sources, ESource *source, GError **error)
  * Sets the default source for the specified @type.
  *
  * Returns: TRUE if the operation was successful, FALSE otherwise.
+ *
+ * Deprecated: 3.2: Use e_cal_client_set_default_source() instead.
  */
 gboolean
 e_cal_set_default_source (ESource *source, ECalSourceType type, GError **error)
@@ -4422,6 +4603,8 @@ get_sources (ESourceList **sources, const gchar *key, GError **error)
  * Gets the list of sources defined in the configuration for the given @type.
  *
  * Returns: TRUE if the operation was successful, FALSE otherwise.
+ *
+ * Deprecated: 3.2: Use e_cal_client_get_sources() instead.
  */
 gboolean
 e_cal_get_sources (ESourceList **sources, ECalSourceType type, GError **error)
diff --git a/calendar/libecal/e-cal.h b/calendar/libecal/e-cal.h
index ea599d5..a1dc014 100644
--- a/calendar/libecal/e-cal.h
+++ b/calendar/libecal/e-cal.h
@@ -22,6 +22,8 @@
 #ifndef E_CAL_H
 #define E_CAL_H
 
+#ifndef E_CAL_DISABLE_DEPRECATED
+
 #include <glib-object.h>
 #include "libedataserver/e-source-list.h"
 #include "libedataserver/e-source.h"
@@ -70,6 +72,14 @@ typedef enum {
 	E_CAL_LOAD_LOADED
 } ECalLoadState;
 
+#ifndef E_CAL_DISABLE_DEPRECATED
+typedef enum {
+	Local = 1 << 0,
+	Remote = 1 << 1,
+	AnyMode = 0x07
+} EDataCalMode;
+#endif
+
 struct _ECal {
 	GObject object;
 
@@ -215,4 +225,6 @@ gboolean e_cal_get_attachments_for_comp (ECal *ecal, const gchar *uid, const gch
 
 G_END_DECLS
 
+#endif /* E_CAL_DISABLE_DEPRECATED */
+
 #endif
diff --git a/calendar/libedata-cal/e-cal-backend-sexp.c b/calendar/libedata-cal/e-cal-backend-sexp.c
index 729285f..2908037 100644
--- a/calendar/libedata-cal/e-cal-backend-sexp.c
+++ b/calendar/libedata-cal/e-cal-backend-sexp.c
@@ -382,9 +382,7 @@ func_occur_in_time_range (ESExp *esexp, gint argc, ESExpResult **argv, gpointer
 	end = argv[1]->value.time;
 
 	/* See if the object occurs in the specified time range */
-	default_zone = e_cal_backend_internal_get_default_timezone (ctx->backend);
-	if (!default_zone)
-		default_zone = icaltimezone_get_utc_timezone ();
+	default_zone = icaltimezone_get_utc_timezone ();
 
 	ctx->occurs = FALSE;
 	e_cal_recur_generate_instances (ctx->comp, start, end,
@@ -883,9 +881,7 @@ func_has_alarms_in_range (ESExp *esexp, gint argc, ESExpResult **argv, gpointer
 	end = argv[1]->value.time;
 
 	/* See if the object has alarms in the given time range */
-	default_zone = e_cal_backend_internal_get_default_timezone (ctx->backend);
-	if (!default_zone)
-		default_zone = icaltimezone_get_utc_timezone ();
+	default_zone = icaltimezone_get_utc_timezone ();
 
 	alarms = e_cal_util_generate_alarms_for_comp (ctx->comp, start, end,
 						      omit, resolve_tzid,
diff --git a/calendar/libedata-cal/e-cal-backend-sync.c b/calendar/libedata-cal/e-cal-backend-sync.c
index 8264719..5c06864 100644
--- a/calendar/libedata-cal/e-cal-backend-sync.c
+++ b/calendar/libedata-cal/e-cal-backend-sync.c
@@ -21,15 +21,25 @@ struct _ECalBackendSyncPrivate {
 	gboolean mutex_lock;
 };
 
-#define LOCK_WRAPPER(func, args) \
-  g_assert (E_CAL_BACKEND_SYNC_GET_CLASS (backend)->func); \
-  if (backend->priv->mutex_lock) \
-    g_mutex_lock (backend->priv->sync_mutex); \
-  (* E_CAL_BACKEND_SYNC_GET_CLASS (backend)->func) args; \
-  if (backend->priv->mutex_lock) \
-    g_mutex_unlock (backend->priv->sync_mutex); \
-
-static GObjectClass *parent_class;
+#define LOCK_WRAPPER(func, args) G_STMT_START {									\
+	gboolean locked = backend->priv->mutex_lock;								\
+	e_return_data_cal_error_if_fail (E_CAL_BACKEND_SYNC_GET_CLASS (backend)->func, NotSupported);		\
+	if (locked)												\
+		g_mutex_lock (backend->priv->sync_mutex);							\
+	(* E_CAL_BACKEND_SYNC_GET_CLASS (backend)->func) args;							\
+	if (locked)												\
+		g_mutex_unlock (backend->priv->sync_mutex);							\
+	} G_STMT_END
+
+#define LOCK_WRAPPER_RET_VAL(func, args) G_STMT_START {								\
+	gboolean locked = backend->priv->mutex_lock;								\
+	e_return_data_cal_error_val_if_fail (E_CAL_BACKEND_SYNC_GET_CLASS (backend)->func, NotSupported);	\
+	if (locked)												\
+		g_mutex_lock (backend->priv->sync_mutex);							\
+	res = (* E_CAL_BACKEND_SYNC_GET_CLASS (backend)->func) args;						\
+	if (locked)												\
+		g_mutex_unlock (backend->priv->sync_mutex);							\
+	} G_STMT_END
 
 /**
  * e_cal_backend_sync_set_lock:
@@ -50,174 +60,230 @@ e_cal_backend_sync_set_lock (ECalBackendSync *backend, gboolean lock)
 }
 
 /**
- * e_cal_backend_sync_is_read_only:
+ * e_cal_backend_sync_open:
  * @backend: An ECalBackendSync object.
  * @cal: An EDataCal object.
- * @read_only: Return value for read-only status.
+ * @cancellable: a #GCancellable for the operation
+ * @only_if_exists: Whether to open the calendar if and only if it already exists
+ * or just create it when it does not exist.
  * @error: Out parameter for a #GError.
  *
- * Calls the is_read_only method on the given backend.
+ * Calls the open_sync method on the given backend.
  */
 void
-e_cal_backend_sync_is_read_only  (ECalBackendSync *backend, EDataCal *cal, gboolean *read_only, GError **error)
+e_cal_backend_sync_open (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, gboolean only_if_exists, GError **error)
 {
 	e_return_data_cal_error_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
-	e_return_data_cal_error_if_fail (read_only, InvalidArg);
 
-	LOCK_WRAPPER (is_read_only_sync, (backend, cal, read_only, error));
+	LOCK_WRAPPER (open_sync, (backend, cal, cancellable, only_if_exists, error));
 }
 
 /**
- * e_cal_backend_sync_get_cal_address:
+ * e_cal_backend_sync_authenticate_user:
+ * @backend: an #ECalBackendSync
+ * @cancellable: a #GCancellable for the operation
+ * @credentials: an #ECredentials to authenticate with
+ * @error: #GError to set, when something fails
+ *
+ * Authenticates @backend with given @credentials.
+ **/
+void
+e_cal_backend_sync_authenticate_user (ECalBackendSync *backend, GCancellable *cancellable, ECredentials *credentials, GError **error)
+{
+	e_return_data_cal_error_if_fail (E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
+	e_return_data_cal_error_if_fail (credentials, InvalidArg);
+
+	LOCK_WRAPPER (authenticate_user_sync, (backend, cancellable, credentials, error));
+}
+
+/**
+ * e_cal_backend_sync_remove:
  * @backend: An ECalBackendSync object.
  * @cal: An EDataCal object.
- * @address: Return value for the address.
+ * @cancellable: a #GCancellable for the operation
  * @error: Out parameter for a #GError.
  *
- * Calls the get_cal_address method on the given backend.
+ * Calls the remove_sync method on the given backend.
  */
 void
-e_cal_backend_sync_get_cal_address  (ECalBackendSync *backend, EDataCal *cal, gchar **address, GError **error)
+e_cal_backend_sync_remove (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, GError **error)
 {
 	e_return_data_cal_error_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
-	e_return_data_cal_error_if_fail (address, InvalidArg);
 
-	LOCK_WRAPPER (get_cal_address_sync, (backend, cal, address, error));
+	LOCK_WRAPPER (remove_sync, (backend, cal, cancellable, error));
 }
 
 /**
- * e_cal_backend_sync_get_alarm_email_address:
+ * e_cal_backend_sync_refresh:
  * @backend: An ECalBackendSync object.
  * @cal: An EDataCal object.
- * @address: Return value for the address.
+ * @cancellable: a #GCancellable for the operation
  * @error: Out parameter for a #GError.
  *
- * Calls the get_alarm_email_address method on the given backend.
+ * Calls the refresh_sync method on the given backend.
+ *
+ * Since: 2.30
  */
 void
-e_cal_backend_sync_get_alarm_email_address  (ECalBackendSync *backend, EDataCal *cal, gchar **address, GError **error)
+e_cal_backend_sync_refresh  (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, GError **error)
 {
 	e_return_data_cal_error_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
-	e_return_data_cal_error_if_fail (address, InvalidArg);
+	e_return_data_cal_error_if_fail (E_CAL_BACKEND_SYNC_GET_CLASS (backend)->refresh_sync != NULL, UnsupportedMethod);
 
-	LOCK_WRAPPER (get_alarm_email_address_sync, (backend, cal, address, error));
+	LOCK_WRAPPER (refresh_sync, (backend, cal, cancellable, error));
 }
 
 /**
- * e_cal_backend_sync_get_ldap_attribute:
+ * e_cal_backend_sync_get_backend_property:
  * @backend: An ECalBackendSync object.
  * @cal: An EDataCal object.
- * @attribute: Return value for LDAP attribute.
+ * @cancellable: a #GCancellable for the operation
+ * @prop_name: Property name whose value to retrieve.
+ * @prop_value: Return value of the @prop_name.
  * @error: Out parameter for a #GError.
  *
- * Calls the get_ldap_attribute method on the given backend.
- */
-void
-e_cal_backend_sync_get_ldap_attribute  (ECalBackendSync *backend, EDataCal *cal, gchar **attribute, GError **error)
+ * Calls the get_backend_property_sync method on the given backend.
+ *
+ * Returns whether processed this property. Returning FALSE means to pass
+ * the call to the ECalBackend parent class, thus neither @error should be
+ * set in this case.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_backend_sync_get_backend_property (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *prop_name, gchar **prop_value, GError **error)
 {
-	e_return_data_cal_error_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
-	e_return_data_cal_error_if_fail (attribute, InvalidArg);
+	gboolean res = FALSE;
+
+	e_return_data_cal_error_val_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
+	e_return_data_cal_error_val_if_fail (prop_name, InvalidArg);
+	e_return_data_cal_error_val_if_fail (prop_value, InvalidArg);
 
-	LOCK_WRAPPER (get_ldap_attribute_sync, (backend, cal, attribute, error));
+	LOCK_WRAPPER_RET_VAL (get_backend_property_sync, (backend, cal, cancellable, prop_name, prop_value, error));
+
+	return res;
 }
 
 /**
- * e_cal_backend_sync_get_static_capabilities:
+ * e_cal_backend_sync_set_backend_property:
  * @backend: An ECalBackendSync object.
  * @cal: An EDataCal object.
- * @capabilities: Return value for capabilities.
+ * @cancellable: a #GCancellable for the operation
+ * @prop_name: Property name to set.
+ * @prop_value: New value of the @prop_name.
  * @error: Out parameter for a #GError.
  *
- * Calls the get_capabilities method on the given backend.
- */
-void
-e_cal_backend_sync_get_static_capabilities  (ECalBackendSync *backend, EDataCal *cal, gchar **capabilities, GError **error)
+ * Calls the set_backend_property_sync method on the given backend.
+ *
+ * Returns whether processed this property. Returning FALSE means to pass
+ * the call to the ECalBackend parent class, thus neither @error should be
+ * set in this case.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_cal_backend_sync_set_backend_property (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *prop_name, const gchar *prop_value, GError **error)
 {
-	e_return_data_cal_error_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
-	e_return_data_cal_error_if_fail (capabilities, InvalidArg);
+	gboolean res = FALSE;
+
+	e_return_data_cal_error_val_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
+	e_return_data_cal_error_val_if_fail (prop_name, InvalidArg);
+	e_return_data_cal_error_val_if_fail (prop_value, InvalidArg);
 
-	LOCK_WRAPPER (get_static_capabilities_sync, (backend, cal, capabilities, error));
+	LOCK_WRAPPER_RET_VAL (set_backend_property_sync, (backend, cal, cancellable, prop_name, prop_value, error));
+
+	return res;
 }
 
 /**
- * e_cal_backend_sync_open:
+ * e_cal_backend_sync_get_object:
  * @backend: An ECalBackendSync object.
  * @cal: An EDataCal object.
- * @only_if_exists: Whether to open the calendar if and only if it already exists
- * or just create it when it does not exist.
- * @username: User name to use for authentication.
- * @password: Password to use for authentication.
+ * @cancellable: a #GCancellable for the operation
+ * @uid: UID of the object to get.
+ * @rid: Recurrence ID of the specific instance to get, or NULL if getting the
+ * master object.
+ * @calobj: Placeholder for returned object.
  * @error: Out parameter for a #GError.
  *
- * Calls the open method on the given backend.
+ * Calls the get_object_sync method on the given backend.
  */
 void
-e_cal_backend_sync_open  (ECalBackendSync *backend, EDataCal *cal, gboolean only_if_exists,
-			  const gchar *username, const gchar *password, GError **error)
+e_cal_backend_sync_get_object (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *uid, const gchar *rid, gchar **calobj, GError **error)
 {
 	e_return_data_cal_error_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
+	e_return_data_cal_error_if_fail (calobj, InvalidArg);
 
-	LOCK_WRAPPER (open_sync, (backend, cal, only_if_exists, username, password, error));
+	LOCK_WRAPPER (get_object_sync, (backend, cal, cancellable, uid, rid, calobj, error));
 }
 
 /**
- * e_cal_backend_sync_remove:
+ * e_cal_backend_sync_get_object_list:
  * @backend: An ECalBackendSync object.
  * @cal: An EDataCal object.
+ * @cancellable: a #GCancellable for the operation
+ * @sexp: Search query.
+ * @calobjs: Placeholder for list of returned objects.
  * @error: Out parameter for a #GError.
  *
- * Calls the remove method on the given backend.
+ * Calls the get_object_list_sync method on the given backend.
  */
 void
-e_cal_backend_sync_remove  (ECalBackendSync *backend, EDataCal *cal, GError **error)
+e_cal_backend_sync_get_object_list (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *sexp, GSList **calobjs, GError **error)
 {
 	e_return_data_cal_error_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
+	e_return_data_cal_error_if_fail (calobjs, InvalidArg);
 
-	LOCK_WRAPPER (remove_sync, (backend, cal, error));
+	LOCK_WRAPPER (get_object_list_sync, (backend, cal, cancellable, sexp, calobjs, error));
 }
 
 /**
- * e_cal_backend_sync_refresh:
+ * e_cal_backend_sync_get_free_busy:
  * @backend: An ECalBackendSync object.
  * @cal: An EDataCal object.
+ * @cancellable: a #GCancellable for the operation
+ * @users: List of users to get F/B info from.
+ * @start: Time range start.
+ * @end: Time range end.
+ * @freebusyobjects: Placeholder for F/B information.
  * @error: Out parameter for a #GError.
  *
- * Calls the refresh method on the given backend.
- *
- * Since: 2.30
+ * Calls the get_free_busy_sync method on the given backend.
  */
 void
-e_cal_backend_sync_refresh  (ECalBackendSync *backend, EDataCal *cal, GError **error)
+e_cal_backend_sync_get_free_busy (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const GSList *users, time_t start, time_t end, GSList **freebusyobjects, GError **error)
 {
-	e_return_data_cal_error_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
-	e_return_data_cal_error_if_fail (E_CAL_BACKEND_SYNC_GET_CLASS (backend)->refresh_sync != NULL, UnsupportedMethod);
+	e_return_data_cal_error_if_fail (E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
 
-	LOCK_WRAPPER (refresh_sync, (backend, cal, error));
+	LOCK_WRAPPER (get_free_busy_sync, (backend, cal, cancellable, users, start, end, freebusyobjects, error));
 }
 
 /**
  * e_cal_backend_sync_create_object:
  * @backend: An ECalBackendSync object.
  * @cal: An EDataCal object.
+ * @cancellable: a #GCancellable for the operation
  * @calobj: The object to be added.
  * @uid: Placeholder for server-generated UID.
+ * @new_object: Placeholder for server-calobj, if it changed. Can be left as is if it's same as @calobj.
  * @error: Out parameter for a #GError.
  *
- * Calls the create_object method on the given backend.
+ * Calls the create_object_sync method on the given backend.
  */
 void
-e_cal_backend_sync_create_object (ECalBackendSync *backend, EDataCal *cal, gchar **calobj, gchar **uid, GError **error)
+e_cal_backend_sync_create_object (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, gchar **uid, gchar **new_object, GError **error)
 {
 	e_return_data_cal_error_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
 	e_return_data_cal_error_if_fail (E_CAL_BACKEND_SYNC_GET_CLASS (backend)->create_object_sync != NULL, UnsupportedMethod);
 
-	LOCK_WRAPPER (create_object_sync, (backend, cal, calobj, uid, error));
+	LOCK_WRAPPER (create_object_sync, (backend, cal, cancellable, calobj, uid, new_object, error));
 }
 
 /**
  * e_cal_backend_sync_modify_object:
  * @backend: An ECalBackendSync object.
  * @cal: An EDataCal object.
+ * @cancellable: a #GCancellable for the operation
  * @calobj: Object to be modified.
  * @mod: Type of modification to be done.
  * @old_object: Placeholder for returning the old object as it was stored on the
@@ -226,187 +292,137 @@ e_cal_backend_sync_create_object (ECalBackendSync *backend, EDataCal *cal, gchar
  * on the backend.
  * @error: Out parameter for a #GError.
  *
- * Calls the modify_object method on the given backend.
+ * Calls the modify_object_sync method on the given backend.
  */
 void
-e_cal_backend_sync_modify_object (ECalBackendSync *backend, EDataCal *cal, const gchar *calobj,
+e_cal_backend_sync_modify_object (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj,
 				  CalObjModType mod, gchar **old_object, gchar **new_object, GError **error)
 {
 	e_return_data_cal_error_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
 	e_return_data_cal_error_if_fail (E_CAL_BACKEND_SYNC_GET_CLASS (backend)->modify_object_sync != NULL, UnsupportedMethod);
 
-	LOCK_WRAPPER (modify_object_sync, (backend, cal, calobj, mod, old_object, new_object, error));
+	LOCK_WRAPPER (modify_object_sync, (backend, cal, cancellable, calobj, mod, old_object, new_object, error));
 }
 
 /**
  * e_cal_backend_sync_remove_object:
  * @backend: An ECalBackendSync object.
  * @cal: An EDataCal object.
+ * @cancellable: a #GCancellable for the operation
  * @uid: UID of the object to remove.
  * @rid: Recurrence ID of the instance to remove, or NULL if removing the
  * whole object.
  * @mod: Type of removal.
  * @old_object: Placeholder for returning the old object as it was stored on the
  * backend.
- * @object: Placeholder for returning the object after it has been modified (when
+ * @new_object: Placeholder for returning the object after it has been modified (when
  * removing individual instances). If removing the whole object, this will be
  * NULL.
  * @error: Out parameter for a #GError.
  *
- * Calls the remove_object method on the given backend.
+ * Calls the remove_object_sync method on the given backend.
  */
 void
-e_cal_backend_sync_remove_object (ECalBackendSync *backend, EDataCal *cal, const gchar *uid, const gchar *rid,
-				  CalObjModType mod, gchar **old_object, gchar **object, GError **error)
+e_cal_backend_sync_remove_object (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *uid, const gchar *rid,
+				  CalObjModType mod, gchar **old_object, gchar **new_object, GError **error)
 {
 	e_return_data_cal_error_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
 	e_return_data_cal_error_if_fail (E_CAL_BACKEND_SYNC_GET_CLASS (backend)->remove_object_sync != NULL, UnsupportedMethod);
 
-	LOCK_WRAPPER (remove_object_sync, (backend, cal, uid, rid, mod, old_object, object, error));
-}
-
-/**
- * e_cal_backend_sync_discard_alarm:
- * @backend: An ECalBackendSync object.
- * @cal: An EDataCal object.
- * @uid: UID of the object to discard the alarm from.
- * @auid: UID of the alarm to be discarded.
- * @error: Out parameter for a #GError.
- *
- * Calls the discard_alarm method on the given backend.
- */
-void
-e_cal_backend_sync_discard_alarm (ECalBackendSync *backend, EDataCal *cal, const gchar *uid, const gchar *auid, GError **error)
-{
-	e_return_data_cal_error_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
-	e_return_data_cal_error_if_fail (E_CAL_BACKEND_SYNC_GET_CLASS (backend)->discard_alarm_sync != NULL, UnsupportedMethod);
-
-	LOCK_WRAPPER (discard_alarm_sync, (backend, cal, uid, auid, error));
+	LOCK_WRAPPER (remove_object_sync, (backend, cal, cancellable, uid, rid, mod, old_object, new_object, error));
 }
 
 /**
  * e_cal_backend_sync_receive_objects:
  * @backend: An ECalBackendSync object.
  * @cal: An EDataCal object.
+ * @cancellable: a #GCancellable for the operation
  * @calobj: iCalendar object to receive.
  * @error: Out parameter for a #GError.
  *
- * Calls the receive_objects method on the given backend.
+ * Calls the receive_objects_sync method on the given backend.
  */
 void
-e_cal_backend_sync_receive_objects (ECalBackendSync *backend, EDataCal *cal, const gchar *calobj, GError **error)
+e_cal_backend_sync_receive_objects (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, GError **error)
 {
 	e_return_data_cal_error_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
 	e_return_data_cal_error_if_fail (E_CAL_BACKEND_SYNC_GET_CLASS (backend)->receive_objects_sync != NULL, UnsupportedMethod);
 
-	LOCK_WRAPPER (receive_objects_sync, (backend, cal, calobj, error));
+	LOCK_WRAPPER (receive_objects_sync, (backend, cal, cancellable, calobj, error));
 }
 
 /**
  * e_cal_backend_sync_send_objects:
  * @backend: An ECalBackendSync object.
  * @cal: An EDataCal object.
+ * @cancellable: a #GCancellable for the operation
  * @calobj: The iCalendar object to send.
  * @users: List of users to send notifications to.
  * @modified_calobj: Placeholder for the iCalendar object after being modified.
  * @error: Out parameter for a #GError.
  *
- * Calls the send_objects method on the given backend.
+ * Calls the send_objects_sync method on the given backend.
  */
 void
-e_cal_backend_sync_send_objects (ECalBackendSync *backend, EDataCal *cal, const gchar *calobj, GList **users,
+e_cal_backend_sync_send_objects (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, GSList **users,
 				 gchar **modified_calobj, GError **error)
 {
 	e_return_data_cal_error_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
 	e_return_data_cal_error_if_fail (E_CAL_BACKEND_SYNC_GET_CLASS (backend)->send_objects_sync != NULL, UnsupportedMethod);
 
-	LOCK_WRAPPER (send_objects_sync, (backend, cal, calobj, users, modified_calobj, error));
+	LOCK_WRAPPER (send_objects_sync, (backend, cal, cancellable, calobj, users, modified_calobj, error));
 }
 
 /**
- * e_cal_backend_sync_get_default_object:
+ * e_cal_backend_sync_get_attachment_uris:
  * @backend: An ECalBackendSync object.
  * @cal: An EDataCal object.
- * @object: Placeholder for returned object.
- * @error: Out parameter for a #GError.
- *
- * Calls the get_default_object method on the given backend.
- */
-void
-e_cal_backend_sync_get_default_object (ECalBackendSync *backend, EDataCal *cal, gchar **object, GError **error)
-{
-	e_return_data_cal_error_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
-	e_return_data_cal_error_if_fail (object, InvalidArg);
-
-	LOCK_WRAPPER (get_default_object_sync, (backend, cal, object, error));
-}
-
-/**
- * e_cal_backend_sync_get_object:
- * @backend: An ECalBackendSync object.
- * @cal: An EDataCal object.
- * @uid: UID of the object to get.
- * @rid: Recurrence ID of the specific instance to get, or NULL if getting the
- * master object.
- * @object: Placeholder for returned object.
- * @error: Out parameter for a #GError.
- *
- * Calls the get_object method on the given backend.
- */
-void
-e_cal_backend_sync_get_object (ECalBackendSync *backend, EDataCal *cal, const gchar *uid, const gchar *rid, gchar **object, GError **error)
-{
-	e_return_data_cal_error_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
-	e_return_data_cal_error_if_fail (object, InvalidArg);
-
-	LOCK_WRAPPER (get_object_sync, (backend, cal, uid, rid, object, error));
-}
-
-/**
- * e_cal_backend_sync_get_object_list:
- * @backend: An ECalBackendSync object.
- * @cal: An EDataCal object.
- * @sexp: Search query.
- * @objects: Placeholder for list of returned objects.
+ * @cancellable: a #GCancellable for the operation
+ * @uid: Unique id of the calendar object.
+ * @rid: Recurrence id of the calendar object.
+ * @attachments: Placeholder for list of returned attachment uris.
  * @error: Out parameter for a #GError.
  *
- * Calls the get_object_list method on the given backend.
+ * Calls the get_attachment_uris_sync method on the given backend.
  */
 void
-e_cal_backend_sync_get_object_list (ECalBackendSync *backend, EDataCal *cal, const gchar *sexp, GList **objects, GError **error)
+e_cal_backend_sync_get_attachment_uris (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *uid, const gchar *rid, GSList **attachments, GError **error)
 {
 	e_return_data_cal_error_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
-	e_return_data_cal_error_if_fail (objects, InvalidArg);
+	e_return_data_cal_error_if_fail (attachments, InvalidArg);
 
-	LOCK_WRAPPER (get_object_list_sync, (backend, cal, sexp, objects, error));
+	LOCK_WRAPPER (get_attachment_uris_sync, (backend, cal, cancellable, uid, rid, attachments, error));
 }
 
 /**
- * e_cal_backend_sync_get_attachment_list:
+ * e_cal_backend_sync_discard_alarm:
  * @backend: An ECalBackendSync object.
  * @cal: An EDataCal object.
+ * @cancellable: a #GCancellable for the operation
  * @uid: Unique id of the calendar object.
  * @rid: Recurrence id of the calendar object.
- * @attachments: Placeholder for list of returned attachment uris.
+ * @auid: Alarm ID to remove.
  * @error: Out parameter for a #GError.
  *
- * Calls the get_attachment_list method on the given backend.
- */
+ * Calls the discard_alarm_sync method on the given backend.
+ **/
 void
-e_cal_backend_sync_get_attachment_list (ECalBackendSync *backend, EDataCal *cal, const gchar *uid, const gchar *rid, GSList **attachments, GError **error)
+e_cal_backend_sync_discard_alarm (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *uid, const gchar *rid, const gchar *auid, GError **error)
 {
 	e_return_data_cal_error_if_fail (backend && E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
-	e_return_data_cal_error_if_fail (attachments, InvalidArg);
+	e_return_data_cal_error_if_fail (uid, InvalidArg);
+	e_return_data_cal_error_if_fail (auid, InvalidArg);
 
-	LOCK_WRAPPER (get_attachment_list_sync, (backend, cal, uid, rid, attachments, error));
+	LOCK_WRAPPER (discard_alarm_sync, (backend, cal, cancellable, uid, rid, auid, error));
 }
 
 /**
  * e_cal_backend_sync_get_timezone:
  * @backend: An ECalBackendSync object.
  * @cal: An EDataCal object.
+ * @cancellable: a #GCancellable for the operation
  * @tzid: ID of the timezone to retrieve.
- * @object: Placeholder for the returned timezone.
+ * @tzobject: Placeholder for the returned timezone.
  * @error: Out parameter for a #GError.
  *
  * Calls the get_timezone_sync method on the given backend.
@@ -418,15 +434,15 @@ e_cal_backend_sync_get_attachment_list (ECalBackendSync *backend, EDataCal *cal,
  * get_timezone_sync completely.
  */
 void
-e_cal_backend_sync_get_timezone (ECalBackendSync *backend, EDataCal *cal, const gchar *tzid, gchar **object, GError **error)
+e_cal_backend_sync_get_timezone (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *tzid, gchar **tzobject, GError **error)
 {
 	e_return_data_cal_error_if_fail (E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
 
 	if (E_CAL_BACKEND_SYNC_GET_CLASS (backend)->get_timezone_sync) {
-		LOCK_WRAPPER (get_timezone_sync, (backend, cal, tzid, object, error));
+		LOCK_WRAPPER (get_timezone_sync, (backend, cal, cancellable, tzid, tzobject, error));
 	}
 
-	if (object && !*object) {
+	if (tzobject && !*tzobject) {
 		icaltimezone *zone = NULL;
 
 		if (backend->priv->mutex_lock)
@@ -445,7 +461,7 @@ e_cal_backend_sync_get_timezone (ECalBackendSync *backend, EDataCal *cal, const
 			if (!icalcomp) {
 				g_propagate_error (error, e_data_cal_create_error (InvalidObject, NULL));
 			} else {
-				*object = icalcomponent_as_ical_string_r (icalcomp);
+				*tzobject = icalcomponent_as_ical_string_r (icalcomp);
 			}
 		}
 	}
@@ -455,334 +471,231 @@ e_cal_backend_sync_get_timezone (ECalBackendSync *backend, EDataCal *cal, const
  * e_cal_backend_sync_add_timezone:
  * @backend: An ECalBackendSync object.
  * @cal: An EDataCal object.
- * @tzobj: VTIMEZONE object to be added.
- * @error: Out parameter for a #GError.
- *
- * Calls the add_timezone method on the given backend.
- */
-void
-e_cal_backend_sync_add_timezone (ECalBackendSync *backend, EDataCal *cal, const gchar *tzobj, GError **error)
-{
-	e_return_data_cal_error_if_fail (E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
-
-	LOCK_WRAPPER (add_timezone_sync, (backend, cal, tzobj, error));
-}
-
-/**
- * e_cal_backend_sync_set_default_zone:
- * @backend: An ECalBackendSync object.
- * @cal: An EDataCal object.
- * @tz: Timezone object as string.
+ * @cancellable: a #GCancellable for the operation
+ * @tzobject: VTIMEZONE object to be added.
  * @error: Out parameter for a #GError.
  *
- * Calls the set_default_zone method on the given backend.
+ * Calls the add_timezone_sync method on the given backend.
  */
 void
-e_cal_backend_sync_set_default_zone (ECalBackendSync *backend, EDataCal *cal, const gchar *tz, GError **error)
+e_cal_backend_sync_add_timezone (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *tzobject, GError **error)
 {
 	e_return_data_cal_error_if_fail (E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
 
-	LOCK_WRAPPER (set_default_zone_sync, (backend, cal, tz, error));
-}
-
-/**
- * e_cal_backend_sync_get_changes:
- * @backend: An ECalBackendSync object.
- * @cal: An EDataCal object.
- * @change_id: ID of the change to use as base.
- * @adds: Placeholder for list of additions.
- * @modifies: Placeholder for list of modifications.
- * @deletes: Placeholder for list of deletions.
- * @error: Out parameter for a #GError.
- *
- * Calls the get_changes method on the given backend.
- */
-void
-e_cal_backend_sync_get_changes (ECalBackendSync *backend, EDataCal *cal, const gchar *change_id,
-				GList **adds, GList **modifies, GList **deletes, GError **error)
-{
-	e_return_data_cal_error_if_fail (E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
-
-	LOCK_WRAPPER (get_changes_sync, (backend, cal, change_id, adds, modifies, deletes, error));
-}
-
-/**
- * e_cal_backend_sync_get_free_busy:
- * @backend: An ECalBackendSync object.
- * @cal: An EDataCal object.
- * @users: List of users to get F/B info from.
- * @start: Time range start.
- * @end: Time range end.
- * @freebusy: Placeholder for F/B information.
- * @error: Out parameter for a #GError.
- *
- * Calls the get_free_busy method on the given backend.
- */
-void
-e_cal_backend_sync_get_free_busy (ECalBackendSync *backend, EDataCal *cal, GList *users,
-				  time_t start, time_t end, GList **freebusy, GError **error)
-{
-	e_return_data_cal_error_if_fail (E_IS_CAL_BACKEND_SYNC (backend), InvalidArg);
-
-	LOCK_WRAPPER (get_freebusy_sync, (backend, cal, users, start, end, freebusy, error));
+	LOCK_WRAPPER (add_timezone_sync, (backend, cal, cancellable, tzobject, error));
 }
 
 static void
-_e_cal_backend_is_read_only (ECalBackend *backend, EDataCal *cal)
+cal_backend_open (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, gboolean only_if_exists)
 {
 	GError *error = NULL;
-	gboolean read_only = TRUE;
 
-	e_cal_backend_sync_is_read_only (E_CAL_BACKEND_SYNC (backend), cal, &read_only, &error);
+	e_cal_backend_sync_open (E_CAL_BACKEND_SYNC (backend), cal, cancellable, only_if_exists, &error);
 
-	e_data_cal_notify_read_only (cal, error, read_only);
+	e_data_cal_respond_open (cal, opid, error);
 }
 
 static void
-_e_cal_backend_get_cal_address (ECalBackend *backend, EDataCal *cal, EServerMethodContext context)
+cal_backend_authenticate_user (ECalBackend *backend, GCancellable *cancellable, ECredentials *credentials)
 {
 	GError *error = NULL;
-	gchar *address = NULL;
-
-	e_cal_backend_sync_get_cal_address (E_CAL_BACKEND_SYNC (backend), cal, &address, &error);
 
-	e_data_cal_notify_cal_address (cal, context, error, address);
+	e_cal_backend_sync_authenticate_user (E_CAL_BACKEND_SYNC (backend), cancellable, credentials, &error);
 
-	g_free (address);
+	e_cal_backend_notify_opened (backend, error);
 }
 
 static void
-_e_cal_backend_get_alarm_email_address (ECalBackend *backend, EDataCal *cal, EServerMethodContext context)
+cal_backend_remove (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable)
 {
 	GError *error = NULL;
-	gchar *address = NULL;
 
-	e_cal_backend_sync_get_alarm_email_address (E_CAL_BACKEND_SYNC (backend), cal, &address, &error);
+	e_cal_backend_sync_remove (E_CAL_BACKEND_SYNC (backend), cal, cancellable, &error);
 
-	e_data_cal_notify_alarm_email_address (cal, context, error, address);
-
-	g_free (address);
+	e_data_cal_respond_remove (cal, opid, error);
 }
 
 static void
-_e_cal_backend_get_ldap_attribute (ECalBackend *backend, EDataCal *cal, EServerMethodContext context)
+cal_backend_refresh (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable)
 {
 	GError *error = NULL;
-	gchar *attribute = NULL;
-
-	e_cal_backend_sync_get_ldap_attribute (E_CAL_BACKEND_SYNC (backend), cal, &attribute, &error);
 
-	e_data_cal_notify_ldap_attribute (cal, context, error, attribute);
+	e_cal_backend_sync_refresh (E_CAL_BACKEND_SYNC (backend), cal, cancellable, &error);
 
-	g_free (attribute);
+	e_data_cal_respond_refresh (cal, opid, error);
 }
 
 static void
-_e_cal_backend_get_static_capabilities (ECalBackend *backend, EDataCal *cal, EServerMethodContext context)
+cal_backend_get_backend_property (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *prop_name)
 {
 	GError *error = NULL;
-	gchar *capabilities = NULL;
-
-	e_cal_backend_sync_get_static_capabilities (E_CAL_BACKEND_SYNC (backend), cal, &capabilities, &error);
+	gchar *prop_value = NULL;
 
-	e_data_cal_notify_static_capabilities (cal, context, error, capabilities);
+	if (e_cal_backend_sync_get_backend_property (E_CAL_BACKEND_SYNC (backend), cal, cancellable, prop_name, &prop_value, &error))
+		e_data_cal_respond_get_backend_property (cal, opid, error, prop_value);
+	else
+		(* E_CAL_BACKEND_CLASS (e_cal_backend_sync_parent_class)->get_backend_property) (backend, cal, opid, cancellable, prop_name);
 
-	g_free (capabilities);
+	g_free (prop_value);
 }
 
 static void
-_e_cal_backend_open (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, gboolean only_if_exists,
-		     const gchar *username, const gchar *password)
+cal_backend_set_backend_property (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *prop_name, const gchar *prop_value)
 {
 	GError *error = NULL;
 
-	e_cal_backend_sync_open (E_CAL_BACKEND_SYNC (backend), cal, only_if_exists, username, password, &error);
-
-	e_data_cal_notify_open (cal, context, error);
+	if (e_cal_backend_sync_set_backend_property (E_CAL_BACKEND_SYNC (backend), cal, cancellable, prop_name, prop_value, &error))
+		e_data_cal_respond_set_backend_property (cal, opid, error);
+	else
+		(* E_CAL_BACKEND_CLASS (e_cal_backend_sync_parent_class)->set_backend_property) (backend, cal, opid, cancellable, prop_name, prop_value);
 }
 
 static void
-_e_cal_backend_refresh (ECalBackend *backend, EDataCal *cal, EServerMethodContext context)
+cal_backend_get_object (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *uid, const gchar *rid)
 {
 	GError *error = NULL;
+	gchar *calobj = NULL;
 
-	e_cal_backend_sync_refresh (E_CAL_BACKEND_SYNC (backend), cal, &error);
+	e_cal_backend_sync_get_object (E_CAL_BACKEND_SYNC (backend), cal, cancellable, uid, rid, &calobj, &error);
 
-	e_data_cal_notify_refresh (cal, context, error);
+	e_data_cal_respond_get_object (cal, opid, error, calobj);
+
+	g_free (calobj);
 }
 
 static void
-_e_cal_backend_remove (ECalBackend *backend, EDataCal *cal, EServerMethodContext context)
+cal_backend_get_object_list (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *sexp)
 {
 	GError *error = NULL;
+	GSList *calobjs = NULL;
+
+	e_cal_backend_sync_get_object_list (E_CAL_BACKEND_SYNC (backend), cal, cancellable, sexp, &calobjs, &error);
 
-	e_cal_backend_sync_remove (E_CAL_BACKEND_SYNC (backend), cal, &error);
+	e_data_cal_respond_get_object_list (cal, opid, error, calobjs);
 
-	e_data_cal_notify_remove (cal, context, error);
+	g_slist_foreach (calobjs, (GFunc) g_free, NULL);
+	g_slist_free (calobjs);
 }
 
 static void
-_e_cal_backend_create_object (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *calobj)
+cal_backend_get_free_busy (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const GSList *users, time_t start, time_t end)
 {
 	GError *error = NULL;
-	gchar *uid = NULL, *modified_calobj = (gchar *) calobj;
-
-	e_cal_backend_sync_create_object (E_CAL_BACKEND_SYNC (backend), cal, &modified_calobj, &uid, &error);
+	GSList *freebusyobjs = NULL;
 
-	e_data_cal_notify_object_created (cal, context, error, uid, modified_calobj);
+	e_cal_backend_sync_get_free_busy (E_CAL_BACKEND_SYNC (backend), cal, cancellable, users, start, end, &freebusyobjs, &error);
 
-	/* free memory */
-	if (uid)
-		g_free (uid);
+	if (freebusyobjs)
+		e_data_cal_report_free_busy_data (cal, freebusyobjs);
+	e_data_cal_respond_get_free_busy (cal, opid, error);
 
-	if (modified_calobj != calobj)
-		g_free (modified_calobj);
+	g_slist_foreach (freebusyobjs, (GFunc) g_free, NULL);
+	g_slist_free (freebusyobjs);
 }
 
 static void
-_e_cal_backend_modify_object (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *calobj, CalObjModType mod)
+cal_backend_create_object (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *calobj)
 {
 	GError *error = NULL;
-	gchar *old_object = NULL;
-	gchar *new_object = NULL;
+	gchar *uid = NULL, *new_object = NULL;
 
-	e_cal_backend_sync_modify_object (E_CAL_BACKEND_SYNC (backend), cal,
-						   calobj, mod, &old_object, &new_object, &error);
+	e_cal_backend_sync_create_object (E_CAL_BACKEND_SYNC (backend), cal, cancellable, calobj, &uid, &new_object, &error);
 
-	if (new_object)
-		e_data_cal_notify_object_modified (cal, context, error, old_object, new_object);
-	else
-		e_data_cal_notify_object_modified (cal, context, error, old_object, calobj);
+	e_data_cal_respond_create_object (cal, opid, error, uid, new_object ? new_object : calobj);
 
-	g_free (old_object);
+	g_free (uid);
 	g_free (new_object);
 }
 
 static void
-_e_cal_backend_remove_object (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *uid, const gchar *rid, CalObjModType mod)
+cal_backend_modify_object (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *calobj, CalObjModType mod)
 {
 	GError *error = NULL;
-	gchar *object = NULL, *old_object = NULL;
-
-	e_cal_backend_sync_remove_object (E_CAL_BACKEND_SYNC (backend), cal, uid, rid, mod, &old_object, &object, &error);
-
-	if (!error) {
-		ECalComponentId *id = g_new0 (ECalComponentId, 1);
-		id->uid = g_strdup (uid);
+	gchar *old_object = NULL, *new_object = NULL;
 
-		if (mod == CALOBJ_MOD_THIS)
-			id->rid = g_strdup (rid);
+	e_cal_backend_sync_modify_object (E_CAL_BACKEND_SYNC (backend), cal, cancellable, calobj, mod, &old_object, &new_object, &error);
 
-		if (!object)
-			e_data_cal_notify_object_removed (cal, context, error, id, old_object, object);
-		else
-			e_data_cal_notify_object_modified (cal, context, error, old_object, object);
-
-		e_cal_component_free_id (id);
-	} else
-		e_data_cal_notify_object_removed (cal, context, error, NULL, old_object, object);
+	e_data_cal_respond_modify_object (cal, opid, error, old_object ? old_object : calobj, new_object);
 
 	g_free (old_object);
-	g_free (object);
-}
-
-static void
-_e_cal_backend_discard_alarm (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *uid, const gchar *auid)
-{
-	GError *error = NULL;
-
-	e_cal_backend_sync_discard_alarm (E_CAL_BACKEND_SYNC (backend), cal, uid, auid, &error);
-
-	e_data_cal_notify_alarm_discarded (cal, context, error);
+	g_free (new_object);
 }
 
 static void
-_e_cal_backend_receive_objects (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *calobj)
+cal_backend_remove_object (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *uid, const gchar *rid, CalObjModType mod)
 {
 	GError *error = NULL;
+	gchar *old_object = NULL, *new_object = NULL;
+	ECalComponentId compid;
 
-	e_cal_backend_sync_receive_objects (E_CAL_BACKEND_SYNC (backend), cal, calobj, &error);
-
-	e_data_cal_notify_objects_received (cal, context, error);
-}
+	compid.uid = (gchar *) uid;
+	compid.rid = (gchar *) (mod == CALOBJ_MOD_THIS ? rid : NULL);
 
-static void
-_e_cal_backend_send_objects (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *calobj)
-{
-	GError *error = NULL;
-	GList *users = NULL;
-	gchar *modified_calobj = NULL;
+	e_cal_backend_sync_remove_object (E_CAL_BACKEND_SYNC (backend), cal, cancellable, uid, rid, mod, &old_object, &new_object, &error);
 
-	e_cal_backend_sync_send_objects (E_CAL_BACKEND_SYNC (backend), cal, calobj, &users, &modified_calobj, &error);
-	e_data_cal_notify_objects_sent (cal, context, error, users, modified_calobj);
+	e_data_cal_respond_remove_object (cal, opid, error, &compid, old_object, new_object);
 
-	g_list_foreach (users, (GFunc) g_free, NULL);
-	g_list_free (users);
-	g_free (modified_calobj);
+	g_free (old_object);
+	g_free (new_object);
 }
 
 static void
-_e_cal_backend_get_default_object (ECalBackend *backend, EDataCal *cal, EServerMethodContext context)
+cal_backend_receive_objects (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *calobj)
 {
 	GError *error = NULL;
-	gchar *object = NULL;
-
-	e_cal_backend_sync_get_default_object (E_CAL_BACKEND_SYNC (backend), cal, &object, &error);
 
-	e_data_cal_notify_default_object (cal, context, error, object);
+	e_cal_backend_sync_receive_objects (E_CAL_BACKEND_SYNC (backend), cal, cancellable, calobj, &error);
 
-	g_free (object);
+	e_data_cal_respond_receive_objects (cal, opid, error);
 }
 
 static void
-_e_cal_backend_get_object (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *uid, const gchar *rid)
+cal_backend_send_objects (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *calobj)
 {
 	GError *error = NULL;
-	gchar *object = NULL;
+	GSList *users = NULL;
+	gchar *modified_calobj = NULL;
 
-	e_cal_backend_sync_get_object (E_CAL_BACKEND_SYNC (backend), cal, uid, rid, &object, &error);
+	e_cal_backend_sync_send_objects (E_CAL_BACKEND_SYNC (backend), cal, cancellable, calobj, &users, &modified_calobj, &error);
 
-	e_data_cal_notify_object (cal, context, error, object);
+	e_data_cal_respond_send_objects (cal, opid, error, users, modified_calobj ? modified_calobj : calobj);
 
-	g_free (object);
+	g_slist_foreach (users, (GFunc) g_free, NULL);
+	g_slist_free (users);
+	g_free (modified_calobj);
 }
 
 static void
-_e_cal_backend_get_attachment_list (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *uid, const gchar *rid)
+cal_backend_get_attachment_uris (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *uid, const gchar *rid)
 {
 	GError *error = NULL;
-	GSList *list = NULL;
+	GSList *attachments = NULL;
 
-	e_cal_backend_sync_get_attachment_list (E_CAL_BACKEND_SYNC (backend), cal, uid, rid, &list, &error);
+	e_cal_backend_sync_get_attachment_uris (E_CAL_BACKEND_SYNC (backend), cal, cancellable, uid, rid, &attachments, &error);
 
-	e_data_cal_notify_attachment_list (cal, context, error, list);
+	e_data_cal_respond_get_attachment_uris (cal, opid, error, attachments);
 
-	g_slist_foreach (list, (GFunc) g_free, NULL);
-	g_free (list);
+	g_slist_foreach (attachments, (GFunc) g_free, NULL);
+	g_slist_free (attachments);
 }
 
 static void
-_e_cal_backend_get_object_list (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *sexp)
+cal_backend_discard_alarm (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *uid, const gchar *rid, const gchar *auid)
 {
 	GError *error = NULL;
-	GList *objects = NULL, *l;
 
-	e_cal_backend_sync_get_object_list (E_CAL_BACKEND_SYNC (backend), cal, sexp, &objects, &error);
+	e_cal_backend_sync_discard_alarm (E_CAL_BACKEND_SYNC (backend), cal, cancellable, uid, rid, auid, &error);
 
-	e_data_cal_notify_object_list (cal, context, error, objects);
-
-	for (l = objects; l; l = l->next)
-		g_free (l->data);
-	g_list_free (objects);
+	e_data_cal_respond_discard_alarm (cal, opid, error);
 }
 
 static void
-_e_cal_backend_get_timezone (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *tzid)
+cal_backend_get_timezone (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *tzid)
 {
 	GError *error = NULL;
 	gchar *object = NULL;
 
-	e_cal_backend_sync_get_timezone (E_CAL_BACKEND_SYNC (backend), cal, tzid, &object, &error);
+	e_cal_backend_sync_get_timezone (E_CAL_BACKEND_SYNC (backend), cal, cancellable, tzid, &object, &error);
 
 	if (!object && tzid) {
 		/* fallback if tzid contains only the location of timezone */
@@ -827,22 +740,22 @@ _e_cal_backend_get_timezone (ECalBackend *backend, EDataCal *cal, EServerMethodC
 
 		/* also cache this timezone to backend */
 		if (object)
-			e_cal_backend_sync_add_timezone (E_CAL_BACKEND_SYNC (backend), cal, object, NULL);
+			e_cal_backend_sync_add_timezone (E_CAL_BACKEND_SYNC (backend), cal, cancellable, object, NULL);
 	}
 
-	e_data_cal_notify_timezone_requested (cal, context, error, object);
+	e_data_cal_respond_get_timezone	 (cal, opid, error, object);
 
 	g_free (object);
 }
 
 static void
-_e_cal_backend_add_timezone (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *tzobj)
+cal_backend_add_timezone (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *tzobject)
 {
 	GError *error = NULL;
 
-	e_cal_backend_sync_add_timezone (E_CAL_BACKEND_SYNC (backend), cal, tzobj, &error);
+	e_cal_backend_sync_add_timezone (E_CAL_BACKEND_SYNC (backend), cal, cancellable, tzobject, &error);
 
-	e_data_cal_notify_timezone_added (cal, context, error, tzobj);
+	e_data_cal_respond_add_timezone (cal, opid, error);
 }
 
 /* The default implementation is looking for timezone in the ical's builtin timezones,
@@ -853,7 +766,7 @@ _e_cal_backend_add_timezone (ECalBackend *backend, EDataCal *cal, EServerMethodC
    fails, then call parent's object internal_get_timezone, and that's all.
  */
 static icaltimezone *
-_e_cal_backend_internal_get_timezone (ECalBackend *backend, const gchar *tzid)
+cal_backend_internal_get_timezone (ECalBackend *backend, const gchar *tzid)
 {
 	icaltimezone *zone = NULL;
 
@@ -885,53 +798,18 @@ _e_cal_backend_internal_get_timezone (ECalBackend *backend, const gchar *tzid)
 	return zone;
 }
 
-static void
-_e_cal_backend_set_default_zone (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *tz)
+static gboolean
+cal_backend_sync_get_backend_property (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *prop_name, gchar **prop_value, GError **error)
 {
-	GError *error = NULL;
-
-	e_cal_backend_sync_set_default_zone (E_CAL_BACKEND_SYNC (backend), cal, tz, &error);
-
-	e_data_cal_notify_default_timezone_set (cal, context, error);
+	/* to indicate to pass to the ECalBackend parent class */
+	return FALSE;
 }
 
-static void
-_e_cal_backend_get_changes (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *change_id)
+static gboolean
+cal_backend_sync_set_backend_property (ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *prop_name, const gchar *prop_value, GError **error)
 {
-	GError *error = NULL;
-	GList *adds = NULL, *modifies = NULL, *deletes = NULL, *l;
-
-	e_cal_backend_sync_get_changes (E_CAL_BACKEND_SYNC (backend), cal, change_id,
-					       &adds, &modifies, &deletes, &error);
-
-	e_data_cal_notify_changes (cal, context, error, adds, modifies, deletes);
-
-	for (l = adds; l; l = l->next)
-		g_free (l->data);
-	g_list_free (adds);
-
-	for (l = modifies; l; l = l->next)
-		g_free (l->data);
-	g_list_free (modifies);
-
-	for (l = deletes; l; l = l->next)
-		g_free (l->data);
-	g_list_free (deletes);
-}
-
-static void
-_e_cal_backend_get_free_busy (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, GList *users, time_t start, time_t end)
-{
-	GError *error = NULL;
-	GList *freebusy = NULL, *l;
-
-	e_cal_backend_sync_get_free_busy (E_CAL_BACKEND_SYNC (backend), cal, users, start, end, &freebusy, &error);
-
-	e_data_cal_notify_free_busy (cal, context, error, freebusy);
-
-	for (l = freebusy; l; l = l->next)
-		g_free (l->data);
-	g_list_free (freebusy);
+	/* to indicate to pass to the ECalBackend parent class */
+	return FALSE;
 }
 
 static void
@@ -959,43 +837,39 @@ e_cal_backend_sync_dispose (GObject *object)
 		backend->priv = NULL;
 	}
 
-	G_OBJECT_CLASS (parent_class)->dispose (object);
+	G_OBJECT_CLASS (e_cal_backend_sync_parent_class)->dispose (object);
 }
 
 static void
 e_cal_backend_sync_class_init (ECalBackendSyncClass *klass)
 {
 	GObjectClass *object_class;
-	ECalBackendClass *backend_class = E_CAL_BACKEND_CLASS (klass);
-
-	parent_class = g_type_class_peek_parent (klass);
-
-	object_class = (GObjectClass *) klass;
-
-	backend_class->is_read_only = _e_cal_backend_is_read_only;
-	backend_class->get_cal_address = _e_cal_backend_get_cal_address;
-	backend_class->get_alarm_email_address = _e_cal_backend_get_alarm_email_address;
-	backend_class->get_ldap_attribute = _e_cal_backend_get_ldap_attribute;
-	backend_class->get_static_capabilities = _e_cal_backend_get_static_capabilities;
-	backend_class->open = _e_cal_backend_open;
-	backend_class->refresh = _e_cal_backend_refresh;
-	backend_class->remove = _e_cal_backend_remove;
-	backend_class->create_object = _e_cal_backend_create_object;
-	backend_class->modify_object = _e_cal_backend_modify_object;
-	backend_class->remove_object = _e_cal_backend_remove_object;
-	backend_class->discard_alarm = _e_cal_backend_discard_alarm;
-	backend_class->receive_objects = _e_cal_backend_receive_objects;
-	backend_class->send_objects = _e_cal_backend_send_objects;
-	backend_class->get_default_object = _e_cal_backend_get_default_object;
-	backend_class->get_object = _e_cal_backend_get_object;
-	backend_class->get_object_list = _e_cal_backend_get_object_list;
-	backend_class->get_attachment_list = _e_cal_backend_get_attachment_list;
-	backend_class->get_timezone = _e_cal_backend_get_timezone;
-	backend_class->add_timezone = _e_cal_backend_add_timezone;
-	backend_class->set_default_zone = _e_cal_backend_set_default_zone;
-	backend_class->get_changes = _e_cal_backend_get_changes;
-	backend_class->get_free_busy = _e_cal_backend_get_free_busy;
-	backend_class->internal_get_timezone = _e_cal_backend_internal_get_timezone;
+	ECalBackendClass *backend_class;
 
+	object_class = G_OBJECT_CLASS (klass);
 	object_class->dispose = e_cal_backend_sync_dispose;
+
+	backend_class = E_CAL_BACKEND_CLASS (klass);
+	backend_class->open			= cal_backend_open;
+	backend_class->authenticate_user	= cal_backend_authenticate_user;
+	backend_class->remove			= cal_backend_remove;
+	backend_class->refresh			= cal_backend_refresh;
+	backend_class->get_backend_property	= cal_backend_get_backend_property;
+	backend_class->set_backend_property	= cal_backend_set_backend_property;
+	backend_class->get_object		= cal_backend_get_object;
+	backend_class->get_object_list		= cal_backend_get_object_list;
+	backend_class->get_free_busy		= cal_backend_get_free_busy;
+	backend_class->create_object		= cal_backend_create_object;
+	backend_class->modify_object		= cal_backend_modify_object;
+	backend_class->remove_object		= cal_backend_remove_object;
+	backend_class->receive_objects		= cal_backend_receive_objects;
+	backend_class->send_objects		= cal_backend_send_objects;
+	backend_class->get_attachment_uris	= cal_backend_get_attachment_uris;
+	backend_class->discard_alarm		= cal_backend_discard_alarm;
+	backend_class->get_timezone		= cal_backend_get_timezone;
+	backend_class->add_timezone		= cal_backend_add_timezone;
+	backend_class->internal_get_timezone	= cal_backend_internal_get_timezone;
+
+	klass->get_backend_property_sync	= cal_backend_sync_get_backend_property;
+	klass->set_backend_property_sync	= cal_backend_sync_set_backend_property;
 }
diff --git a/calendar/libedata-cal/e-cal-backend-sync.h b/calendar/libedata-cal/e-cal-backend-sync.h
index 5080582..a77dc87 100644
--- a/calendar/libedata-cal/e-cal-backend-sync.h
+++ b/calendar/libedata-cal/e-cal-backend-sync.h
@@ -16,6 +16,7 @@ G_BEGIN_DECLS
 #define E_IS_CAL_BACKEND_SYNC(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_CAL_BACKEND_SYNC))
 #define E_IS_CAL_BACKEND_SYNC_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_CAL_BACKEND_SYNC))
 #define E_CAL_BACKEND_SYNC_GET_CLASS(k) (G_TYPE_INSTANCE_GET_CLASS ((k), E_TYPE_CAL_BACKEND_SYNC, ECalBackendSyncClass))
+
 typedef struct _ECalBackendSync ECalBackendSync;
 typedef struct _ECalBackendSyncClass ECalBackendSyncClass;
 typedef struct _ECalBackendSyncPrivate ECalBackendSyncPrivate;
@@ -30,177 +31,51 @@ struct _ECalBackendSyncClass {
 	ECalBackendClass parent_class;
 
 	/* Virtual methods */
-	void (*is_read_only_sync)  (ECalBackendSync *backend, EDataCal *cal, gboolean *read_only, GError **perror);
-	void (*get_cal_address_sync)  (ECalBackendSync *backend, EDataCal *cal, gchar **address, GError **perror);
-	void (*get_alarm_email_address_sync)  (ECalBackendSync *backend, EDataCal *cal, gchar **address, GError **perror);
-	void (*get_ldap_attribute_sync)  (ECalBackendSync *backend, EDataCal *cal, gchar **attribute, GError **perror);
-	void (*get_static_capabilities_sync)  (ECalBackendSync *backend, EDataCal *cal, gchar **capabilities, GError **perror);
-
-	void (*open_sync)  (ECalBackendSync *backend, EDataCal *cal, gboolean only_if_exists, const gchar *username, const gchar *password, GError **perror);
-	void (*refresh_sync)  (ECalBackendSync *backend, EDataCal *cal, GError **perror);
-	void (*remove_sync)  (ECalBackendSync *backend, EDataCal *cal, GError **perror);
-
-	void (*create_object_sync)  (ECalBackendSync *backend, EDataCal *cal, gchar **calobj, gchar **uid, GError **perror);
-	void (*modify_object_sync)  (ECalBackendSync *backend, EDataCal *cal, const gchar *calobj, CalObjModType mod, gchar **old_object, gchar **new_object, GError **perror);
-	void (*remove_object_sync)  (ECalBackendSync *backend, EDataCal *cal, const gchar *uid, const gchar *rid, CalObjModType mod, gchar **old_object, gchar **object, GError **perror);
-
-	void (*discard_alarm_sync)  (ECalBackendSync *backend, EDataCal *cal, const gchar *uid, const gchar *auid, GError **perror);
-
-	void (*receive_objects_sync)  (ECalBackendSync *backend, EDataCal *cal, const gchar *calobj, GError **perror);
-	void (*send_objects_sync)  (ECalBackendSync *backend, EDataCal *cal, const gchar *calobj, GList **users,
-						     gchar **modified_calobj, GError **perror);
-
-	void (*get_default_object_sync)  (ECalBackendSync *backend, EDataCal *cal, gchar **object, GError **perror);
-	void (*get_object_sync)  (ECalBackendSync *backend, EDataCal *cal, const gchar *uid, const gchar *rid, gchar **object, GError **perror);
-	void (*get_object_list_sync)  (ECalBackendSync *backend, EDataCal *cal, const gchar *sexp, GList **objects, GError **perror);
-
-	void (*get_attachment_list_sync)  (ECalBackendSync *backend, EDataCal *cal, const gchar *uid, const gchar *rid, GSList **attachments, GError **perror);
-
-	void (*get_timezone_sync) (ECalBackendSync *backend, EDataCal *cal, const gchar *tzid, gchar **object, GError **perror);
-	void (*add_timezone_sync) (ECalBackendSync *backend, EDataCal *cal, const gchar *tzobj, GError **perror);
-	void (*set_default_zone_sync) (ECalBackendSync *backend, EDataCal *cal, const gchar *tz, GError **perror);
-
-	void (*get_changes_sync) (ECalBackendSync *backend, EDataCal *cal, const gchar *change_id, GList **adds, GList **modifies, GList **deletes, GError **perror);
-	void (*get_freebusy_sync) (ECalBackendSync *backend, EDataCal *cal, GList *users, time_t start, time_t end, GList **freebusy, GError **perror);
-
-	/* Padding for future expansion */
-	void (*_cal_reserved0) (void);
-	void (*_cal_reserved1) (void);
-	void (*_cal_reserved2) (void);
-	void (*_cal_reserved3) (void);
-	void (*_cal_reserved4) (void);
-
+	void	(* open_sync)			(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, gboolean only_if_exists, GError **error);
+	void	(* remove_sync)			(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, GError **error);
+
+	void	(* refresh_sync)		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, GError **error);
+	gboolean (* get_backend_property_sync)	(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *prop_name, gchar **prop_value, GError **error);
+	gboolean (* set_backend_property_sync)	(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *prop_name, const gchar *prop_value, GError **error);
+	void	(* get_object_sync)		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *uid, const gchar *rid, gchar **calobj, GError **error);
+	void	(* get_object_list_sync)	(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *sexp, GSList **calobjs, GError **error);
+	void	(* get_free_busy_sync)		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const GSList *users, time_t start, time_t end, GSList **freebusyobjs, GError **error);
+	void	(* create_object_sync)		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, gchar **uid, gchar **new_object, GError **error);
+	void	(* modify_object_sync)		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, CalObjModType mod, gchar **old_object, gchar **new_object, GError **error);
+	void	(* remove_object_sync)		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *uid, const gchar *rid, CalObjModType mod, gchar **old_object, gchar **new_object, GError **error);
+	void	(* receive_objects_sync)	(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, GError **error);
+	void	(* send_objects_sync)		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, GSList **users, gchar **modified_calobj, GError **error);
+	void	(* get_attachment_uris_sync)	(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *uid, const gchar *rid, GSList **attachments, GError **error);
+	void	(* discard_alarm_sync)		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *uid, const gchar *rid, const gchar *auid, GError **error);
+	void	(* get_timezone_sync)		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *tzid, gchar **tzobject, GError **error);
+	void	(* add_timezone_sync)		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *tzobject, GError **error);
+
+	void	(* authenticate_user_sync)	(ECalBackendSync *backend, GCancellable *cancellable, ECredentials *credentials, GError **error);
 };
 
-typedef ECalBackendSync * (*ECalBackendSyncFactoryFn) (void);
-GType                e_cal_backend_sync_get_type                (void);
-
-void	e_cal_backend_sync_set_lock		(ECalBackendSync *backend,
-						 gboolean lock);
-
-void	e_cal_backend_sync_is_read_only		(ECalBackendSync *backend,
-						 EDataCal *cal,
-						 gboolean *read_only,
-						 GError **error);
-void	e_cal_backend_sync_get_cal_address	(ECalBackendSync *backend,
-						 EDataCal *cal,
-						 gchar **address,
-						 GError **error);
-void	e_cal_backend_sync_get_alarm_email_address
-						(ECalBackendSync *backend,
-						 EDataCal *cal,
-						 gchar **address,
-						 GError **error);
-void	e_cal_backend_sync_get_ldap_attribute	(ECalBackendSync *backend,
-						 EDataCal *cal,
-						 gchar **attribute,
-						 GError **error);
-void	e_cal_backend_sync_get_static_capabilities
-						(ECalBackendSync *backend,
-						 EDataCal *cal,
-						 gchar **capabiliites,
-						 GError **error);
-void	e_cal_backend_sync_open			(ECalBackendSync *backend,
-						 EDataCal *cal,
-						 gboolean only_if_exists,
-						 const gchar *username,
-						 const gchar *password,
-						 GError **error);
-void	e_cal_backend_sync_refresh		(ECalBackendSync *backend,
-						 EDataCal *cal,
-						 GError **error);
-void	e_cal_backend_sync_remove		(ECalBackendSync *backend,
-						 EDataCal *cal,
-						 GError **error);
-void	e_cal_backend_sync_create_object	(ECalBackendSync *backend,
-						 EDataCal *cal,
-						 gchar **calobj,
-						 gchar **uid,
-						 GError **error);
-void	e_cal_backend_sync_modify_object	(ECalBackendSync *backend,
-						 EDataCal *cal,
-						 const gchar *calobj,
-						 CalObjModType mod,
-						 gchar **old_object,
-						 gchar **new_object,
-						 GError **error);
-void	e_cal_backend_sync_remove_object	(ECalBackendSync *backend,
-						 EDataCal *cal,
-						 const gchar *uid,
-						 const gchar *rid,
-						 CalObjModType mod,
-						 gchar **old_object,
-						 gchar **object,
-						 GError **error);
-void	e_cal_backend_sync_get_attachment_list	(ECalBackendSync *backend,
-						 EDataCal *cal,
-						 const gchar *uid,
-						 const gchar *rid,
-						 GSList **attachments,
-						 GError **error);
-
-void	e_cal_backend_sync_discard_alarm	(ECalBackendSync *backend,
-						 EDataCal *cal,
-						 const gchar *uid,
-						 const gchar *auid,
-						 GError **error);
-
-void	e_cal_backend_sync_receive_objects	(ECalBackendSync *backend,
-						 EDataCal *cal,
-						 const gchar *calobj,
-						 GError **error);
-void	e_cal_backend_sync_send_objects		(ECalBackendSync *backend,
-						 EDataCal *cal,
-						 const gchar *calobj,
-						 GList **users,
-						 gchar **modified_calobj,
-						 GError **error);
-void	e_cal_backend_sync_get_default_object	(ECalBackendSync *backend,
-						 EDataCal *cal,
-						 gchar **object,
-						 GError **error);
-
-void	e_cal_backend_sync_get_object		(ECalBackendSync *backend,
-						 EDataCal *cal,
-						 const gchar *uid,
-						 const gchar *rid,
-						 gchar **object,
-						 GError **error);
-
-void	e_cal_backend_sync_get_object_list	(ECalBackendSync *backend,
-						 EDataCal *cal,
-						 const gchar *sexp,
-						 GList **objects,
-						 GError **error);
-
-void	e_cal_backend_sync_get_timezone		(ECalBackendSync *backend,
-						 EDataCal *cal,
-						 const gchar *tzid,
-						 gchar **object,
-						 GError **error);
-void	e_cal_backend_sync_add_timezone		(ECalBackendSync *backend,
-						 EDataCal *cal,
-						 const gchar *tzobj,
-						 GError **error);
-void	e_cal_backend_sync_set_default_zone	(ECalBackendSync *backend,
-						 EDataCal *cal,
-						 const gchar *tzobj,
-						 GError **error);
-
-void	e_cal_backend_sync_get_changes		(ECalBackendSync *backend,
-						 EDataCal *cal,
-						 const gchar *change_id,
-						 GList **adds,
-						 GList **modifies,
-						 GList **deletes,
-						 GError **error);
-void	e_cal_backend_sync_get_free_busy	(ECalBackendSync *backend,
-						 EDataCal *cal,
-						 GList *users,
-						 time_t start,
-						 time_t end,
-						 GList **freebusy,
-						 GError **error);
+GType	e_cal_backend_sync_get_type		(void);
+
+void	e_cal_backend_sync_set_lock		(ECalBackendSync *backend, gboolean lock);
+
+void	e_cal_backend_sync_open			(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, gboolean only_if_exists, GError **error);
+void	e_cal_backend_sync_remove		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, GError **error);
+void	e_cal_backend_sync_refresh		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, GError **error);
+gboolean e_cal_backend_sync_get_backend_property(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *prop_name, gchar **prop_value, GError **error);
+gboolean e_cal_backend_sync_set_backend_property(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *prop_name, const gchar *prop_value, GError **error);
+void	e_cal_backend_sync_get_object		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *uid, const gchar *rid, gchar **calobj, GError **error);
+void	e_cal_backend_sync_get_object_list	(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *sexp, GSList **calobjs, GError **error);
+void	e_cal_backend_sync_get_free_busy	(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const GSList *users, time_t start, time_t end, GSList **freebusyobjs, GError **error);
+void	e_cal_backend_sync_create_object	(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, gchar **uid, gchar **new_object, GError **error);
+void	e_cal_backend_sync_modify_object	(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, CalObjModType mod, gchar **old_object, gchar **new_object, GError **error);
+void	e_cal_backend_sync_remove_object	(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *uid, const gchar *rid, CalObjModType mod, gchar **old_object, gchar **new_object, GError **error);
+void	e_cal_backend_sync_receive_objects	(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, GError **error);
+void	e_cal_backend_sync_send_objects		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *calobj, GSList **users, gchar **modified_calobj, GError **error);
+void	e_cal_backend_sync_get_attachment_uris	(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *uid, const gchar *rid, GSList **attachments, GError **error);
+void	e_cal_backend_sync_discard_alarm	(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *uid, const gchar *rid, const gchar *auid, GError **error);
+void	e_cal_backend_sync_get_timezone		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *tzid, gchar **tzobject, GError **error);
+void	e_cal_backend_sync_add_timezone		(ECalBackendSync *backend, EDataCal *cal, GCancellable *cancellable, const gchar *tzobject, GError **error);
+
+void	e_cal_backend_sync_authenticate_user	(ECalBackendSync *backend, GCancellable *cancellable, ECredentials *credentials, GError **error);
 
 G_END_DECLS
 
diff --git a/calendar/libedata-cal/e-cal-backend.c b/calendar/libedata-cal/e-cal-backend.c
index 5082ab3..a65051f 100644
--- a/calendar/libedata-cal/e-cal-backend.c
+++ b/calendar/libedata-cal/e-cal-backend.c
@@ -22,47 +22,41 @@
  */
 
 #include <config.h>
-#include <libxml/parser.h>
-#include <libxml/parserInternals.h>
-#include <libxml/xmlmemory.h>
+
+#include <glib/gi18n-lib.h>
 
 #include <libedataserver/e-data-server-util.h>
 
 #include "e-cal-backend.h"
 #include "e-cal-backend-cache.h"
 
-/* For convenience */
-#define CLASS(backend) (E_CAL_BACKEND_GET_CLASS(backend))
-
 #define EDC_ERROR(_code) e_data_cal_create_error (_code, NULL)
+#define EDC_OPENING_ERROR e_data_cal_create_error (Busy, _("Cannot process, calendar backend is opening"))
 
 /* Private part of the CalBackend structure */
 struct _ECalBackendPrivate {
 	/* The source for this backend */
 	ESource *source;
+	/* The kind of components for this backend */
+	icalcomponent_kind kind;
+
+	gboolean opening, opened, readonly, removed, online;
 
 	/* URI, from source. This is cached, since we return const. */
 	gchar *uri;
 
 	gchar *cache_dir;
 
-	/* The kind of components for this backend */
-	icalcomponent_kind kind;
-
 	/* List of Cal objects */
 	GMutex *clients_mutex;
-	GList *clients;
+	GSList *clients;
 
-	GMutex *queries_mutex;
-	EList *queries;
+	GMutex *views_mutex;
+	GSList *views;
 
 	/* ECalBackend to pass notifications on to */
 	ECalBackend *notification_proxy;
 
-	/* used when notifying clients about progress of some operation,
-	 * we do not send multiple notifications with the same percent
-	 * value */
-	gint last_percent_notified;
 };
 
 /* Property IDs */
@@ -192,6 +186,40 @@ cal_backend_set_kind (ECalBackend *backend,
 }
 
 static void
+cal_backend_get_backend_property (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *prop_name)
+{
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (E_IS_CAL_BACKEND (backend));
+	g_return_if_fail (cal != NULL);
+	g_return_if_fail (prop_name != NULL);
+
+	if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_OPENED)) {
+		e_data_cal_respond_get_backend_property (cal, opid, NULL, e_cal_backend_is_opened (backend) ? "TRUE" : "FALSE");
+	} else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_OPENING)) {
+		e_data_cal_respond_get_backend_property (cal, opid, NULL, e_cal_backend_is_opening (backend) ? "TRUE" : "FALSE");
+	} else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_ONLINE)) {
+		e_data_cal_respond_get_backend_property (cal, opid, NULL, e_cal_backend_is_online (backend) ? "TRUE" : "FALSE");
+	} else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_READONLY)) {
+		e_data_cal_respond_get_backend_property (cal, opid, NULL, e_cal_backend_is_readonly (backend) ? "TRUE" : "FALSE");
+	} else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CACHE_DIR)) {
+		e_data_cal_respond_get_backend_property (cal, opid, NULL, e_cal_backend_get_cache_dir (backend));
+	} else {
+		e_data_cal_respond_get_backend_property (cal, opid, e_data_cal_create_error_fmt (NotSupported, _("Unknown calendar property '%s'"), prop_name), NULL);
+	}
+}
+
+static void
+cal_backend_set_backend_property (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *prop_name, const gchar *prop_value)
+{
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (E_IS_CAL_BACKEND (backend));
+	g_return_if_fail (cal != NULL);
+	g_return_if_fail (prop_name != NULL);
+
+	e_data_cal_respond_set_backend_property (cal, opid, e_data_cal_create_error_fmt (NotSupported, _("Cannot change value of calendar property '%s'"), prop_name));
+}
+
+static void
 cal_backend_set_property (GObject *object,
                           guint property_id,
                           const GValue *value,
@@ -264,10 +292,12 @@ cal_backend_finalize (GObject *object)
 
 	g_assert (priv->clients == NULL);
 
-	g_object_unref (priv->queries);
+	g_slist_free (priv->views);
+	/* should be NULL, anyway */
+	g_slist_free (priv->clients);
 
 	g_mutex_free (priv->clients_mutex);
-	g_mutex_free (priv->queries_mutex);
+	g_mutex_free (priv->views_mutex);
 
 	g_free (priv->uri);
 	g_free (priv->cache_dir);
@@ -285,21 +315,26 @@ static void
 cal_backend_constructed (GObject *object)
 {
 	cal_backend_set_default_cache_dir (E_CAL_BACKEND (object));
+
+	G_OBJECT_CLASS (e_cal_backend_parent_class)->constructed (object);
 }
 
 static void
-e_cal_backend_class_init (ECalBackendClass *class)
+e_cal_backend_class_init (ECalBackendClass *klass)
 {
 	GObjectClass *object_class;
 
-	g_type_class_add_private (class, sizeof (ECalBackendPrivate));
+	g_type_class_add_private (klass, sizeof (ECalBackendPrivate));
 
-	object_class = G_OBJECT_CLASS (class);
+	object_class = G_OBJECT_CLASS (klass);
 	object_class->set_property = cal_backend_set_property;
 	object_class->get_property = cal_backend_get_property;
 	object_class->finalize = cal_backend_finalize;
 	object_class->constructed = cal_backend_constructed;
 
+	klass->get_backend_property = cal_backend_get_backend_property;
+	klass->set_backend_property = cal_backend_set_backend_property;
+
 	g_object_class_install_property (
 		object_class,
 		PROP_CACHE_DIR,
@@ -347,7 +382,7 @@ e_cal_backend_class_init (ECalBackendClass *class)
 
 	signals[LAST_CLIENT_GONE] = g_signal_new (
 		"last_client_gone",
-		G_TYPE_FROM_CLASS (class),
+		G_TYPE_FROM_CLASS (klass),
 		G_SIGNAL_RUN_FIRST,
 		G_STRUCT_OFFSET (ECalBackendClass, last_client_gone),
 		NULL, NULL,
@@ -364,10 +399,161 @@ e_cal_backend_init (ECalBackend *backend)
 	backend->priv->clients = NULL;
 	backend->priv->clients_mutex = g_mutex_new ();
 
-	backend->priv->queries = e_list_new (
-		(EListCopyFunc) NULL,
-		(EListFreeFunc) NULL, NULL);
-	backend->priv->queries_mutex = g_mutex_new ();
+	backend->priv->views = NULL;
+	backend->priv->views_mutex = g_mutex_new ();
+
+	backend->priv->readonly = TRUE;
+	backend->priv->online = FALSE;
+}
+
+/**
+ * e_cal_backend_get_source:
+ * @backend: an #ECalBackend
+ *
+ * Gets the #ESource associated with the given backend.
+ *
+ * Returns: The #ESource for the backend.
+ */
+ESource *
+e_cal_backend_get_source (ECalBackend *backend)
+{
+	g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
+
+	return backend->priv->source;
+}
+
+/**
+ * e_cal_backend_get_uri:
+ * @backend: an #ECalBackend
+ *
+ * Queries the URI of a calendar backend, which must already have an open
+ * calendar.
+ *
+ * Returns: The URI where the calendar is stored.
+ **/
+const gchar *
+e_cal_backend_get_uri (ECalBackend *backend)
+{
+	g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
+
+	return backend->priv->uri;
+}
+
+/**
+ * e_cal_backend_get_kind:
+ * @backend: an #ECalBackend
+ *
+ * Gets the kind of components the given backend stores.
+ *
+ * Returns: The kind of components for this backend.
+ */
+icalcomponent_kind
+e_cal_backend_get_kind (ECalBackend *backend)
+{
+	g_return_val_if_fail (E_IS_CAL_BACKEND (backend), ICAL_NO_COMPONENT);
+
+	return backend->priv->kind;
+}
+
+/**
+ * e_cal_backend_is_online:
+ * @backend: an #ECalBackend
+ *
+ * Returns: Whether is backend online.
+ **/
+gboolean
+e_cal_backend_is_online (ECalBackend *backend)
+{
+	g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
+
+	return backend->priv->online;
+}
+
+/**
+ * e_cal_backend_is_opened:
+ * @backend: an #ECalBackend
+ *
+ * Checks if @backend's storage has been opened (and
+ * authenticated, if necessary) and the backend itself
+ * is ready for accessing. This property is changed automatically
+ * within call of e_cal_backend_notify_opened().
+ *
+ * Returns: %TRUE if fully opened, %FALSE otherwise.
+ **/
+gboolean
+e_cal_backend_is_opened (ECalBackend *backend)
+{
+	g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
+
+	return backend->priv->opened;
+}
+
+/**
+ * e_cal_backend_is_opening::
+ * @backend: an #ECalBackend
+ *
+ * Checks if @backend is processing its opening phase, which
+ * includes everything since the e_cal_backend_open() call,
+ * through authentication, up to e_cal_backend_notify_opened().
+ * This property is managed automatically and the backend deny
+ * every operation except of cancel and authenticate_user while
+ * it is being opening.
+ *
+ * Returns: %TRUE if opening phase is in the effect, %FALSE otherwise.
+ **/
+gboolean
+e_cal_backend_is_opening (ECalBackend *backend)
+{
+	g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
+
+	return backend->priv->opening;
+}
+
+/**
+ * e_cal_backend_is_readonly:
+ * @backend: an #ECalBackend
+ *
+ * Returns: Whether is backend read-only. This value is the last used
+ * in a call of e_cal_backend_notify_readonly().
+ **/
+gboolean
+e_cal_backend_is_readonly (ECalBackend *backend)
+{
+	g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
+
+	return backend->priv->readonly;
+}
+
+/**
+ * e_cal_backend_is_removed:
+ * @backend: an #ECalBackend
+ *
+ * Checks if @backend has been removed from its physical storage.
+ *
+ * Returns: %TRUE if @backend has been removed, %FALSE otherwise.
+ **/
+gboolean
+e_cal_backend_is_removed (ECalBackend *backend)
+{
+	g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
+
+	return backend->priv->removed;
+}
+
+/**
+ * e_cal_backend_set_is_removed:
+ * @backend: an #ECalBackend
+ * @is_removed: A flag indicating whether the backend's storage was removed
+ *
+ * Sets the flag indicating whether @backend was removed to @is_removed.
+ * Meant to be used by backend implementations.
+ **/
+void
+e_cal_backend_set_is_removed (ECalBackend *backend, gboolean is_removed)
+{
+	g_return_if_fail (E_IS_CAL_BACKEND (backend));
+
+	backend->priv->removed = is_removed;
 }
 
 /**
@@ -415,52 +601,60 @@ e_cal_backend_set_cache_dir (ECalBackend *backend,
 }
 
 /**
- * e_cal_backend_get_kind:
- * @backend: an #ECalBackend
- *
- * Gets the kind of components the given backend stores.
- *
- * Returns: The kind of components for this backend.
- */
-icalcomponent_kind
-e_cal_backend_get_kind (ECalBackend *backend)
-{
-	g_return_val_if_fail (E_IS_CAL_BACKEND (backend), ICAL_NO_COMPONENT);
-
-	return backend->priv->kind;
-}
-
-/**
- * e_cal_backend_get_source:
+ * e_cal_backend_get_backend_property:
  * @backend: an #ECalBackend
- *
- * Gets the #ESource associated with the given backend.
- *
- * Returns: The #ESource for the backend.
- */
-ESource *
-e_cal_backend_get_source (ECalBackend *backend)
+ * @cal: an #EDataCal
+ * @opid: the ID to use for this operation
+ * @cancellable: a #GCancellable for the operation
+ * @prop_name: property name to get value of; cannot be NULL
+ *
+ * Calls the get_backend_property method on the given backend.
+ * This might be finished with e_data_cal_respond_get_backend_property().
+ * Default implementation takes care of common properties and returns
+ * an 'unsupported' error for any unknown properties. The subclass may
+ * always call this default implementation for properties which fetching
+ * it doesn't overwrite.
+ *
+ * Since: 3.2
+ **/
+void
+e_cal_backend_get_backend_property (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *prop_name)
 {
-	g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (E_IS_CAL_BACKEND (backend));
+	g_return_if_fail (prop_name != NULL);
+	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_backend_property != NULL);
 
-	return backend->priv->source;
+	(* E_CAL_BACKEND_GET_CLASS (backend)->get_backend_property) (backend, cal, opid, cancellable, prop_name);
 }
 
 /**
- * e_cal_backend_get_uri:
+ * e_cal_backend_set_backend_property:
  * @backend: an #ECalBackend
- *
- * Queries the URI of a calendar backend, which must already have an open
- * calendar.
- *
- * Returns: The URI where the calendar is stored.
+ * @cal: an #EDataCal
+ * @opid: the ID to use for this operation
+ * @cancellable: a #GCancellable for the operation
+ * @prop_name: property name to change; cannot be NULL
+ * @prop_value: value to set to @prop_name; cannot be NULL
+ *
+ * Calls the set_backend_property method on the given backend.
+ * This might be finished with e_data_cal_respond_set_backend_property().
+ * Default implementation simply returns an 'unsupported' error.
+ * The subclass may always call this default implementation for properties
+ * which fetching it doesn't overwrite.
+ *
+ * Since: 3.2
  **/
-const gchar *
-e_cal_backend_get_uri (ECalBackend *backend)
+void
+e_cal_backend_set_backend_property (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *prop_name, const gchar *prop_value)
 {
-	g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (E_IS_CAL_BACKEND (backend));
+	g_return_if_fail (prop_name != NULL);
+	g_return_if_fail (prop_value != NULL);
+	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->set_backend_property != NULL);
 
-	return backend->priv->uri;
+	(* E_CAL_BACKEND_GET_CLASS (backend)->set_backend_property) (backend, cal, opid, cancellable, prop_name, prop_value);
 }
 
 static void
@@ -493,7 +687,7 @@ e_cal_backend_add_client (ECalBackend *backend, EDataCal *cal)
 	g_object_weak_ref (G_OBJECT (cal), cal_destroy_cb, backend);
 
 	g_mutex_lock (priv->clients_mutex);
-	priv->clients = g_list_append (priv->clients, cal);
+	priv->clients = g_slist_append (priv->clients, cal);
 	g_mutex_unlock (priv->clients_mutex);
 }
 
@@ -517,7 +711,7 @@ e_cal_backend_remove_client_private (ECalBackend *backend, EDataCal *cal, gboole
 
 	/* Disconnect */
 	g_mutex_lock (priv->clients_mutex);
-	priv->clients = g_list_remove (priv->clients, cal);
+	priv->clients = g_slist_remove (priv->clients, cal);
 	g_mutex_unlock (priv->clients_mutex);
 
 	/* When all clients go away, notify the parent factory about it so that
@@ -541,773 +735,598 @@ e_cal_backend_remove_client (ECalBackend *backend, EDataCal *cal)
 }
 
 /**
- * e_cal_backend_add_query:
+ * e_cal_backend_add_view:
  * @backend: an #ECalBackend
- * @query: An #EDataCalView object.
+ * @view: An #EDataCalView object.
  *
- * Adds a query to the list of live queries being run by the given backend.
- * Doing so means that any listener on the query will get notified of any
- * change that affect the live query.
+ * Adds a view to the list of live views being run by the given backend.
+ * Doing so means that any listener on the view will get notified of any
+ * change that affect the live view.
  */
 void
-e_cal_backend_add_query (ECalBackend *backend, EDataCalView *query)
+e_cal_backend_add_view (ECalBackend *backend, EDataCalView *view)
 {
 	g_return_if_fail (backend != NULL);
 	g_return_if_fail (E_IS_CAL_BACKEND (backend));
 
-	g_mutex_lock (backend->priv->queries_mutex);
-
-	e_list_append (backend->priv->queries, query);
-
-	g_mutex_unlock (backend->priv->queries_mutex);
-}
+	g_mutex_lock (backend->priv->views_mutex);
 
-/**
- * e_cal_backend_get_queries:
- * @backend: an #ECalBackend
- *
- * Gets the list of live queries being run on the given backend.
- *
- * Returns: The list of live queries.
- */
-EList *
-e_cal_backend_get_queries (ECalBackend *backend)
-{
-	g_return_val_if_fail (backend != NULL, NULL);
-	g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
+	backend->priv->views = g_slist_append (backend->priv->views, view);
 
-	return backend->priv->queries;
+	g_mutex_unlock (backend->priv->views_mutex);
 }
 
 /**
- * e_cal_backend_remove_query
+ * e_cal_backend_remove_view
  * @backend: an #ECalBackend
- * @query: An #EDataCalView object, previously added with @ref e_cal_backend_add_query.
+ * @view: An #EDataCalView object, previously added with @ref e_cal_backend_add_view.
  *
- * Removes query from the list of live queries for the backend.
+ * Removes view from the list of live views for the backend.
  *
  * Since: 2.24
  **/
 void
-e_cal_backend_remove_query (ECalBackend *backend, EDataCalView *query)
+e_cal_backend_remove_view (ECalBackend *backend, EDataCalView *view)
 {
 	g_return_if_fail (backend != NULL);
 	g_return_if_fail (E_IS_CAL_BACKEND (backend));
 
-	g_mutex_lock (backend->priv->queries_mutex);
+	g_mutex_lock (backend->priv->views_mutex);
 
-	e_list_remove (backend->priv->queries, query);
+	backend->priv->views = g_slist_remove (backend->priv->views, view);
 
-	g_mutex_unlock (backend->priv->queries_mutex);
+	g_mutex_unlock (backend->priv->views_mutex);
 }
 
 /**
- * e_cal_backend_get_cal_address:
+ * e_cal_backend_foreach_view:
  * @backend: an #ECalBackend
+ * @callback: callback to call
+ * @user_data: user_data passed into the @callback
  *
- * Queries the cal address associated with a calendar backend, which
- * must already have an open calendar.
+ * Calls @callback for each known calendar view of this @backend.
+ * @callback returns %FALSE to stop further processing.
  **/
 void
-e_cal_backend_get_cal_address (ECalBackend *backend, EDataCal *cal, EServerMethodContext context)
+e_cal_backend_foreach_view (ECalBackend *backend, gboolean (* callback) (EDataCalView *view, gpointer user_data), gpointer user_data)
 {
-	g_return_if_fail (backend != NULL);
-	g_return_if_fail (E_IS_CAL_BACKEND (backend));
-
-	g_assert (CLASS (backend)->get_cal_address != NULL);
-
-	g_object_ref (backend);
-
-	(* CLASS (backend)->get_cal_address) (backend, cal, context);
+	const GSList *views;
+	EDataCalView *view;
+	gboolean stop = FALSE;
 
-	g_object_unref (backend);
-}
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (callback != NULL);
 
-void
-e_cal_backend_notify_readonly (ECalBackend *backend, gboolean read_only)
-{
-	ECalBackendPrivate *priv;
-	GList *l;
+	g_mutex_lock (backend->priv->views_mutex);
 
-	priv = backend->priv;
+	for (views = backend->priv->views; views && !stop; views = views->next) {
+		view = E_DATA_CAL_VIEW (views->data);
 
-	if (priv->notification_proxy) {
-		e_cal_backend_notify_readonly (priv->notification_proxy, read_only);
-		return;
+		g_object_ref (view);
+		stop = !callback (view, user_data);
+		g_object_unref (view);
 	}
-	for (l = priv->clients; l; l = l->next)
-		e_data_cal_notify_read_only (l->data, NULL /* Success */, read_only);
-}
-
-void
-e_cal_backend_notify_cal_address (ECalBackend *backend, EServerMethodContext context, gchar *address)
-{
-	ECalBackendPrivate *priv;
-	GList *l;
-
-	priv = backend->priv;
 
-	for (l = priv->clients; l; l = l->next)
-		e_data_cal_notify_cal_address (l->data, context, NULL /* Success */, address);
+	g_mutex_unlock (backend->priv->views_mutex);
 }
 
 /**
- * e_cal_backend_get_alarm_email_address:
+ * e_cal_backend_set_notification_proxy:
  * @backend: an #ECalBackend
- * @cal: an #EDataCal
+ * @proxy: The calendar backend to act as notification proxy.
  *
- * Calls the get_alarm_email_address method on the given backend.
+ * Sets the backend that will act as notification proxy for the given backend.
  */
 void
-e_cal_backend_get_alarm_email_address (ECalBackend *backend, EDataCal *cal, EServerMethodContext context)
+e_cal_backend_set_notification_proxy (ECalBackend *backend, ECalBackend *proxy)
 {
-	g_return_if_fail (backend != NULL);
 	g_return_if_fail (E_IS_CAL_BACKEND (backend));
 
-	g_assert (CLASS (backend)->get_alarm_email_address != NULL);
-
-	g_object_ref (backend);
-
-	(* CLASS (backend)->get_alarm_email_address) (backend, cal, context);
-
-	g_object_unref (backend);
+	backend->priv->notification_proxy = proxy;
 }
 
 /**
- *e_cal_backend_get_alarm_email_address:
- * @backend: an #ECalBackend
- * @cal: an #EDataCal
+ * e_cal_backend_set_online:
+ * @backend: A calendar backend
+ * @is_online: Whether is online
  *
- * Calls the get_ldap_attribute method of the given backend.
+ * Sets the online mode of the calendar
  */
 void
-e_cal_backend_get_ldap_attribute (ECalBackend *backend, EDataCal *cal, EServerMethodContext context)
+e_cal_backend_set_online (ECalBackend *backend, gboolean is_online)
 {
 	g_return_if_fail (backend != NULL);
 	g_return_if_fail (E_IS_CAL_BACKEND (backend));
+	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->set_online != NULL);
 
-	g_assert (CLASS (backend)->get_ldap_attribute != NULL);
-
-	g_object_ref (backend);
-
-	(* CLASS (backend)->get_ldap_attribute) (backend, cal, context);
-
-	g_object_unref (backend);
+	(* E_CAL_BACKEND_GET_CLASS (backend)->set_online) (backend, is_online);
 }
 
 /**
- * e_cal_backend_get_alarm_email_address:
+ * e_cal_backend_open:
  * @backend: an #ECalBackend
  * @cal: an #EDataCal
+ * @opid: the ID to use for this operation
+ * @cancellable: a #GCancellable for the operation
+ * @only_if_exists: Whether the calendar should be opened only if it already
+ * exists.  If FALSE, a new calendar will be created when the specified @uri
+ * does not exist.
  *
- * Calls the get_static_capabilities method on the given backend.
- */
+ * Opens a calendar backend with data from a calendar stored at the specified URI.
+ * This might be finished with e_data_cal_respond_open() or e_cal_backend_respond_opened(),
+ * though the overall opening phase finishes only after call
+ * of e_cal_backend_notify_opened() after which call the backend
+ * is either fully opened (including authentication against (remote)
+ * server/storage) or an error was encountered during this opening phase.
+ * 'opened' and 'opening' properties are updated automatically.
+ * The backend refuses all other operations until the opening phase is finished.
+ *
+ * The e_cal_backend_notify_opened() is called either from this function
+ * or from e_cal_backend_authenticate_user(), or after necessary steps
+ * initiated by these two functions.
+ *
+ * The opening phase usually works like this:
+ * 1) client requests open for the backend
+ * 2) server receives this request and calls e_cal_backend_open() - the opening phase begun
+ * 3) either the backend is opened during this call, and notifies client
+ *    with e_cal_backend_notify_opened() about that. This is usually
+ *    for local backends; their opening phase is finished
+ * 4) or the backend requires authentication, thus it notifies client
+ *    about that with e_cal_backend_notify_auth_required() and is
+ *    waiting for credentials, which will be received from client
+ *    by e_cal_backend_authenticate_user() call. Backend's opening
+ *    phase is still running in this case, thus it doesn't call
+ *    e_cal_backend_notify_opened() within e_cal_backend_open() call.
+ * 5) when backend receives credentials in e_cal_backend_authenticate_user()
+ *    then it tries to authenticate against a server/storage with them
+ *    and only after it knows result of the authentication, whether user
+ *    was or wasn't authenticated, it notifies client with the result
+ *    by e_cal_backend_notify_opened() and it's opening phase is
+ *    finished now. If there was no error returned then the backend is
+ *    considered opened, otherwise it's considered closed. Use AuthenticationFailed
+ *    error when the given credentials were rejected by the server/store, which
+ *    will result in a re-prompt on the client side, otherwise use AuthenticationRequired
+ *    if there was anything wrong with the given credentials. Set error's
+ *    message to a reason for a re-prompt, it'll be shown to a user.
+ * 6) client checks error returned from e_cal_backend_notify_opened() and
+ *    reprompts for a password if it was AuthenticationFailed. Otherwise
+ *    considers backend opened based on the error presence (no error means success).
+ *
+ * In any case, the call of e_cal_backend_open() should be always finished
+ * with e_data_cal_respond_open(), which has no influence on the opening phase,
+ * or alternatively with e_cal_backend_respond_opened(). Never use authentication
+ * errors in e_data_cal_respond_open() to notify the client the authentication is
+ * required, there is e_cal_backend_notify_auth_required() for this.
+ **/
 void
-e_cal_backend_get_static_capabilities (ECalBackend *backend, EDataCal *cal, EServerMethodContext context)
+e_cal_backend_open (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, gboolean only_if_exists)
 {
 	g_return_if_fail (backend != NULL);
 	g_return_if_fail (E_IS_CAL_BACKEND (backend));
+	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->open != NULL);
+
+	g_mutex_lock (backend->priv->clients_mutex);
+
+	if (e_cal_backend_is_opened (backend)) {
+		g_mutex_unlock (backend->priv->clients_mutex);
 
-	g_assert (CLASS (backend)->get_static_capabilities != NULL);
+		e_data_cal_report_readonly (cal, backend->priv->readonly);
+		e_data_cal_report_online (cal, backend->priv->online);
 
-	g_object_ref (backend);
+		e_cal_backend_respond_opened (backend, cal, opid, NULL);
+	} else if (e_cal_backend_is_opening (backend)) {
+		g_mutex_unlock (backend->priv->clients_mutex);
 
-	(* CLASS (backend)->get_static_capabilities) (backend, cal, context);
+		e_data_cal_respond_open (cal, opid, EDC_OPENING_ERROR);
+	} else {
+		backend->priv->opening = TRUE;
+		g_mutex_unlock (backend->priv->clients_mutex);
 
-	g_object_unref (backend);
+		(* E_CAL_BACKEND_GET_CLASS (backend)->open) (backend, cal, opid, cancellable, only_if_exists);
+	}
 }
 
 /**
- * e_cal_backend_open:
+ * e_cal_backend_authenticate_user:
  * @backend: an #ECalBackend
- * @cal: an #EDataCal
- * @only_if_exists: Whether the calendar should be opened only if it already
- * exists.  If FALSE, a new calendar will be created when the specified @uri
- * does not exist.
- * @username: User name to use for authentication (if needed).
- * @password: Password for @username.
- *
- * Opens a calendar backend with data from a calendar stored at the specified
- * URI.
- */
+ * @cancellable: a #GCancellable for the operation
+ * @credentials: #ECredentials to use for authentication
+ *
+ * Notifies @backend about @credentials provided by user to use
+ * for authentication. This notification is usually called during
+ * opening phase as a response to e_cal_backend_notify_auth_required()
+ * on the client side and it results in setting property 'opening' to %TRUE
+ * unless the backend is already opened. This function finishes opening
+ * phase, thus it should be finished with e_cal_backend_notify_opened().
+ *
+ * See information at e_cal_backend_open() for more details
+ * how the opening phase works.
+ **/
 void
-e_cal_backend_open (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, gboolean only_if_exists,
-		    const gchar *username, const gchar *password)
+e_cal_backend_authenticate_user (ECalBackend  *backend,
+				 GCancellable *cancellable,
+				 ECredentials *credentials)
 {
-	g_return_if_fail (backend != NULL);
 	g_return_if_fail (E_IS_CAL_BACKEND (backend));
+	g_return_if_fail (credentials != NULL);
+	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->authenticate_user);
 
-	g_assert (CLASS (backend)->open != NULL);
-
-	g_object_ref (backend);
+	if (!e_cal_backend_is_opened (backend))
+		backend->priv->opening = TRUE;
 
-	(* CLASS (backend)->open) (backend, cal, context, only_if_exists, username, password);
-
-	g_object_unref (backend);
+	(* E_CAL_BACKEND_GET_CLASS (backend)->authenticate_user) (backend, cancellable, credentials);
 }
 
 /**
- * e_cal_backend_refresh:
- * @backend: an #ECalBackend
- * @cal: an #EDataCal
- *
- * Refreshes the calendar being accessed by the given backend.
- *
- * Since: 2.30
- */
-void
-e_cal_backend_refresh (ECalBackend *backend, EDataCal *cal, EServerMethodContext context)
-{
-	g_return_if_fail (backend != NULL);
-	g_return_if_fail (E_IS_CAL_BACKEND (backend));
-
-	g_assert (CLASS (backend)->refresh != NULL);
-
-	g_object_ref (backend);
-
-	(* CLASS (backend)->refresh) (backend, cal, context);
-
-	g_object_unref (backend);
-}
-
-/**
- * e_cal_backend_remove:
+ * e_cal_backend_remove:
  * @backend: an #ECalBackend
  * @cal: an #EDataCal
+ * @opid: the ID to use for this operation
+ * @cancellable: a #GCancellable for the operation
  *
  * Removes the calendar being accessed by the given backend.
- */
+ * This might be finished with e_data_cal_respond_remove().
+ **/
 void
-e_cal_backend_remove (ECalBackend *backend, EDataCal *cal, EServerMethodContext context)
+e_cal_backend_remove (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable)
 {
 	g_return_if_fail (backend != NULL);
 	g_return_if_fail (E_IS_CAL_BACKEND (backend));
+	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->remove != NULL);
 
-	g_assert (CLASS (backend)->remove != NULL);
-
-	g_object_ref (backend);
-
-	(* CLASS (backend)->remove) (backend, cal, context);
-
-	g_object_unref (backend);
-}
-
-/**
- * e_cal_backend_is_loaded:
- * @backend: an #ECalBackend
- *
- * Queries whether a calendar backend has been loaded yet.
- *
- * Returns: TRUE if the backend has been loaded with data, FALSE
- * otherwise.
- */
-gboolean
-e_cal_backend_is_loaded (ECalBackend *backend)
-{
-	gboolean result;
-
-	g_return_val_if_fail (backend != NULL, FALSE);
-	g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
-
-	g_assert (CLASS (backend)->is_loaded != NULL);
-
-	g_object_ref (backend);
-
-	result = (* CLASS (backend)->is_loaded) (backend);
-
-	g_object_unref (backend);
-
-	return result;
+	if (e_cal_backend_is_opening (backend))
+		e_data_cal_respond_remove (cal, opid, EDC_OPENING_ERROR);
+	else
+		(* E_CAL_BACKEND_GET_CLASS (backend)->remove) (backend, cal, opid, cancellable);
 }
 
 /**
- * e_cal_backend_is_read_only
+ * e_cal_backend_refresh:
  * @backend: an #ECalBackend
  * @cal: an #EDataCal
+ * @opid: the ID to use for this operation
+ * @cancellable: a #GCancellable for the operation
  *
- * Queries whether a calendar backend is read only or not.
- *
- */
-void
-e_cal_backend_is_read_only (ECalBackend *backend, EDataCal *cal)
-{
-	g_return_if_fail (backend != NULL);
-	g_return_if_fail (E_IS_CAL_BACKEND (backend));
-
-	g_assert (CLASS (backend)->is_read_only != NULL);
-
-	g_object_ref (backend);
-
-	(* CLASS (backend)->is_read_only) (backend, cal);
-
-	g_object_unref (backend);
-}
-
-/**
- * e_cal_backend_start_query:
- * @backend: an #ECalBackend
- * @query: The query to be started.
- *
- * Starts a new live query on the given backend.
- */
-void
-e_cal_backend_start_query (ECalBackend *backend, EDataCalView *query)
-{
-	g_return_if_fail (backend != NULL);
-	g_return_if_fail (E_IS_CAL_BACKEND (backend));
-
-	g_assert (CLASS (backend)->start_query != NULL);
-
-	g_object_ref (backend);
-
-	(* CLASS (backend)->start_query) (backend, query);
-
-	g_object_unref (backend);
-}
-
-/**
- * e_cal_backend_get_mode:
- * @backend: an #ECalBackend
- *
- * Queries whether a calendar backend is connected remotely.
+ * Refreshes the calendar being accessed by the given backend.
+ * This might be finished with e_data_cal_respond_refresh(),
+ * and it might be called as soon as possible; it doesn't mean
+ * that the refreshing is done after calling that, the backend
+ * is only notifying client whether it started the refresh process
+ * or not.
  *
- * Returns: The current mode the calendar is in
+ * Since: 2.30
  **/
-CalMode
-e_cal_backend_get_mode (ECalBackend *backend)
-{
-	CalMode result;
-
-	g_return_val_if_fail (backend != NULL, FALSE);
-	g_return_val_if_fail (E_IS_CAL_BACKEND (backend), FALSE);
-
-	g_assert (CLASS (backend)->get_mode != NULL);
-
-	g_object_ref (backend);
-
-	result = (* CLASS (backend)->get_mode) (backend);
-
-	g_object_unref (backend);
-
-	return result;
-}
-
-/**
- * e_cal_backend_set_mode:
- * @backend: A calendar backend
- * @mode: Mode to change to
- *
- * Sets the mode of the calendar
- */
-void
-e_cal_backend_set_mode (ECalBackend *backend, CalMode mode)
-{
-	g_return_if_fail (backend != NULL);
-	g_return_if_fail (E_IS_CAL_BACKEND (backend));
-
-	g_assert (CLASS (backend)->set_mode != NULL);
-
-	g_object_ref (backend);
-
-	(* CLASS (backend)->set_mode) (backend, mode);
-
-	g_object_unref (backend);
-}
-
-/**
- * e_cal_backend_get_default_object:
- * @backend: an #ECalBackend
- * @cal: an #EDataCal
- *
- * Calls the get_default_object method on the given backend.
- */
 void
-e_cal_backend_get_default_object (ECalBackend *backend, EDataCal *cal, EServerMethodContext context)
+e_cal_backend_refresh (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable)
 {
 	g_return_if_fail (backend != NULL);
 	g_return_if_fail (E_IS_CAL_BACKEND (backend));
 
-	g_assert (CLASS (backend)->get_default_object != NULL);
-
-	g_object_ref (backend);
-
-	(* CLASS (backend)->get_default_object) (backend, cal, context);
-
-	g_object_unref (backend);
+	if (e_cal_backend_is_opening (backend))
+		e_data_cal_respond_refresh (cal, opid, EDC_OPENING_ERROR);
+	else if (!E_CAL_BACKEND_GET_CLASS (backend)->refresh)
+		e_data_cal_respond_refresh (cal, opid, EDC_ERROR (UnsupportedMethod));
+	else
+		(* E_CAL_BACKEND_GET_CLASS (backend)->refresh) (backend, cal, opid, cancellable);
 }
 
 /**
  * e_cal_backend_get_object:
  * @backend: an #ECalBackend
  * @cal: an #EDataCal
+ * @opid: the ID to use for this operation
+ * @cancellable: a #GCancellable for the operation
  * @uid: Unique identifier for a calendar object.
  * @rid: ID for the object's recurrence to get.
  *
  * Queries a calendar backend for a calendar object based on its unique
  * identifier and its recurrence ID (if a recurrent appointment).
- */
+ * This might be finished with e_data_cal_respond_get_object().
+ **/
 void
-e_cal_backend_get_object (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *uid, const gchar *rid)
+e_cal_backend_get_object (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *uid, const gchar *rid)
 {
 	g_return_if_fail (backend != NULL);
 	g_return_if_fail (E_IS_CAL_BACKEND (backend));
 	g_return_if_fail (uid != NULL);
+	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_object != NULL);
 
-	g_assert (CLASS (backend)->get_object != NULL);
-
-	g_object_ref (backend);
-
-	(* CLASS (backend)->get_object) (backend, cal, context, uid, rid);
-
-	g_object_unref (backend);
+	if (e_cal_backend_is_opening (backend))
+		e_data_cal_respond_get_object (cal, opid, EDC_OPENING_ERROR, NULL);
+	else
+		(* E_CAL_BACKEND_GET_CLASS (backend)->get_object) (backend, cal, opid, cancellable, uid, rid);
 }
 
 /**
  * e_cal_backend_get_object_list:
  * @backend: an #ECalBackend
  * @cal: an #EDataCal
+ * @opid: the ID to use for this operation
+ * @cancellable: a #GCancellable for the operation
  * @sexp: Expression to search for.
  *
  * Calls the get_object_list method on the given backend.
- */
-void
-e_cal_backend_get_object_list (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *sexp)
-{
-	g_return_if_fail (backend != NULL);
-	g_return_if_fail (E_IS_CAL_BACKEND (backend));
-
-	g_assert (CLASS (backend)->get_object_list != NULL);
-
-	g_object_ref (backend);
-
-	(* CLASS (backend)->get_object_list) (backend, cal, context, sexp);
-
-	g_object_unref (backend);
-}
-
-/**
- * e_cal_backend_get_attachment_list:
- * @backend: an #ECalBackend
- * @cal: an #EDataCal
- * @uid: Unique identifier for a calendar object.
- * @rid: ID for the object's recurrence to get.
- *
- * Queries a calendar backend for attachments present in a calendar object based
- * on its unique identifier and its recurrence ID (if a recurrent appointment).
- */
+ * This might be finished with e_data_cal_respond_get_object_list().
+ **/
 void
-e_cal_backend_get_attachment_list (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *uid, const gchar *rid)
+e_cal_backend_get_object_list (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *sexp)
 {
 	g_return_if_fail (backend != NULL);
 	g_return_if_fail (E_IS_CAL_BACKEND (backend));
-	g_return_if_fail (uid != NULL);
-
-	g_assert (CLASS (backend)->get_object != NULL);
-
-	g_object_ref (backend);
+	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_object_list != NULL);
 
-	(* CLASS (backend)->get_attachment_list) (backend, cal, context, uid, rid);
-
-	g_object_unref (backend);
+	if (e_cal_backend_is_opening (backend))
+		e_data_cal_respond_get_object_list (cal, opid, EDC_OPENING_ERROR, NULL);
+	else
+		(* E_CAL_BACKEND_GET_CLASS (backend)->get_object_list) (backend, cal, opid, cancellable, sexp);
 }
 
 /**
  * e_cal_backend_get_free_busy:
  * @backend: an #ECalBackend
  * @cal: an #EDataCal
+ * @opid: the ID to use for this operation
+ * @cancellable: a #GCancellable for the operation
  * @users: List of users to get free/busy information for.
  * @start: Start time for query.
  * @end: End time for query.
  *
- * Gets a free/busy object for the given time interval
- */
+ * Gets a free/busy object for the given time interval. Client side is
+ * notified about free/busy objects throug e_data_cal_report_free_busy_data().
+ * This might be finished with e_data_cal_respond_get_free_busy().
+ **/
 void
-e_cal_backend_get_free_busy (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, GList *users, time_t start, time_t end)
+e_cal_backend_get_free_busy (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const GSList *users, time_t start, time_t end)
 {
 	g_return_if_fail (backend != NULL);
 	g_return_if_fail (E_IS_CAL_BACKEND (backend));
 	g_return_if_fail (start != -1 && end != -1);
 	g_return_if_fail (start <= end);
+	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_free_busy != NULL);
 
-	g_assert (CLASS (backend)->get_free_busy != NULL);
-
-	g_object_ref (backend);
-
-	(* CLASS (backend)->get_free_busy) (backend, cal, context, users, start, end);
-
-	g_object_unref (backend);
-}
-
-/**
- * e_cal_backend_get_changes:
- * @backend: an #ECalBackend
- * @cal: an #EDataCal
- * @change_id: A unique uid for the callers change list
- *
- * Builds a sequence of objects and the type of change that occurred on them since
- * the last time the give change_id was seen
- */
-void
-e_cal_backend_get_changes (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *change_id)
-{
-	g_return_if_fail (backend != NULL);
-	g_return_if_fail (E_IS_CAL_BACKEND (backend));
-	g_return_if_fail (change_id != NULL);
-
-	g_assert (CLASS (backend)->get_changes != NULL);
-
-	g_object_ref (backend);
-
-	(* CLASS (backend)->get_changes) (backend, cal, context, change_id);
-
-	g_object_unref (backend);
-}
-
-/**
- * e_cal_backend_discard_alarm
- * @backend: an #ECalBackend
- * @cal: an #EDataCal
- * @uid: UID of the component to discard the alarm from.
- * @auid: Alarm ID.
- *
- * Discards an alarm from the given component. This allows the specific backend
- * to do whatever is needed to really discard the alarm.
- */
-void
-e_cal_backend_discard_alarm (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *uid, const gchar *auid)
-{
-	g_return_if_fail (backend != NULL);
-	g_return_if_fail (E_IS_CAL_BACKEND (backend));
-	g_return_if_fail (uid != NULL);
-	g_return_if_fail (auid != NULL);
-
-	g_assert (CLASS (backend)->discard_alarm != NULL);
-
-	g_object_ref (backend);
-
-	(* CLASS (backend)->discard_alarm) (backend, cal, context, uid, auid);
-
-	g_object_unref (backend);
+	if (e_cal_backend_is_opening (backend))
+		e_data_cal_respond_get_free_busy (cal, opid, EDC_OPENING_ERROR);
+	else
+		(* E_CAL_BACKEND_GET_CLASS (backend)->get_free_busy) (backend, cal, opid, cancellable, users, start, end);
 }
 
 /**
  * e_cal_backend_create_object:
  * @backend: an #ECalBackend
  * @cal: an #EDataCal
+ * @opid: the ID to use for this operation
+ * @cancellable: a #GCancellable for the operation
  * @calobj: The object to create.
  *
  * Calls the create_object method on the given backend.
- */
+ * This might be finished with e_data_cal_respond_create_object().
+ **/
 void
-e_cal_backend_create_object (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *calobj)
+e_cal_backend_create_object (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *calobj)
 {
 	g_return_if_fail (backend != NULL);
 	g_return_if_fail (E_IS_CAL_BACKEND (backend));
 	g_return_if_fail (calobj != NULL);
 
-	g_object_ref (backend);
-
-	if (CLASS (backend)->create_object)
-		(* CLASS (backend)->create_object) (backend, cal, context, calobj);
+	if (e_cal_backend_is_opening (backend))
+		e_data_cal_respond_create_object (cal, opid, EDC_OPENING_ERROR, NULL, NULL);
+	else if (E_CAL_BACKEND_GET_CLASS (backend)->create_object)
+		(* E_CAL_BACKEND_GET_CLASS (backend)->create_object) (backend, cal, opid, cancellable, calobj);
 	else
-		e_data_cal_notify_object_created (cal, context, EDC_ERROR (UnsupportedMethod), NULL, NULL);
-
-	g_object_unref (backend);
+		e_data_cal_respond_create_object (cal, opid, EDC_ERROR (UnsupportedMethod), NULL, NULL);
 }
 
 /**
  * e_cal_backend_modify_object:
  * @backend: an #ECalBackend
  * @cal: an #EDataCal
+ * @opid: the ID to use for this operation
+ * @cancellable: a #GCancellable for the operation
  * @calobj: Object to be modified.
  * @mod: Type of modification.
  *
  * Calls the modify_object method on the given backend.
- */
+ * This might be finished with e_data_cal_respond_modify_object().
+ **/
 void
-e_cal_backend_modify_object (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *calobj, CalObjModType mod)
+e_cal_backend_modify_object (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *calobj, CalObjModType mod)
 {
 	g_return_if_fail (backend != NULL);
 	g_return_if_fail (E_IS_CAL_BACKEND (backend));
 	g_return_if_fail (calobj != NULL);
 
-	g_object_ref (backend);
-
-	if (CLASS (backend)->modify_object)
-		(* CLASS (backend)->modify_object) (backend, cal, context, calobj, mod);
+	if (e_cal_backend_is_opening (backend))
+		e_data_cal_respond_modify_object (cal, opid, EDC_OPENING_ERROR, NULL, NULL);
+	else if (E_CAL_BACKEND_GET_CLASS (backend)->modify_object)
+		(* E_CAL_BACKEND_GET_CLASS (backend)->modify_object) (backend, cal, opid, cancellable, calobj, mod);
 	else
-		e_data_cal_notify_object_removed (cal, context, EDC_ERROR (UnsupportedMethod), NULL, NULL, NULL);
-
-	g_object_unref (backend);
+		e_data_cal_respond_modify_object (cal, opid, EDC_ERROR (UnsupportedMethod), NULL, NULL);
 }
 
 /**
  * e_cal_backend_remove_object:
  * @backend: an #ECalBackend
  * @cal: an #EDataCal
+ * @opid: the ID to use for this operation
+ * @cancellable: a #GCancellable for the operation
  * @uid: Unique identifier of the object to remove.
  * @rid: A recurrence ID.
  * @mod: Type of removal.
  *
  * Removes an object in a calendar backend.  The backend will notify all of its
  * clients about the change.
- */
+ * This might be finished with e_data_cal_respond_remove_object().
+ **/
 void
-e_cal_backend_remove_object (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *uid, const gchar *rid, CalObjModType mod)
+e_cal_backend_remove_object (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *uid, const gchar *rid, CalObjModType mod)
 {
 	g_return_if_fail (backend != NULL);
 	g_return_if_fail (E_IS_CAL_BACKEND (backend));
 	g_return_if_fail (uid != NULL);
+	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->remove_object != NULL);
 
-	g_assert (CLASS (backend)->remove_object != NULL);
-
-	g_object_ref (backend);
-
-	(* CLASS (backend)->remove_object) (backend, cal, context, uid, rid, mod);
-
-	g_object_unref (backend);
+	if (e_cal_backend_is_opening (backend))
+		e_data_cal_respond_remove_object (cal, opid, EDC_OPENING_ERROR, NULL, NULL, NULL);
+	else
+		(* E_CAL_BACKEND_GET_CLASS (backend)->remove_object) (backend, cal, opid, cancellable, uid, rid, mod);
 }
 
 /**
  * e_cal_backend_receive_objects:
  * @backend: an #ECalBackend
  * @cal: an #EDataCal
+ * @opid: the ID to use for this operation
+ * @cancellable: a #GCancellable for the operation
  * @calobj: iCalendar object.
  *
  * Calls the receive_objects method on the given backend.
- */
+ * This might be finished with e_data_cal_respond_receive_objects().
+ **/
 void
-e_cal_backend_receive_objects (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *calobj)
+e_cal_backend_receive_objects (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *calobj)
 {
 	g_return_if_fail (backend != NULL);
 	g_return_if_fail (E_IS_CAL_BACKEND (backend));
 	g_return_if_fail (calobj != NULL);
+	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->receive_objects != NULL);
 
-	g_assert (CLASS (backend)->receive_objects != NULL);
-
-	g_object_ref (backend);
-
-	(* CLASS (backend)->receive_objects) (backend, cal, context, calobj);
-
-	g_object_unref (backend);
+	if (e_cal_backend_is_opening (backend))
+		e_data_cal_respond_receive_objects (cal, opid, EDC_OPENING_ERROR);
+	else
+		(* E_CAL_BACKEND_GET_CLASS (backend)->receive_objects) (backend, cal, opid, cancellable, calobj);
 }
 
 /**
  * e_cal_backend_send_objects:
  * @backend: an #ECalBackend
  * @cal: an #EDataCal
+ * @opid: the ID to use for this operation
+ * @cancellable: a #GCancellable for the operation
  * @calobj: iCalendar object to be sent.
  *
  * Calls the send_objects method on the given backend.
- */
+ * This might be finished with e_data_cal_respond_send_objects().
+ **/
 void
-e_cal_backend_send_objects (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *calobj)
+e_cal_backend_send_objects (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *calobj)
 {
 	g_return_if_fail (backend != NULL);
 	g_return_if_fail (E_IS_CAL_BACKEND (backend));
 	g_return_if_fail (calobj != NULL);
+	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->send_objects != NULL);
 
-	g_assert (CLASS (backend)->send_objects != NULL);
-
-	g_object_ref (backend);
-
-	(* CLASS (backend)->send_objects) (backend, cal, context, calobj);
-
-	g_object_unref (backend);
+	if (e_cal_backend_is_opening (backend))
+		e_data_cal_respond_send_objects (cal, opid, EDC_OPENING_ERROR, NULL, NULL);
+	else
+		(* E_CAL_BACKEND_GET_CLASS (backend)->send_objects) (backend, cal, opid, cancellable, calobj);
 }
 
 /**
- * e_cal_backend_get_timezone:
+ * e_cal_backend_get_attachment_uris:
  * @backend: an #ECalBackend
  * @cal: an #EDataCal
- * @tzid: Unique identifier of a VTIMEZONE object. Note that this must not be
- * NULL.
+ * @opid: the ID to use for this operation
+ * @cancellable: a #GCancellable for the operation
+ * @uid: Unique identifier for a calendar object.
+ * @rid: ID for the object's recurrence to get.
  *
- * Returns the icaltimezone* corresponding to the TZID, or NULL if the TZID
- * can't be found.
- */
+ * Queries a calendar backend for attachments present in a calendar object based
+ * on its unique identifier and its recurrence ID (if a recurrent appointment).
+ * This might be finished with e_data_cal_respond_get_attachment_uris().
+ **/
 void
-e_cal_backend_get_timezone (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *tzid)
+e_cal_backend_get_attachment_uris (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *uid, const gchar *rid)
 {
 	g_return_if_fail (backend != NULL);
 	g_return_if_fail (E_IS_CAL_BACKEND (backend));
-	g_return_if_fail (tzid != NULL);
-
-	g_assert (CLASS (backend)->get_timezone != NULL);
-
-	g_object_ref (backend);
-
-	(* CLASS (backend)->get_timezone) (backend, cal, context, tzid);
+	g_return_if_fail (uid != NULL);
+	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_attachment_uris != NULL);
 
-	g_object_unref (backend);
+	if (e_cal_backend_is_opening (backend))
+		e_data_cal_respond_get_attachment_uris (cal, opid, EDC_OPENING_ERROR, NULL);
+	else
+		(* E_CAL_BACKEND_GET_CLASS (backend)->get_attachment_uris) (backend, cal, opid, cancellable, uid, rid);
 }
 
 /**
- * e_cal_backend_set_default_zone:
+ * e_cal_backend_discard_alarm:
  * @backend: an #ECalBackend
  * @cal: an #EDataCal
- * @tzobj: The timezone object, in a string.
+ * @opid: the ID to use for this operation
+ * @cancellable: a #GCancellable for the operation
+ * @uid: Unique identifier for a calendar object.
+ * @rid: ID for the object's recurrence to discard alarm in.
+ * @auid: Unique identifier of the alarm itself.
  *
- * Sets the default timezone for the calendar, which is used to resolve
- * DATE and floating DATE-TIME values.
- */
+ * Discards alarm @auid from the object identified by @uid and @rid.
+ * This might be finished with e_data_cal_respond_discard_alarm().
+ * Default implementation of this method returns Not Supported error.
+ **/
 void
-e_cal_backend_set_default_zone (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *tzobj)
+e_cal_backend_discard_alarm (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *uid, const gchar *rid, const gchar *auid)
 {
 	g_return_if_fail (backend != NULL);
 	g_return_if_fail (E_IS_CAL_BACKEND (backend));
-	g_return_if_fail (tzobj != NULL);
-
-	g_object_ref (backend);
-
-	(* CLASS (backend)->set_default_zone) (backend, cal, context, tzobj);
+	g_return_if_fail (uid != NULL);
+	g_return_if_fail (auid != NULL);
 
-	g_object_unref (backend);
+	if (e_cal_backend_is_opening (backend))
+		e_data_cal_respond_discard_alarm (cal, opid, EDC_OPENING_ERROR);
+	else if (E_CAL_BACKEND_GET_CLASS (backend)->discard_alarm)
+		(* E_CAL_BACKEND_GET_CLASS (backend)->discard_alarm) (backend, cal, opid, cancellable, uid, rid, auid);
+	else
+		e_data_cal_respond_discard_alarm (cal, opid, e_data_cal_create_error (NotSupported, NULL));
 }
 
 /**
- * e_cal_backend_add_timezone
+ * e_cal_backend_get_timezone:
  * @backend: an #ECalBackend
  * @cal: an #EDataCal
- * @tzobj: The timezone object, in a string.
+ * @opid: the ID to use for this operation
+ * @cancellable: a #GCancellable for the operation
+ * @tzid: Unique identifier of a VTIMEZONE object. Note that this must not be
+ * NULL.
  *
- * Add a timezone object to the given backend.
- */
+ * Returns the icaltimezone* corresponding to the TZID, or NULL if the TZID
+ * can't be found.
+ * This might be finished with e_data_cal_respond_get_timezone().
+ **/
 void
-e_cal_backend_add_timezone (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *tzobj)
+e_cal_backend_get_timezone (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *tzid)
 {
+	g_return_if_fail (backend != NULL);
 	g_return_if_fail (E_IS_CAL_BACKEND (backend));
-	g_return_if_fail (tzobj != NULL);
-	g_return_if_fail (CLASS (backend)->add_timezone != NULL);
-
-	g_object_ref (backend);
-
-	(* CLASS (backend)->add_timezone) (backend, cal, context, tzobj);
+	g_return_if_fail (tzid != NULL);
+	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->get_timezone != NULL);
 
-	g_object_unref (backend);
+	if (e_cal_backend_is_opening (backend))
+		e_data_cal_respond_get_timezone (cal, opid, EDC_OPENING_ERROR, NULL);
+	else
+		(* E_CAL_BACKEND_GET_CLASS (backend)->get_timezone) (backend, cal, opid, cancellable, tzid);
 }
 
 /**
- * e_cal_backend_internal_get_default_timezone:
+ * e_cal_backend_add_timezone
  * @backend: an #ECalBackend
+ * @cal: an #EDataCal
+ * @opid: the ID to use for this operation
+ * @cancellable: a #GCancellable for the operation
+ * @tzobj: The timezone object, in a string.
  *
- * Calls the internal_get_default_timezone method on the given backend.
- */
-icaltimezone *
-e_cal_backend_internal_get_default_timezone (ECalBackend *backend)
+ * Add a timezone object to the given backend.
+ * This might be finished with e_data_cal_respond_add_timezone().
+ **/
+void
+e_cal_backend_add_timezone (ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *tzobject)
 {
-	icaltimezone *timezone;
-
-	g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
-	g_return_val_if_fail (CLASS (backend)->internal_get_default_timezone != NULL, NULL);
-
-	g_object_ref (backend);
-
-	timezone = (* CLASS (backend)->internal_get_default_timezone) (backend);
-
-	g_object_unref (backend);
+	g_return_if_fail (E_IS_CAL_BACKEND (backend));
+	g_return_if_fail (tzobject != NULL);
+	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->add_timezone != NULL);
 
-	return timezone;
+	if (e_cal_backend_is_opening (backend))
+		e_data_cal_respond_add_timezone (cal, opid, EDC_OPENING_ERROR);
+	else
+		(* E_CAL_BACKEND_GET_CLASS (backend)->add_timezone) (backend, cal, opid, cancellable, tzobject);
 }
 
 /**
@@ -1320,38 +1339,59 @@ e_cal_backend_internal_get_default_timezone (ECalBackend *backend)
 icaltimezone *
 e_cal_backend_internal_get_timezone (ECalBackend *backend, const gchar *tzid)
 {
-	icaltimezone *timezone;
-
 	g_return_val_if_fail (E_IS_CAL_BACKEND (backend), NULL);
 	g_return_val_if_fail (tzid != NULL, NULL);
-	g_return_val_if_fail (CLASS (backend)->internal_get_timezone != NULL, NULL);
+	g_return_val_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->internal_get_timezone != NULL, NULL);
 
-	g_object_ref (backend);
-
-	timezone = (* CLASS (backend)->internal_get_timezone) (backend, tzid);
+	return (* E_CAL_BACKEND_GET_CLASS (backend)->internal_get_timezone) (backend, tzid);
+}
 
-	g_object_unref (backend);
+/**
+ * e_cal_backend_start_view:
+ * @backend: an #ECalBackend
+ * @view: The view to be started.
+ *
+ * Starts a new live view on the given backend.
+ */
+void
+e_cal_backend_start_view (ECalBackend *backend, EDataCalView *view)
+{
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (E_IS_CAL_BACKEND (backend));
+	g_return_if_fail (E_CAL_BACKEND_GET_CLASS (backend)->start_view != NULL);
 
-	return timezone;
+	(* E_CAL_BACKEND_GET_CLASS (backend)->start_view) (backend, view);
 }
 
 /**
- * e_cal_backend_set_notification_proxy:
+ * e_cal_backend_stop_view:
  * @backend: an #ECalBackend
- * @proxy: The calendar backend to act as notification proxy.
+ * @view: The view to be stopped.
  *
- * Sets the backend that will act as notification proxy for the given backend.
+ * Stops a previously started live view on the given backend.
+ *
+ * Since: 3.2
  */
 void
-e_cal_backend_set_notification_proxy (ECalBackend *backend, ECalBackend *proxy)
+e_cal_backend_stop_view (ECalBackend *backend, EDataCalView *view)
 {
-	ECalBackendPrivate *priv;
-
+	g_return_if_fail (backend != NULL);
 	g_return_if_fail (E_IS_CAL_BACKEND (backend));
 
-	priv = backend->priv;
+	/* backward compatibility, do not force each backend define this function */
+	if (!E_CAL_BACKEND_GET_CLASS (backend)->stop_view)
+		return;
 
-	priv->notification_proxy = proxy;
+	(* E_CAL_BACKEND_GET_CLASS (backend)->stop_view) (backend, view);
+}
+
+static gboolean
+object_created_cb (EDataCalView *view, gpointer calobj)
+{
+	if (e_data_cal_view_object_matches (view, calobj))
+		e_data_cal_view_notify_objects_added_1 (view, calobj);
+
+	return TRUE;
 }
 
 /**
@@ -1369,9 +1409,6 @@ void
 e_cal_backend_notify_object_created (ECalBackend *backend, const gchar *calobj)
 {
 	ECalBackendPrivate *priv;
-	EList *queries;
-	EIterator *iter;
-	EDataCalView *query;
 
 	priv = backend->priv;
 
@@ -1380,35 +1417,33 @@ e_cal_backend_notify_object_created (ECalBackend *backend, const gchar *calobj)
 		return;
 	}
 
-	queries = e_cal_backend_get_queries (backend);
-	iter = e_list_get_iterator (queries);
-
-	while (e_iterator_is_valid (iter)) {
-		query = QUERY (e_iterator_get (iter));
-
-		g_object_ref (query);
-		if (e_data_cal_view_object_matches (query, calobj))
-			e_data_cal_view_notify_objects_added_1 (query, calobj);
-		g_object_unref (query);
+	e_cal_backend_foreach_view (backend, object_created_cb, (gpointer) calobj);
+}
 
-		e_iterator_next (iter);
-	}
-	g_object_unref (iter);
+/**
+ * e_cal_backend_notify_objects_added:
+ *
+ * Since: 2.24
+ **/
+void
+e_cal_backend_notify_objects_added (ECalBackend *backend, EDataCalView *view, const GSList *objects)
+{
+	e_data_cal_view_notify_objects_added (view, objects);
 }
 
 static void
-match_query_and_notify (EDataCalView *query, const gchar *old_object, const gchar *object)
+match_view_and_notify (EDataCalView *view, const gchar *old_object, const gchar *object)
 {
 	gboolean old_match = FALSE, new_match = FALSE;
 
 	if (old_object)
-		old_match = e_data_cal_view_object_matches (query, old_object);
+		old_match = e_data_cal_view_object_matches (view, old_object);
 
-	new_match = e_data_cal_view_object_matches (query, object);
+	new_match = e_data_cal_view_object_matches (view, object);
 	if (old_match && new_match)
-		e_data_cal_view_notify_objects_modified_1 (query, object);
+		e_data_cal_view_notify_objects_modified_1 (view, object);
 	else if (new_match)
-		e_data_cal_view_notify_objects_added_1 (query, object);
+		e_data_cal_view_notify_objects_added_1 (view, object);
 	else if (old_match) {
 		ECalComponent *comp = NULL;
 
@@ -1416,7 +1451,7 @@ match_query_and_notify (EDataCalView *query, const gchar *old_object, const gcha
 		if (comp) {
 			ECalComponentId *id = e_cal_component_get_id (comp);
 
-			e_data_cal_view_notify_objects_removed_1 (query, id);
+			e_data_cal_view_notify_objects_removed_1 (view, id);
 
 			e_cal_component_free_id (id);
 			g_object_unref (comp);
@@ -1424,107 +1459,22 @@ match_query_and_notify (EDataCalView *query, const gchar *old_object, const gcha
 	}
 }
 
-/**
- * e_cal_backend_notify_view_progress_start
- * @backend: an #ECalBackend
- *
- * This methods has to be used before e_cal_backend_notify_view_progress.
- * Sets last notified percent value to 0.
- *
- * Since: 2.24
- **/
-void
-e_cal_backend_notify_view_progress_start (ECalBackend *backend)
-{
-	ECalBackendPrivate *priv;
-
-	priv = backend->priv;
-
-	priv->last_percent_notified = 0;
-}
-
-/**
- * e_cal_backend_notify_view_progress:
- * @backend: an #ECalBackend
- * @message: the UID of the removed object
- * @percent: percentage of the objects loaded in the view
- *
- * Notifies each of the backend's listeners about the view_progress in downloading the items.
- **/
-void
-e_cal_backend_notify_view_progress (ECalBackend *backend, const gchar *message, gint percent)
-{
-	ECalBackendPrivate *priv;
-	EList *queries;
-	EIterator *iter;
-	EDataCalView *query;
-
-	priv = backend->priv;
-
-	if (percent <= priv->last_percent_notified)
-		return;
-
-	priv->last_percent_notified = percent;
-
-	if (priv->notification_proxy) {
-		e_cal_backend_notify_view_progress (priv->notification_proxy, message, percent);
-		return;
-	}
-
-	queries = e_cal_backend_get_queries (backend);
-	iter = e_list_get_iterator (queries);
-
-	while (e_iterator_is_valid (iter)) {
-		query = QUERY (e_iterator_get (iter));
-
-		g_object_ref (query);
-
-		e_data_cal_view_notify_progress (query, message, percent);
-
-		g_object_unref (query);
-
-		e_iterator_next (iter);
-	}
-	g_object_unref (iter);
-}
+struct call_data {
+	const gchar *old_object;
+	const gchar *object;
+	const ECalComponentId *id;
+};
 
-/**
- * e_cal_backend_notify_view_done:
- * @backend: an #ECalBackend
- * @error: returns the error, if any, once the view is fully populated.
- *
- * Notifies each of the backend's listeners about the view_done in downloading the items.
- **/
-void
-e_cal_backend_notify_view_done (ECalBackend *backend, const GError *error)
+static gboolean
+call_match_and_notify (EDataCalView *view, gpointer user_data)
 {
-	ECalBackendPrivate *priv;
-	EList *queries;
-	EIterator *iter;
-	EDataCalView *query;
-
-	priv = backend->priv;
-
-	if (priv->notification_proxy) {
-		e_cal_backend_notify_view_done (priv->notification_proxy, error);
-		return;
-	}
-
-	queries = e_cal_backend_get_queries (backend);
-	iter = e_list_get_iterator (queries);
+	struct call_data *cd = user_data;
 
-	while (e_iterator_is_valid (iter)) {
-		query = QUERY (e_iterator_get (iter));
+	g_return_val_if_fail (user_data != NULL, FALSE);
 
-		g_object_ref (query);
+	match_view_and_notify (view, cd->old_object, cd->object);
 
-		e_data_cal_view_notify_done (query, error);
-
-		g_object_unref (query);
-
-		e_iterator_next (iter);
-	}
-	g_object_unref (iter);
+	return TRUE;
 }
 
 /**
@@ -1540,13 +1490,10 @@ e_cal_backend_notify_view_done (ECalBackend *backend, const GError *error)
  * modified by non-EDS clients.
  **/
 void
-e_cal_backend_notify_object_modified (ECalBackend *backend,
-				      const gchar *old_object, const gchar *object)
+e_cal_backend_notify_object_modified (ECalBackend *backend, const gchar *old_object, const gchar *object)
 {
 	ECalBackendPrivate *priv;
-	EList *queries;
-	EIterator *iter;
-	EDataCalView *query;
+	struct call_data cd;
 
 	priv = backend->priv;
 
@@ -1555,19 +1502,40 @@ e_cal_backend_notify_object_modified (ECalBackend *backend,
 		return;
 	}
 
-	queries = e_cal_backend_get_queries (backend);
-	iter = e_list_get_iterator (queries);
+	cd.old_object = old_object;
+	cd.object = object;
+	cd.id = NULL;
 
-	while (e_iterator_is_valid (iter)) {
-		query = QUERY (e_iterator_get (iter));
+	e_cal_backend_foreach_view (backend, call_match_and_notify, &cd);
+}
 
-		g_object_ref (query);
-		match_query_and_notify (query, old_object, object);
-		g_object_unref (query);
+/**
+ * e_cal_backend_notify_objects_modified:
+ *
+ * Since: 2.24
+ **/
+void
+e_cal_backend_notify_objects_modified (ECalBackend *backend, EDataCalView *view, const GSList *objects)
+{
+	e_data_cal_view_notify_objects_modified (view, objects);
+}
 
-		e_iterator_next (iter);
-	}
-	g_object_unref (iter);
+static gboolean
+object_removed_cb (EDataCalView *view, gpointer user_data)
+{
+	struct call_data *cd = user_data;
+
+	g_return_val_if_fail (user_data != NULL, FALSE);
+
+	if (cd->object == NULL) {
+		/* if object == NULL, it means the object has been completely
+		   removed from the backend */
+		if (!cd->old_object || e_data_cal_view_object_matches (view, cd->old_object))
+			e_data_cal_view_notify_objects_removed_1 (view, cd->id);
+	} else
+		match_view_and_notify (view, cd->old_object, cd->object);
+
+	return TRUE;
 }
 
 /**
@@ -1590,9 +1558,7 @@ e_cal_backend_notify_object_removed (ECalBackend *backend, const ECalComponentId
 				     const gchar *old_object, const gchar *object)
 {
 	ECalBackendPrivate *priv;
-	EList *queries;
-	EIterator *iter;
-	EDataCalView *query;
+	struct call_data cd;
 
 	priv = backend->priv;
 
@@ -1601,125 +1567,225 @@ e_cal_backend_notify_object_removed (ECalBackend *backend, const ECalComponentId
 		return;
 	}
 
-	queries = e_cal_backend_get_queries (backend);
-	iter = e_list_get_iterator (queries);
-
-	while (e_iterator_is_valid (iter)) {
-		query = QUERY (e_iterator_get (iter));
+	cd.old_object = old_object;
+	cd.object = object;
+	cd.id = id;
 
-		g_object_ref (query);
-
-		if (object == NULL) {
-			/* if object == NULL, it means the object has been completely
-			   removed from the backend */
-			if (!old_object || e_data_cal_view_object_matches (query, old_object))
-				e_data_cal_view_notify_objects_removed_1 (query, id);
-		} else
-			match_query_and_notify (query, old_object, object);
-
-		g_object_unref (query);
-
-		e_iterator_next (iter);
-	}
-	g_object_unref (iter);
+	e_cal_backend_foreach_view (backend, object_removed_cb, &cd);
 }
 
 /**
- * e_cal_backend_notify_objects_added:
+ * e_cal_backend_notify_objects_removed:
  *
  * Since: 2.24
  **/
 void
-e_cal_backend_notify_objects_added (ECalBackend *backend, EDataCalView *query, const GList *objects)
+e_cal_backend_notify_objects_removed (ECalBackend *backend, EDataCalView *view, const GSList *ids)
 {
-	e_data_cal_view_notify_objects_added (query, objects);
+	e_data_cal_view_notify_objects_removed (view, ids);
 }
 
 /**
- * e_cal_backend_notify_objects_removed:
+ * e_cal_backend_notify_error:
+ * @backend: an #ECalBackend
+ * @message: Error message
  *
- * Since: 2.24
+ * Notifies each of the backend's listeners about an error
  **/
 void
-e_cal_backend_notify_objects_removed (ECalBackend *backend, EDataCalView *query, const GList *ids)
+e_cal_backend_notify_error (ECalBackend *backend, const gchar *message)
 {
-	e_data_cal_view_notify_objects_removed (query, ids);
+	ECalBackendPrivate *priv = backend->priv;
+	GSList *l;
+
+	if (priv->notification_proxy) {
+		e_cal_backend_notify_error (priv->notification_proxy, message);
+		return;
+	}
+
+	g_mutex_lock (priv->clients_mutex);
+
+	for (l = priv->clients; l; l = l->next)
+		e_data_cal_report_error (l->data, message);
+
+	g_mutex_unlock (priv->clients_mutex);
 }
 
 /**
- * e_cal_backend_notify_objects_modified:
+ * e_cal_backend_notify_readonly:
+ * @backend: an #ECalBackend
+ * @is_readonly: flag indicating readonly status
  *
- * Since: 2.24
+ * Notifies all backend's clients about the current readonly state.
+ * Meant to be used by backend implementations.
  **/
 void
-e_cal_backend_notify_objects_modified (ECalBackend *backend, EDataCalView *query, const GList *objects)
+e_cal_backend_notify_readonly (ECalBackend *backend, gboolean is_readonly)
 {
-	e_data_cal_view_notify_objects_modified (query, objects);
+	ECalBackendPrivate *priv;
+	GSList *l;
+
+	priv = backend->priv;
+	priv->readonly = is_readonly;
+
+	if (priv->notification_proxy) {
+		e_cal_backend_notify_readonly (priv->notification_proxy, is_readonly);
+		return;
+	}
+
+	g_mutex_lock (priv->clients_mutex);
+
+	for (l = priv->clients; l; l = l->next)
+		e_data_cal_report_readonly (l->data, is_readonly);
+
+	g_mutex_unlock (priv->clients_mutex);
 }
 
 /**
- * e_cal_backend_notify_mode:
+ * e_cal_backend_notify_online:
  * @backend: an #ECalBackend
- * @status: Status of the mode set
- * @mode: the current mode
+ * @is_online: flag indicating whether @backend is connected and online
  *
- * Notifies each of the backend's listeners about the results of a
- * setMode call.
+ * Notifies clients of @backend's connection status indicated by @is_online.
+ * Meant to be used by backend implementations.
  **/
 void
-e_cal_backend_notify_mode (ECalBackend *backend,
-			   EDataCalViewListenerSetModeStatus status,
-			   EDataCalMode mode)
+e_cal_backend_notify_online (ECalBackend *backend, gboolean is_online)
 {
-	ECalBackendPrivate *priv = backend->priv;
-	GList *l;
+	ECalBackendPrivate *priv;
+	GSList *clients;
+
+	priv = backend->priv;
+	priv->online = is_online;
 
 	if (priv->notification_proxy) {
-		e_cal_backend_notify_mode (priv->notification_proxy, status, mode);
+		e_cal_backend_notify_online (priv->notification_proxy, is_online);
 		return;
 	}
 
-	for (l = priv->clients; l; l = l->next)
-		e_data_cal_notify_mode (l->data, status, mode);
+	g_mutex_lock (priv->clients_mutex);
+
+	for (clients = priv->clients; clients != NULL; clients = g_slist_next (clients))
+		e_data_cal_report_online (E_DATA_CAL (clients->data), is_online);
+
+	g_mutex_unlock (priv->clients_mutex);
 }
 
 /**
  * e_cal_backend_notify_auth_required:
  * @backend: an #ECalBackend
+ * @is_self: Use %TRUE to indicate the authentication is required
+ *    for the @backend, otheriwse the authentication is for any
+ *    other source. Having @credentials %NULL means @is_self
+ *    automatically.
+ * @credentials: an #ECredentials that contains extra information for
+ *    a source for which authentication is requested.
+ *    This parameter can be NULL to indicate "for this calendar".
+ *
+ * Notifies clients that @backend requires authentication in order to
+ * connect. This function call does not influence 'opening', but 
+ * influences 'opened' property, which is set to %FALSE when @is_self
+ * is %TRUE or @credentials is %NULL. Opening phase is finished
+ * by e_cal_backend_notify_opened() if this is requested for @backend.
+ *
+ * See e_cal_backend_open() for a description how the whole opening
+ * phase works.
+ *
+ * Meant to be used by backend implementations.
+ **/
+void
+e_cal_backend_notify_auth_required (ECalBackend *backend, gboolean is_self, const ECredentials *credentials)
+{
+	ECalBackendPrivate *priv;
+	GSList *clients;
+
+	priv = backend->priv;
+
+	if (priv->notification_proxy) {
+		e_cal_backend_notify_auth_required (priv->notification_proxy, is_self, credentials);
+		return;
+	}
+
+	g_mutex_lock (priv->clients_mutex);
+
+	if (is_self || !credentials)
+		priv->opened = FALSE;
+
+	for (clients = priv->clients; clients != NULL; clients = g_slist_next (clients))
+		e_data_cal_report_auth_required (E_DATA_CAL (clients->data), credentials);
+
+	g_mutex_unlock (priv->clients_mutex);
+}
+
+/**
+ * e_cal_backend_notify_opened:
+ * @backend: an #ECalBackend
+ * @error: a #GError corresponding to the error encountered during
+ *    the opening phase. Use %NULL for success. The @error is freed
+ *    automatically if not %NULL.
  *
- * Notifies each of the backend's listeners that authentication is required to
- * open the calendar.
- */
+ * Notifies clients that @backend finished its opening phase.
+ * See e_cal_backend_open() for more information how the opening
+ * phase works. Calling this function changes 'opening' property,
+ * same as 'opened'. 'opening' is set to %FALSE and the backend
+ * is considered 'opened' only if the @error is %NULL.
+ *
+ * See also: e_cal_backend_respond_opened()
+ *
+ * Note: The @error is freed automatically if not %NULL.
+ *
+ * Meant to be used by backend implementations.
+ **/
 void
-e_cal_backend_notify_auth_required (ECalBackend *backend)
+e_cal_backend_notify_opened (ECalBackend *backend, GError *error)
 {
-	ECalBackendPrivate *priv = backend->priv;
-	GList *l;
+	ECalBackendPrivate *priv;
+	GSList *clients;
 
-	for (l = priv->clients; l; l = l->next)
-		e_data_cal_notify_auth_required (l->data);
+	priv = backend->priv;
+	g_mutex_lock (priv->clients_mutex);
+
+	priv->opening = FALSE;
+	priv->opened = error == NULL;
+
+	for (clients = priv->clients; clients != NULL; clients = g_slist_next (clients))
+		e_data_cal_report_opened (E_DATA_CAL (clients->data), error);
+
+	g_mutex_unlock (priv->clients_mutex);
+
+	if (error)
+		g_error_free (error);
 }
 
 /**
- * e_cal_backend_notify_error:
+ * e_cal_backend_respond_opened:
  * @backend: an #ECalBackend
- * @message: Error message
+ * @cal: an #EDataCal
+ * @opid: an operation ID
+ * @error: result error; can be %NULL, if it isn't then it's automatically freed
  *
- * Notifies each of the backend's listeners about an error
+ * This is a replacement for e_data_cal_respond_open() for cases where
+ * the finish of 'open' method call also finishes backend opening phase.
+ * This function covers calling of both e_data_cal_respond_open() and
+ * e_cal_backend_notify_opened() with the same @error.
+ *
+ * See e_cal_backend_open() for more details how the opening phase works.
  **/
 void
-e_cal_backend_notify_error (ECalBackend *backend, const gchar *message)
+e_cal_backend_respond_opened (ECalBackend *backend, EDataCal *cal, guint32 opid, GError *error)
 {
-	ECalBackendPrivate *priv = backend->priv;
-	GList *l;
+	GError *copy = NULL;
 
-	if (priv->notification_proxy) {
-		e_cal_backend_notify_error (priv->notification_proxy, message);
-		return;
-	}
+	g_return_if_fail (backend != NULL);
+	g_return_if_fail (E_IS_CAL_BACKEND (backend));
+	g_return_if_fail (cal != NULL);
+	g_return_if_fail (opid != 0);
 
-	for (l = priv->clients; l; l = l->next)
-		e_data_cal_notify_error (l->data, message);
+	if (error)
+		copy = g_error_copy (error);
+
+	e_data_cal_respond_open (cal, opid, error);
+	e_cal_backend_notify_opened (backend, copy);
 }
 
 /**
diff --git a/calendar/libedata-cal/e-cal-backend.h b/calendar/libedata-cal/e-cal-backend.h
index d9fccf8..360c4e4 100644
--- a/calendar/libedata-cal/e-cal-backend.h
+++ b/calendar/libedata-cal/e-cal-backend.h
@@ -23,8 +23,8 @@
 #ifndef E_CAL_BACKEND_H
 #define E_CAL_BACKEND_H
 
-#include "libedataserver/e-list.h"
-#include "libedataserver/e-source.h"
+#include <libedataserver/e-credentials.h>
+#include <libedataserver/e-source.h>
 #include <libecal/e-cal-util.h>
 #include <libecal/e-cal-component.h>
 #include "e-data-cal-common.h"
@@ -38,11 +38,20 @@ G_BEGIN_DECLS
 
 #define E_TYPE_CAL_BACKEND            (e_cal_backend_get_type ())
 #define E_CAL_BACKEND(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_TYPE_CAL_BACKEND, ECalBackend))
-#define E_CAL_BACKEND_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_CAL_BACKEND,		\
-				     ECalBackendClass))
+#define E_CAL_BACKEND_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), E_TYPE_CAL_BACKEND, ECalBackendClass))
 #define E_IS_CAL_BACKEND(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_TYPE_CAL_BACKEND))
 #define E_IS_CAL_BACKEND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), E_TYPE_CAL_BACKEND))
-#define E_CAL_BACKEND_GET_CLASS(obj) (E_CAL_BACKEND_CLASS (G_OBJECT_GET_CLASS (obj)))
+#define E_CAL_BACKEND_GET_CLASS(obj)  (E_CAL_BACKEND_CLASS (G_OBJECT_GET_CLASS (obj)))
+
+#define CLIENT_BACKEND_PROPERTY_OPENED			"opened"
+#define CLIENT_BACKEND_PROPERTY_OPENING			"opening"
+#define CLIENT_BACKEND_PROPERTY_ONLINE			"online"
+#define CLIENT_BACKEND_PROPERTY_READONLY		"readonly"
+#define CLIENT_BACKEND_PROPERTY_CACHE_DIR		"cache-dir"
+#define CLIENT_BACKEND_PROPERTY_CAPABILITIES		"capabilities"
+#define CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS		"cal-email-address"
+#define CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS	"alarm-email-address"
+#define CAL_BACKEND_PROPERTY_DEFAULT_OBJECT		"default-object"
 
 struct _ECalBackendCache;
 
@@ -57,136 +66,106 @@ struct _ECalBackend {
 struct _ECalBackendClass {
 	GObjectClass parent_class;
 
-	/* Notification signals */
-	void (* last_client_gone) (ECalBackend *backend);
-	void (* cal_added) (ECalBackend *backend, EDataCal *cal);
-
 	/* Virtual methods */
-	gboolean (* is_loaded) (ECalBackend *backend);
-	void (* is_read_only) (ECalBackend *backend, EDataCal *cal);
-	void (* get_cal_address) (ECalBackend *backend, EDataCal *cal, EServerMethodContext context);
-	void (* get_alarm_email_address) (ECalBackend *backend, EDataCal *cal, EServerMethodContext context);
-	void (* get_ldap_attribute) (ECalBackend *backend, EDataCal *cal, EServerMethodContext context);
-	void (* get_static_capabilities) (ECalBackend *backend, EDataCal *cal, EServerMethodContext context);
-
-	void (* open) (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, gboolean only_if_exists, const gchar *username, const gchar *password);
-	void (* refresh) (ECalBackend *backend, EDataCal *cal, EServerMethodContext context);
-	void (* remove) (ECalBackend *backend, EDataCal *cal, EServerMethodContext context);
-
-	/* Object related virtual methods */
-	void (* create_object) (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *calobj);
-	void (* modify_object) (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *calobj, CalObjModType mod);
-	void (* remove_object) (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *uid, const gchar *rid, CalObjModType mod);
-
-	void (* discard_alarm) (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *uid, const gchar *auid);
-
-	void (* receive_objects) (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *calobj);
-	void (* send_objects) (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *calobj);
-
-	void (* get_default_object) (ECalBackend *backend, EDataCal *cal, EServerMethodContext context);
-	void (* get_object) (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *uid, const gchar *rid);
-	void (* get_object_list) (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *sexp);
-
-	void (* get_attachment_list) (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *uid, const gchar *rid);
-
-	/* Timezone related virtual methods */
-	void (* get_timezone) (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *tzid);
-	void (* add_timezone) (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *object);
-	void (* set_default_zone) (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *tzobj);
+        void	(* get_backend_property)	(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *prop_name);
+        void	(* set_backend_property)	(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *prop_name, const gchar *prop_value);
+
+	void	(* open)			(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, gboolean only_if_exists);
+	void	(* remove)			(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable);
+	void	(* set_online)			(ECalBackend *backend, gboolean is_online);
+	void	(* authenticate_user)		(ECalBackend *backend, GCancellable *cancellable, ECredentials *credentials);
+
+	void	(* refresh)			(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable);
+	void	(* get_object)			(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *uid, const gchar *rid);
+	void	(* get_object_list)		(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *sexp);
+	void	(* get_free_busy)		(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const GSList *users, time_t start, time_t end);
+	void	(* create_object)		(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *calobj);
+	void	(* modify_object)		(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *calobj, CalObjModType mod);
+	void	(* remove_object)		(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *uid, const gchar *rid, CalObjModType mod);
+	void	(* receive_objects)		(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *calobj);
+	void	(* send_objects)		(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *calobj);
+	void	(* get_attachment_uris)		(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *uid, const gchar *rid);
+	void	(* discard_alarm)		(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *uid, const gchar *rid, const gchar *auid);
+	void	(* get_timezone)		(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *tzid);
+	void	(* add_timezone)		(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *tzobject);
+
+	void	(* start_view)			(ECalBackend *backend, EDataCalView *view);
+	void	(* stop_view)			(ECalBackend *backend, EDataCalView *view);
 
-	void (* start_query) (ECalBackend *backend, EDataCalView *query);
-
-	/* Mode relate virtual methods */
-	CalMode (* get_mode) (ECalBackend *backend);
-	void    (* set_mode) (ECalBackend *backend, CalMode mode);
-
-	void (* get_free_busy) (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, GList *users, time_t start, time_t end);
-	void (* get_changes) (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *change_id);
+	/* Notification signals */
+	void	(* last_client_gone)		(ECalBackend *backend);
 
 	/* Internal methods for use only in the pcs */
-	icaltimezone *(* internal_get_default_timezone) (ECalBackend *backend);
 	icaltimezone *(* internal_get_timezone) (ECalBackend *backend, const gchar *tzid);
 };
 
-GType e_cal_backend_get_type (void);
-
-ESource *e_cal_backend_get_source (ECalBackend *backend);
-const gchar *e_cal_backend_get_uri (ECalBackend *backend);
-icalcomponent_kind e_cal_backend_get_kind (ECalBackend *backend);
-
-const gchar *e_cal_backend_get_cache_dir (ECalBackend *backend);
-void e_cal_backend_set_cache_dir (ECalBackend *backend, const gchar *cache_dir);
-
-void e_cal_backend_add_client (ECalBackend *backend, EDataCal *cal);
-void e_cal_backend_remove_client (ECalBackend *backend, EDataCal *cal);
-
-void e_cal_backend_add_query (ECalBackend *backend, EDataCalView *query);
-EList *e_cal_backend_get_queries (ECalBackend *backend);
-void e_cal_backend_remove_query (ECalBackend *backend, EDataCalView *query);
-
-void e_cal_backend_is_read_only (ECalBackend *backend, EDataCal *cal);
-void e_cal_backend_get_cal_address (ECalBackend *backend, EDataCal *cal, EServerMethodContext context);
-void e_cal_backend_get_alarm_email_address (ECalBackend *backend, EDataCal *cal, EServerMethodContext context);
-void e_cal_backend_get_ldap_attribute (ECalBackend *backend, EDataCal *cal, EServerMethodContext context);
-void e_cal_backend_get_static_capabilities (ECalBackend *backend, EDataCal *cal, EServerMethodContext context);
-
-void e_cal_backend_open (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, gboolean only_if_exists, const gchar *username, const gchar *password);
-void e_cal_backend_refresh (ECalBackend *backend, EDataCal *cal, EServerMethodContext context);
-void e_cal_backend_remove (ECalBackend *backend, EDataCal *cal, EServerMethodContext context);
-
-void e_cal_backend_create_object (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *calobj);
-void e_cal_backend_modify_object (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *calobj, CalObjModType mod);
-void e_cal_backend_remove_object (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *uid, const gchar *rid, CalObjModType mod);
-
-void e_cal_backend_discard_alarm (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *uid, const gchar *auid);
-
-void e_cal_backend_receive_objects (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *calobj);
-void e_cal_backend_send_objects (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *calobj);
-
-void e_cal_backend_get_default_object (ECalBackend *backend, EDataCal *cal, EServerMethodContext context);
-void e_cal_backend_get_object (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *uid, const gchar *rid);
-void e_cal_backend_get_object_list (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *sexp);
-void e_cal_backend_get_attachment_list (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *uid, const gchar *rid);
-
-gboolean e_cal_backend_is_loaded (ECalBackend *backend);
-
-void e_cal_backend_start_query (ECalBackend *backend, EDataCalView *query);
-
-CalMode e_cal_backend_get_mode (ECalBackend *backend);
-void e_cal_backend_set_mode (ECalBackend *backend, CalMode mode);
-
-void e_cal_backend_get_timezone (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *tzid);
-void e_cal_backend_add_timezone (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *object);
-void e_cal_backend_set_default_zone (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *tzobj);
-
-void e_cal_backend_get_changes (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, const gchar *change_id);
-void e_cal_backend_get_free_busy (ECalBackend *backend, EDataCal *cal, EServerMethodContext context, GList *users, time_t start, time_t end);
-
-icaltimezone* e_cal_backend_internal_get_default_timezone (ECalBackend *backend);
-icaltimezone* e_cal_backend_internal_get_timezone (ECalBackend *backend, const gchar *tzid);
-
-void e_cal_backend_set_notification_proxy (ECalBackend *backend, ECalBackend *proxy);
-void e_cal_backend_notify_object_created  (ECalBackend *backend, const gchar *calobj);
-void e_cal_backend_notify_object_modified (ECalBackend *backend, const gchar *old_object, const gchar *object);
-void e_cal_backend_notify_object_removed  (ECalBackend *backend, const ECalComponentId *id, const gchar *old_object, const gchar *object);
-
-void e_cal_backend_notify_mode      (ECalBackend *backend,
-				     EDataCalViewListenerSetModeStatus status,
-				     EDataCalMode mode);
-void e_cal_backend_notify_auth_required (ECalBackend *backend);
-void e_cal_backend_notify_error     (ECalBackend *backend, const gchar *message);
-
-void e_cal_backend_notify_view_done (ECalBackend *backend, const GError *error);
-void e_cal_backend_notify_view_progress_start (ECalBackend *backend);
-void e_cal_backend_notify_view_progress (ECalBackend *backend, const gchar *message, gint percent);
-void e_cal_backend_notify_readonly (ECalBackend *backend, gboolean read_only);
-void e_cal_backend_notify_cal_address (ECalBackend *backend, EServerMethodContext context, gchar *address);
-
-void e_cal_backend_notify_objects_added (ECalBackend *backend, EDataCalView *query, const GList *objects);
-void e_cal_backend_notify_objects_removed (ECalBackend *backend, EDataCalView *query, const GList *ids);
-void e_cal_backend_notify_objects_modified (ECalBackend *backend, EDataCalView *query, const GList *objects);
-
-void e_cal_backend_empty_cache (ECalBackend *backend, struct _ECalBackendCache *cache);
+GType		e_cal_backend_get_type			(void);
+
+ESource *	e_cal_backend_get_source		(ECalBackend *backend);
+const gchar *	e_cal_backend_get_uri			(ECalBackend *backend);
+icalcomponent_kind e_cal_backend_get_kind		(ECalBackend *backend);
+gboolean	e_cal_backend_is_online			(ECalBackend *backend);
+gboolean	e_cal_backend_is_opened			(ECalBackend *backend);
+gboolean	e_cal_backend_is_opening		(ECalBackend *backend);
+gboolean	e_cal_backend_is_readonly		(ECalBackend *backend);
+gboolean	e_cal_backend_is_removed		(ECalBackend *backend);
+
+const gchar *	e_cal_backend_get_cache_dir		(ECalBackend *backend);
+void		e_cal_backend_set_cache_dir		(ECalBackend *backend, const gchar *cache_dir);
+
+void		e_cal_backend_add_client		(ECalBackend *backend, EDataCal *cal);
+void		e_cal_backend_remove_client		(ECalBackend *backend, EDataCal *cal);
+
+void		e_cal_backend_add_view			(ECalBackend *backend, EDataCalView *view);
+void		e_cal_backend_remove_view		(ECalBackend *backend, EDataCalView *view);
+void		e_cal_backend_foreach_view		(ECalBackend *backend, gboolean (* callback) (EDataCalView *view, gpointer user_data), gpointer user_data);
+
+void		e_cal_backend_set_notification_proxy	(ECalBackend *backend, ECalBackend *proxy);
+
+void		e_cal_backend_get_backend_property	(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *prop_name);
+void		e_cal_backend_set_backend_property	(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *prop_name, const gchar *prop_value);
+
+void		e_cal_backend_set_online		(ECalBackend *backend, gboolean is_online);
+void		e_cal_backend_authenticate_user		(ECalBackend *backend, GCancellable *cancellable, ECredentials *credentials);
+
+void		e_cal_backend_open			(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, gboolean only_if_exists);
+void		e_cal_backend_remove			(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable);
+void		e_cal_backend_refresh			(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable);
+void		e_cal_backend_get_object		(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *uid, const gchar *rid);
+void		e_cal_backend_get_object_list		(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *sexp);
+void		e_cal_backend_get_free_busy		(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const GSList *users, time_t start, time_t end);
+void		e_cal_backend_create_object		(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *calobj);
+void		e_cal_backend_modify_object		(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *calobj, CalObjModType mod);
+void		e_cal_backend_remove_object		(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *uid, const gchar *rid, CalObjModType mod);
+void		e_cal_backend_receive_objects		(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *calobj);
+void		e_cal_backend_send_objects		(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *calobj);
+void		e_cal_backend_get_attachment_uris	(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *uid, const gchar *rid);
+void		e_cal_backend_discard_alarm		(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *uid, const gchar *rid, const gchar *auid);
+void		e_cal_backend_get_timezone		(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *tzid);
+void		e_cal_backend_add_timezone		(ECalBackend *backend, EDataCal *cal, guint32 opid, GCancellable *cancellable, const gchar *tzobject);
+icaltimezone *	e_cal_backend_internal_get_timezone	(ECalBackend *backend, const gchar *tzid);
+void		e_cal_backend_start_view		(ECalBackend *backend, EDataCalView *view);
+void		e_cal_backend_stop_view			(ECalBackend *backend, EDataCalView *view);
+
+void		e_cal_backend_notify_object_created	(ECalBackend *backend, const gchar *calobj);
+void		e_cal_backend_notify_objects_added	(ECalBackend *backend, EDataCalView *view, const GSList *objects);
+void		e_cal_backend_notify_object_modified	(ECalBackend *backend, const gchar *old_object, const gchar *object);
+void		e_cal_backend_notify_objects_modified	(ECalBackend *backend, EDataCalView *view, const GSList *objects);
+void		e_cal_backend_notify_object_removed	(ECalBackend *backend, const ECalComponentId *id, const gchar *old_object, const gchar *object);
+void		e_cal_backend_notify_objects_removed	(ECalBackend *backend, EDataCalView *view, const GSList *ids);
+
+void		e_cal_backend_notify_error		(ECalBackend *backend, const gchar *message);
+void		e_cal_backend_notify_readonly		(ECalBackend *backend, gboolean is_readonly);
+void		e_cal_backend_notify_online		(ECalBackend *backend, gboolean is_online);
+void		e_cal_backend_notify_auth_required	(ECalBackend *backend, gboolean is_self, const ECredentials *credentials);
+void		e_cal_backend_notify_opened		(ECalBackend *backend, GError *error);
+
+void		e_cal_backend_empty_cache		(ECalBackend *backend, struct _ECalBackendCache *cache);
+
+/* protected functions for subclasses */
+void		e_cal_backend_set_is_removed		(ECalBackend *backend, gboolean is_removed);
+
+void		e_cal_backend_respond_opened		(ECalBackend *backend, EDataCal *cal, guint32 opid, GError *error);
 
 G_END_DECLS
 
diff --git a/calendar/libedata-cal/e-data-cal-common.h b/calendar/libedata-cal/e-data-cal-common.h
index e81fb34..e03fc15 100644
--- a/calendar/libedata-cal/e-data-cal-common.h
+++ b/calendar/libedata-cal/e-data-cal-common.h
@@ -39,9 +39,6 @@ typedef struct _EDataCalViewClass EDataCalViewClass;
 typedef struct _ECalBackendSExp ECalBackendSExp;
 typedef struct _ECalBackendSExpClass ECalBackendSExpClass;
 
-/* Opaque type for backend method context */
-typedef gpointer EServerMethodContext;
-
 
 
 G_END_DECLS
diff --git a/calendar/libedata-cal/e-data-cal-factory.c b/calendar/libedata-cal/e-data-cal-factory.c
index 38e1e68..8e64ffb 100644
--- a/calendar/libedata-cal/e-data-cal-factory.c
+++ b/calendar/libedata-cal/e-data-cal-factory.c
@@ -48,7 +48,7 @@
 #include "e-data-cal-factory.h"
 #include "e-cal-backend-loader-factory.h"
 
-#include "e-gdbus-egdbuscalfactory.h"
+#include "e-gdbus-cal-factory.h"
 
 #ifdef HAVE_ICAL_UNKNOWN_TOKEN_HANDLING
 #include <libical/ical.h>
@@ -97,7 +97,7 @@ struct _EDataCalFactoryPrivate {
 
 	GHashTable *connections;
 
-	gint mode;
+	gboolean is_online;
 
 	/* this is for notifications of source changes */
 	ESourceList *lists[E_CAL_SOURCE_TYPE_LAST];
@@ -297,6 +297,18 @@ calendar_freed_cb (EDataCalFactory *factory, GObject *dead)
 			10, (GSourceFunc) g_main_loop_quit, loop);
 }
 
+static void
+last_client_gone_cb (ECalBackend *backend, EDataCalFactory *factory)
+{
+	EDataCalFactoryPrivate *priv = factory->priv;
+
+	if (e_cal_backend_is_removed (backend)) {
+		g_mutex_lock (priv->backends_mutex);
+		g_hash_table_foreach_remove (priv->backends, remove_dead_calendar_cb, backend);
+		g_mutex_unlock (priv->backends_mutex);
+	}
+}
+
 struct find_backend_data {
 	const gchar *str_uri;
 	ECalBackend *backend;
@@ -329,7 +341,7 @@ find_backend_cb (gpointer key, gpointer value, gpointer data)
 }
 
 static gboolean
-impl_CalFactory_getCal (EGdbusCalFactory *object, GDBusMethodInvocation *invocation, const gchar *source_xml, guint type, EDataCalFactory *factory)
+impl_CalFactory_getCal (EGdbusCalFactory *object, GDBusMethodInvocation *invocation, const gchar * const *in_source_type, EDataCalFactory *factory)
 {
 	EDataCal *calendar;
 	EDataCalFactoryPrivate *priv = factory->priv;
@@ -343,15 +355,21 @@ impl_CalFactory_getCal (EGdbusCalFactory *object, GDBusMethodInvocation *invocat
 	const gchar *sender;
 	GList *list;
 	GError *error = NULL;
+	gchar *source_xml = NULL;
+	guint type = 0;
 
-	/* Remove a pending exit */
-	if (priv->exit_timeout) {
-		g_source_remove (priv->exit_timeout);
-		priv->exit_timeout = 0;
+	if (!e_gdbus_cal_factory_decode_get_cal (in_source_type, &source_xml, &type)) {
+		error = g_error_new (E_DATA_CAL_ERROR, NoSuchCal, _("Invalid call"));
+		g_dbus_method_invocation_return_gerror (invocation, error);
+		g_error_free (error);
+
+		return TRUE;
 	}
 
 	source = e_source_new_from_standalone_xml (source_xml);
 	if (!source) {
+		g_free (source_xml);
+
 		error = g_error_new (E_DATA_CAL_ERROR, NoSuchCal, _("Invalid source"));
 		g_dbus_method_invocation_return_gerror (invocation, error);
 		g_error_free (error);
@@ -359,6 +377,8 @@ impl_CalFactory_getCal (EGdbusCalFactory *object, GDBusMethodInvocation *invocat
 		return TRUE;
 	}
 
+	g_free (source_xml);
+
 	/* Get the URI so we can extract the protocol */
 	str_uri = e_source_get_uri (source);
 	if (!str_uri) {
@@ -469,12 +489,19 @@ impl_CalFactory_getCal (EGdbusCalFactory *object, GDBusMethodInvocation *invocat
 		g_hash_table_insert (
 			priv->backends, g_strdup (uid_type_string), backend);
 
-		e_cal_backend_set_mode (backend, priv->mode);
+		g_signal_connect (backend, "last-client-gone", G_CALLBACK (last_client_gone_cb), factory);
+		e_cal_backend_set_online (backend, priv->is_online);
 	} else if (!e_source_equal (source, e_cal_backend_get_source (backend))) {
 		/* source changed, update it in a backend */
 		update_source_in_backend (backend, source);
 	}
 
+	/* Remove a pending exit */
+	if (priv->exit_timeout) {
+		g_source_remove (priv->exit_timeout);
+		priv->exit_timeout = 0;
+	}
+
 	calendar = e_data_cal_new (backend, source);
 	e_cal_backend_add_client (backend, calendar);
 
@@ -503,11 +530,10 @@ cleanup2:
 	g_free (uid_type_string);
 	g_object_unref (source);
 
-	if (error) {
-		g_dbus_method_invocation_return_gerror (invocation, error);
+	e_gdbus_cal_factory_complete_get_cal (object, invocation, path, error);
+
+	if (error)
 		g_error_free (error);
-	} else
-		e_gdbus_cal_factory_complete_get_cal (object, invocation, path);
 
 	g_free (path);
 
@@ -640,27 +666,27 @@ set_backend_online_status (gpointer key, gpointer value, gpointer data)
 {
 	ECalBackend *backend = E_CAL_BACKEND (value);
 
-	e_cal_backend_set_mode (backend,  GPOINTER_TO_INT (data));
+	e_cal_backend_set_online (backend,  GPOINTER_TO_INT (data) != 0);
 }
 
 /**
- * e_data_cal_factory_set_backend_mode:
+ * e_data_cal_factory_set_backend_online:
  * @factory: A calendar factory.
- * @mode: Online mode to set.
+ * @is_online: Online mode to set.
  *
  * Sets the online mode for all backends created by the given factory.
  */
 void
-e_data_cal_factory_set_backend_mode (EDataCalFactory *factory, gint mode)
+e_data_cal_factory_set_backend_online (EDataCalFactory *factory, gboolean is_online)
 {
 	g_return_if_fail (E_IS_DATA_CAL_FACTORY (factory));
 
-	factory->priv->mode = mode;
+	factory->priv->is_online = is_online;
 	g_mutex_lock (factory->priv->backends_mutex);
 	g_hash_table_foreach (
 		factory->priv->backends,
 		set_backend_online_status,
-		GINT_TO_POINTER (factory->priv->mode));
+		GINT_TO_POINTER (factory->priv->is_online ? 1 : 0));
 	g_mutex_unlock (factory->priv->backends_mutex);
 }
 
@@ -842,8 +868,7 @@ offline_state_changed_cb (EOfflineListener *eol,
 
 	g_return_if_fail (state == EOL_STATE_ONLINE || state == EOL_STATE_OFFLINE);
 
-	e_data_cal_factory_set_backend_mode (
-		factory, state == EOL_STATE_ONLINE ? Remote : Local);
+	e_data_cal_factory_set_backend_online (factory, state == EOL_STATE_ONLINE);
 }
 
 static void
diff --git a/calendar/libedata-cal/e-data-cal-factory.h b/calendar/libedata-cal/e-data-cal-factory.h
index cd5afe6..3bf4779 100644
--- a/calendar/libedata-cal/e-data-cal-factory.h
+++ b/calendar/libedata-cal/e-data-cal-factory.h
@@ -55,16 +55,13 @@ typedef enum {
 GQuark e_data_cal_factory_error_quark (void);
 #define E_DATA_CAL_FACTORY_ERROR e_data_cal_factory_error_quark ()
 
-GType       e_data_cal_factory_get_type        (void);
+GType	e_data_cal_factory_get_type        (void);
 
-void        e_data_cal_factory_register_backend  (EDataCalFactory *factory,
-						  ECalBackendFactory *backend_factory);
-
-void	    e_data_cal_factory_register_backends    (EDataCalFactory    *factory);
-
-gint         e_data_cal_factory_get_n_backends       (EDataCalFactory *factory);
-void        e_data_cal_factory_dump_active_backends (EDataCalFactory *factory);
-void        e_data_cal_factory_set_backend_mode (EDataCalFactory *factory, gint mode);
+void	e_data_cal_factory_register_backend	(EDataCalFactory *factory, ECalBackendFactory *backend_factory);
+void	e_data_cal_factory_register_backends	(EDataCalFactory *factory);
+gint	e_data_cal_factory_get_n_backends	(EDataCalFactory *factory);
+void	e_data_cal_factory_dump_active_backends	(EDataCalFactory *factory);
+void	e_data_cal_factory_set_backend_online	(EDataCalFactory *factory, gboolean is_online);
 
 G_END_DECLS
 
diff --git a/calendar/libedata-cal/e-data-cal-types.h b/calendar/libedata-cal/e-data-cal-types.h
index fce65cc..d4f75f4 100644
--- a/calendar/libedata-cal/e-data-cal-types.h
+++ b/calendar/libedata-cal/e-data-cal-types.h
@@ -6,6 +6,7 @@ G_BEGIN_DECLS
 
 typedef enum {
 	Success,
+	Busy,
 	RepositoryOffline,
 	PermissionDenied,
 	InvalidRange,
@@ -39,12 +40,6 @@ typedef enum {
 } EDataCalCallStatus;
 
 typedef enum {
-	ModeSet,                    /* All OK */
-	ModeNotSet,                /* Generic error */
-	ModeNotSupported           /* Mode not supported */
-} EDataCalViewListenerSetModeStatus;
-
-typedef enum {
 	Event = 1 << 0,
 	Todo = 1 << 1,
 	Journal = 1 << 2,
@@ -58,12 +53,6 @@ typedef enum {
 	All = 0x07
 } EDataCalObjModType;
 
-typedef enum {
-	Local = 1 << 0,
-	Remote = 1 << 1,
-	AnyMode = 0x07
-} EDataCalMode;
-
 G_END_DECLS
 
 #endif /* __E_DATA_CAL_TYPES_H__ */
diff --git a/calendar/libedata-cal/e-data-cal-view.c b/calendar/libedata-cal/e-data-cal-view.c
index 78407aa..c0eea92 100644
--- a/calendar/libedata-cal/e-data-cal-view.c
+++ b/calendar/libedata-cal/e-data-cal-view.c
@@ -1,5 +1,5 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/* Evolution calendar - Live search query implementation
+/* Evolution calendar - Live search view implementation
  *
  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
  * Copyright (C) 2009 Intel Corporation
@@ -33,7 +33,7 @@
 #include "libedataserver/e-data-server-util.h"
 #include "e-cal-backend-sexp.h"
 #include "e-data-cal-view.h"
-#include "e-gdbus-egdbuscalview.h"
+#include "e-gdbus-cal-view.h"
 
 static void ensure_pending_flush_timeout (EDataCalView *view);
 
@@ -48,9 +48,9 @@ struct _EDataCalViewPrivate {
 
 	gboolean started;
 	gboolean stopped;
-	gboolean done;
+	gboolean complete;
 
-	/* Sexp that defines the query */
+	/* Sexp that defines the view */
 	ECalBackendSExp *sexp;
 
 	GArray *adds;
@@ -61,6 +61,9 @@ struct _EDataCalViewPrivate {
 
 	GMutex *pending_mutex;
 	guint flush_id;
+
+	/* which fields is listener interested in */
+	GHashTable *fields_of_interest;
 };
 
 G_DEFINE_TYPE (EDataCalView, e_data_cal_view, G_TYPE_OBJECT);
@@ -102,6 +105,43 @@ e_data_cal_view_class_init (EDataCalViewClass *klass)
 }
 
 static guint
+str_ic_hash (gconstpointer key)
+{
+	guint32 hash = 5381;
+	const gchar *str = key;
+	gint ii;
+
+	if (!str)
+		return hash;
+
+	for (ii = 0; str[ii]; ii++) {
+		hash = hash * 33 + g_ascii_tolower (str[ii]);
+	}
+
+	return hash;
+}
+
+static gboolean
+str_ic_equal (gconstpointer a, gconstpointer b)
+{
+	const gchar *stra = a, *strb = b;
+	gint ii;
+
+	if (!stra && !strb)
+		return TRUE;
+
+	if (!stra || !strb)
+		return FALSE;
+
+	for (ii = 0; stra[ii] && strb[ii]; ii++) {
+		if (g_ascii_tolower (stra[ii]) != g_ascii_tolower (strb[ii]))
+			return FALSE;
+	}
+
+	return stra[ii] == strb[ii];
+}
+
+static guint
 id_hash (gconstpointer key)
 {
 	const ECalComponentId *id = key;
@@ -118,11 +158,11 @@ id_equal (gconstpointer a, gconstpointer b)
 EDataCalView *
 e_data_cal_view_new (ECalBackend *backend, ECalBackendSExp *sexp)
 {
-	EDataCalView *query;
+	EDataCalView *view;
 
-	query = g_object_new (E_DATA_CAL_VIEW_TYPE, "backend", backend, "sexp", sexp, NULL);
+	view = g_object_new (E_DATA_CAL_VIEW_TYPE, "backend", backend, "sexp", sexp, NULL);
 
-	return query;
+	return view;
 }
 
 /**
@@ -131,14 +171,14 @@ e_data_cal_view_new (ECalBackend *backend, ECalBackendSExp *sexp)
  * Since: 2.32
  **/
 guint
-e_data_cal_view_register_gdbus_object (EDataCalView *query, GDBusConnection *connection, const gchar *object_path, GError **error)
+e_data_cal_view_register_gdbus_object (EDataCalView *view, GDBusConnection *connection, const gchar *object_path, GError **error)
 {
-	g_return_val_if_fail (query != NULL, 0);
-	g_return_val_if_fail (E_IS_DATA_CAL_VIEW (query), 0);
+	g_return_val_if_fail (view != NULL, 0);
+	g_return_val_if_fail (E_IS_DATA_CAL_VIEW (view), 0);
 	g_return_val_if_fail (connection != NULL, 0);
 	g_return_val_if_fail (object_path != NULL, 0);
 
-	return e_gdbus_cal_view_register_object (query->priv->gdbus_object, connection, object_path, error);
+	return e_gdbus_cal_view_register_object (view->priv->gdbus_object, connection, object_path, error);
 }
 
 static void
@@ -221,7 +261,7 @@ ensure_pending_flush_timeout (EDataCalView *view)
 	if (priv->flush_id)
 		return;
 
-	priv->flush_id = g_timeout_add (e_data_cal_view_is_done (view) ? 10 : (THRESHOLD_SECONDS * 1000), pending_flush_timeout_cb, view);
+	priv->flush_id = g_timeout_add (e_data_cal_view_is_completed (view) ? 10 : (THRESHOLD_SECONDS * 1000), pending_flush_timeout_cb, view);
 }
 
 static void
@@ -287,57 +327,94 @@ notify_remove (EDataCalView *view, ECalComponentId *id)
 }
 
 static void
-notify_done (EDataCalView *view, const GError *error)
+notify_complete (EDataCalView *view, const GError *error)
 {
-	gchar *gdbus_error_msg = NULL;
+	gchar **error_strv;
 
 	send_pending_adds (view);
 	send_pending_changes (view);
 	send_pending_removes (view);
 
-	e_gdbus_cal_view_emit_done (view->priv->gdbus_object, error ? error->code : 0, e_util_ensure_gdbus_string (error ? error->message : "", &gdbus_error_msg));
+	error_strv = e_gdbus_templates_encode_error (error);
+
+	e_gdbus_cal_view_emit_complete (view->priv->gdbus_object, (const gchar * const *) error_strv);
 
-	g_free (gdbus_error_msg);
+	g_strfreev (error_strv);
 }
 
 static gboolean
-impl_DataCalView_start (EGdbusCalView *object, GDBusMethodInvocation *invocation, EDataCalView *query)
+impl_DataCalView_start (EGdbusCalView *object, GDBusMethodInvocation *invocation, EDataCalView *view)
 {
 	EDataCalViewPrivate *priv;
 
-	priv = query->priv;
+	priv = view->priv;
 
 	if (!priv->started) {
 		priv->started = TRUE;
-		e_debug_log(FALSE, E_DEBUG_LOG_DOMAIN_CAL_QUERIES, "---;%p;QUERY-START;%s;%s", query, e_data_cal_view_get_text (query), G_OBJECT_TYPE_NAME(priv->backend));
-		e_cal_backend_start_query (priv->backend, query);
+		e_debug_log(FALSE, E_DEBUG_LOG_DOMAIN_CAL_QUERIES, "---;%p;VIEW-START;%s;%s", view, e_data_cal_view_get_text (view), G_OBJECT_TYPE_NAME(priv->backend));
+		e_cal_backend_start_view (priv->backend, view);
 	}
 
-	e_gdbus_cal_view_complete_start (object, invocation);
+	e_gdbus_cal_view_complete_start (object, invocation, NULL);
 
 	return TRUE;
 }
 
 static gboolean
-impl_DataCalView_stop (EGdbusCalView *object, GDBusMethodInvocation *invocation, EDataCalView *query)
+impl_DataCalView_stop (EGdbusCalView *object, GDBusMethodInvocation *invocation, EDataCalView *view)
 {
 	EDataCalViewPrivate *priv;
 
-	priv = query->priv;
+	priv = view->priv;
 
 	priv->stopped = TRUE;
 
-	e_gdbus_cal_view_complete_stop (object, invocation);
+	e_gdbus_cal_view_complete_stop (object, invocation, NULL);
+	e_cal_backend_stop_view (priv->backend, view);
 
 	return TRUE;
 }
 
 static gboolean
-impl_DataCalView_dispose (EGdbusCalView *object, GDBusMethodInvocation *invocation, EDataCalView *query)
+impl_DataCalView_dispose (EGdbusCalView *object, GDBusMethodInvocation *invocation, EDataCalView *view)
 {
-	e_gdbus_cal_view_complete_dispose (object, invocation);
+	e_gdbus_cal_view_complete_dispose (object, invocation, NULL);
+
+	view->priv->stopped = TRUE;
+	e_cal_backend_stop_view (view->priv->backend, view);
+
+	g_object_unref (view);
+
+	return TRUE;
+}
+
+static gboolean
+impl_DataCalView_setFieldsOfInterest (EGdbusCalView *object, GDBusMethodInvocation *invocation, const gchar * const *in_fields_of_interest, EDataCalView *view)
+{
+	EDataCalViewPrivate *priv;
+	gint ii;
+
+	g_return_val_if_fail (in_fields_of_interest != NULL, TRUE);
+
+	priv = view->priv;
+
+	if (priv->fields_of_interest)
+		g_hash_table_destroy (priv->fields_of_interest);
+	priv->fields_of_interest = NULL;
 
-	g_object_unref (query);
+	for (ii = 0; in_fields_of_interest[ii]; ii++) {
+		const gchar *field = in_fields_of_interest[ii];
+
+		if (!*field)
+			continue;
+
+		if (!priv->fields_of_interest)
+			priv->fields_of_interest = g_hash_table_new_full (str_ic_hash, str_ic_equal, g_free, NULL);
+
+		g_hash_table_insert (priv->fields_of_interest, g_strdup (field), GINT_TO_POINTER (1));
+	}
+
+	e_gdbus_cal_view_complete_set_fields_of_interest (object, invocation, NULL);
 
 	return TRUE;
 }
@@ -345,11 +422,11 @@ impl_DataCalView_dispose (EGdbusCalView *object, GDBusMethodInvocation *invocati
 static void
 e_data_cal_view_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
 {
-	EDataCalView *query;
+	EDataCalView *view;
 	EDataCalViewPrivate *priv;
 
-	query = QUERY (object);
-	priv = query->priv;
+	view = E_DATA_CAL_VIEW (object);
+	priv = view->priv;
 
 	switch (property_id) {
 	case PROP_BACKEND:
@@ -367,11 +444,11 @@ e_data_cal_view_set_property (GObject *object, guint property_id, const GValue *
 static void
 e_data_cal_view_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
 {
-	EDataCalView *query;
+	EDataCalView *view;
 	EDataCalViewPrivate *priv;
 
-	query = QUERY (object);
-	priv = query->priv;
+	view = E_DATA_CAL_VIEW (object);
+	priv = view->priv;
 
 	switch (property_id) {
 	case PROP_BACKEND:
@@ -388,23 +465,25 @@ e_data_cal_view_get_property (GObject *object, guint property_id, GValue *value,
 
 /* Instance init */
 static void
-e_data_cal_view_init (EDataCalView *query)
+e_data_cal_view_init (EDataCalView *view)
 {
 	EDataCalViewPrivate *priv = G_TYPE_INSTANCE_GET_PRIVATE (
-		query, E_DATA_CAL_VIEW_TYPE, EDataCalViewPrivate);
+		view, E_DATA_CAL_VIEW_TYPE, EDataCalViewPrivate);
 
-	query->priv = priv;
+	view->priv = priv;
 
 	priv->gdbus_object = e_gdbus_cal_view_stub_new ();
-	g_signal_connect (priv->gdbus_object, "handle-start", G_CALLBACK (impl_DataCalView_start), query);
-	g_signal_connect (priv->gdbus_object, "handle-stop", G_CALLBACK (impl_DataCalView_stop), query);
-	g_signal_connect (priv->gdbus_object, "handle-dispose", G_CALLBACK (impl_DataCalView_dispose), query);
+	g_signal_connect (priv->gdbus_object, "handle-start", G_CALLBACK (impl_DataCalView_start), view);
+	g_signal_connect (priv->gdbus_object, "handle-stop", G_CALLBACK (impl_DataCalView_stop), view);
+	g_signal_connect (priv->gdbus_object, "handle-dispose", G_CALLBACK (impl_DataCalView_dispose), view);
+	g_signal_connect (priv->gdbus_object, "handle-set-fields-of-interest", G_CALLBACK (impl_DataCalView_setFieldsOfInterest), view);
 
 	priv->backend = NULL;
 	priv->started = FALSE;
 	priv->stopped = FALSE;
-	priv->done = FALSE;
+	priv->complete = FALSE;
 	priv->sexp = NULL;
+	priv->fields_of_interest = NULL;
 
 	priv->adds = g_array_sized_new (TRUE, TRUE, sizeof (gchar *), THRESHOLD_ITEMS);
 	priv->changes = g_array_sized_new (TRUE, TRUE, sizeof (gchar *), THRESHOLD_ITEMS);
@@ -419,17 +498,17 @@ e_data_cal_view_init (EDataCalView *query)
 static void
 e_data_cal_view_dispose (GObject *object)
 {
-	EDataCalView *query;
+	EDataCalView *view;
 	EDataCalViewPrivate *priv;
 
 	g_return_if_fail (object != NULL);
-	g_return_if_fail (IS_QUERY (object));
+	g_return_if_fail (E_IS_DATA_CAL_VIEW (object));
 
-	query = QUERY (object);
-	priv = query->priv;
+	view = E_DATA_CAL_VIEW (object);
+	priv = view->priv;
 
 	if (priv->backend) {
-		e_cal_backend_remove_query (priv->backend, query);
+		e_cal_backend_remove_view (priv->backend, view);
 		g_object_unref (priv->backend);
 		priv->backend = NULL;
 	}
@@ -454,17 +533,28 @@ e_data_cal_view_dispose (GObject *object)
 static void
 e_data_cal_view_finalize (GObject *object)
 {
-	EDataCalView *query;
+	EDataCalView *view;
 	EDataCalViewPrivate *priv;
 
 	g_return_if_fail (object != NULL);
-	g_return_if_fail (IS_QUERY (object));
+	g_return_if_fail (E_IS_DATA_CAL_VIEW (object));
 
-	query = QUERY (object);
-	priv = query->priv;
+	view = E_DATA_CAL_VIEW (object);
+	priv = view->priv;
+
+	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);
 
 	g_hash_table_destroy (priv->ids);
 
+	if (priv->fields_of_interest)
+		g_hash_table_destroy (priv->fields_of_interest);
+
 	g_mutex_free (priv->pending_mutex);
 
 	(* G_OBJECT_CLASS (e_data_cal_view_parent_class)->finalize) (object);
@@ -472,83 +562,67 @@ e_data_cal_view_finalize (GObject *object)
 
 /**
  * e_data_cal_view_get_text:
- * @query: A #EDataCalView object.
+ * @view: A #EDataCalView object.
  *
- * Get the expression used for the given query.
+ * Get the expression used for the given view.
  *
- * Returns: the query expression used to search.
+ * Returns: the view expression used to search.
  */
 const gchar *
-e_data_cal_view_get_text (EDataCalView *query)
+e_data_cal_view_get_text (EDataCalView *view)
 {
-	g_return_val_if_fail (IS_QUERY (query), NULL);
+	g_return_val_if_fail (E_IS_DATA_CAL_VIEW (view), NULL);
 
-	return e_cal_backend_sexp_text (query->priv->sexp);
+	return e_cal_backend_sexp_text (view->priv->sexp);
 }
 
 /**
  * e_data_cal_view_get_object_sexp:
- * @query: A query object.
+ * @view: A view object.
  *
- * Get the #ECalBackendSExp object used for the given query.
+ * Get the #ECalBackendSExp object used for the given view.
  *
  * Returns: The expression object used to search.
  */
 ECalBackendSExp *
-e_data_cal_view_get_object_sexp (EDataCalView *query)
+e_data_cal_view_get_object_sexp (EDataCalView *view)
 {
-	g_return_val_if_fail (IS_QUERY (query), NULL);
+	g_return_val_if_fail (E_IS_DATA_CAL_VIEW (view), NULL);
 
-	return query->priv->sexp;
+	return view->priv->sexp;
 }
 
 /**
  * e_data_cal_view_object_matches:
- * @query: A query object.
+ * @view: A view object.
  * @object: Object to match.
  *
  * Compares the given @object to the regular expression used for the
- * given query.
+ * given view.
  *
  * Returns: TRUE if the object matches the expression, FALSE if not.
  */
 gboolean
-e_data_cal_view_object_matches (EDataCalView *query, const gchar *object)
+e_data_cal_view_object_matches (EDataCalView *view, const gchar *object)
 {
 	EDataCalViewPrivate *priv;
 
-	g_return_val_if_fail (query != NULL, FALSE);
-	g_return_val_if_fail (IS_QUERY (query), FALSE);
+	g_return_val_if_fail (view != NULL, FALSE);
+	g_return_val_if_fail (E_IS_DATA_CAL_VIEW (view), FALSE);
 	g_return_val_if_fail (object != NULL, FALSE);
 
-	priv = query->priv;
+	priv = view->priv;
 
 	return e_cal_backend_sexp_match_object (priv->sexp, object, priv->backend);
 }
 
 /**
- * e_data_cal_view_get_matched_objects:
- * @query: A query object.
- *
- * Gets the list of objects already matched for the given query.
- *
- * Returns: A list of matched objects.
- */
-GList *
-e_data_cal_view_get_matched_objects (EDataCalView *query)
-{
-	g_return_val_if_fail (IS_QUERY (query), NULL);
-	/* TODO e_data_cal_view_get_matched_objects */
-	return NULL;
-}
-
-/**
  * e_data_cal_view_is_started:
- * @query: A query object.
+ * @view: A view object.
  *
- * Checks whether the given query has already been started.
+ * Checks whether the given view has already been started.
  *
- * Returns: TRUE if the query has already been started, FALSE otherwise.
+ * Returns: TRUE if the view has already been started, FALSE otherwise.
  */
 gboolean
 e_data_cal_view_is_started (EDataCalView *view)
@@ -560,11 +634,11 @@ e_data_cal_view_is_started (EDataCalView *view)
 
 /**
  * e_data_cal_view_is_stopped:
- * @query: A query object.
+ * @view: A view object.
  *
- * Checks whether the given query has been stopped.
+ * Checks whether the given view has been stopped.
  *
- * Returns: TRUE if the query has been stopped, FALSE otherwise.
+ * Returns: TRUE if the view has been stopped, FALSE otherwise.
  *
  * Since: 2.32
  */
@@ -577,40 +651,56 @@ e_data_cal_view_is_stopped (EDataCalView *view)
 }
 
 /**
- * e_data_cal_view_is_done:
- * @query: A query object.
+ * e_data_cal_view_is_completed:
+ * @view: A view object.
  *
- * Checks whether the given query is already done. Being done means the initial
+ * Checks whether the given view is already completed. Being completed means the initial
  * matching of objects have been finished, not that no more notifications about
- * changes will be sent. In fact, even after done, notifications will still be sent
- * if there are changes in the objects matching the query search expression.
+ * changes will be sent. In fact, even after completed, notifications will still be sent
+ * if there are changes in the objects matching the view search expression.
  *
- * Returns: TRUE if the query is done, FALSE if still in progress.
+ * Returns: TRUE if the view is completed, FALSE if still in progress.
  */
 gboolean
-e_data_cal_view_is_done (EDataCalView *query)
+e_data_cal_view_is_completed (EDataCalView *view)
 {
-	EDataCalViewPrivate *priv;
+	g_return_val_if_fail (E_IS_DATA_CAL_VIEW (view), FALSE);
 
-	g_return_val_if_fail (IS_QUERY (query), FALSE);
+	return view->priv->complete;
+}
 
-	priv = query->priv;
+/**
+ * e_data_cal_view_get_fields_of_interest:
+ * @view: A view object.
+ *
+ * Returns: Hash table of field names which the listener is interested in.
+ * Backends can return fully populated objects, but the listener advertised
+ * that it will use only these. Returns %NULL for all available fields.
+ *
+ * Note: The data pointer in the hash table has no special meaning, it's
+ * only GINT_TO_POINTER(1) for easier checking. Also, field names are
+ * compared case insensitively.
+ **/
+/* const */ GHashTable *
+e_data_cal_view_get_fields_of_interest (EDataCalView *view)
+{
+	g_return_val_if_fail (E_IS_DATA_CAL_VIEW (view), NULL);
 
-	return priv->done;
+	return view->priv->fields_of_interest;
 }
 
 /**
  * e_data_cal_view_notify_objects_added:
- * @query: A query object.
+ * @view: A view object.
  * @objects: List of objects that have been added.
  *
- * Notifies all query listeners of the addition of a list of objects.
+ * Notifies all view listeners of the addition of a list of objects.
  */
 void
-e_data_cal_view_notify_objects_added (EDataCalView *view, const GList *objects)
+e_data_cal_view_notify_objects_added (EDataCalView *view, const GSList *objects)
 {
 	EDataCalViewPrivate *priv;
-	const GList *l;
+	const GSList *l;
 
 	g_return_if_fail (view && E_IS_DATA_CAL_VIEW (view));
 	priv = view->priv;
@@ -629,15 +719,15 @@ e_data_cal_view_notify_objects_added (EDataCalView *view, const GList *objects)
 
 /**
  * e_data_cal_view_notify_objects_added_1:
- * @query: A query object.
+ * @view: A view object.
  * @object: The object that has been added.
  *
- * Notifies all the query listeners of the addition of a single object.
+ * Notifies all the view listeners of the addition of a single object.
  */
 void
 e_data_cal_view_notify_objects_added_1 (EDataCalView *view, const gchar *object)
 {
-	GList l = {NULL,};
+	GSList l = {NULL,};
 
 	g_return_if_fail (view && E_IS_DATA_CAL_VIEW (view));
 	g_return_if_fail (object);
@@ -648,16 +738,16 @@ e_data_cal_view_notify_objects_added_1 (EDataCalView *view, const gchar *object)
 
 /**
  * e_data_cal_view_notify_objects_modified:
- * @query: A query object.
+ * @view: A view object.
  * @objects: List of modified objects.
  *
- * Notifies all query listeners of the modification of a list of objects.
+ * Notifies all view listeners of the modification of a list of objects.
  */
 void
-e_data_cal_view_notify_objects_modified (EDataCalView *view, const GList *objects)
+e_data_cal_view_notify_objects_modified (EDataCalView *view, const GSList *objects)
 {
 	EDataCalViewPrivate *priv;
-	const GList *l;
+	const GSList *l;
 
 	g_return_if_fail (view && E_IS_DATA_CAL_VIEW (view));
 	priv = view->priv;
@@ -677,15 +767,15 @@ e_data_cal_view_notify_objects_modified (EDataCalView *view, const GList *object
 
 /**
  * e_data_cal_view_notify_objects_modified_1:
- * @query: A query object.
+ * @view: A view object.
  * @object: The modified object.
  *
- * Notifies all query listeners of the modification of a single object.
+ * Notifies all view listeners of the modification of a single object.
  */
 void
 e_data_cal_view_notify_objects_modified_1 (EDataCalView *view, const gchar *object)
 {
-	GList l = {NULL,};
+	GSList l = {NULL,};
 
 	g_return_if_fail (view && E_IS_DATA_CAL_VIEW (view));
 	g_return_if_fail (object);
@@ -696,16 +786,16 @@ e_data_cal_view_notify_objects_modified_1 (EDataCalView *view, const gchar *obje
 
 /**
  * e_data_cal_view_notify_objects_removed:
- * @query: A query object.
+ * @view: A view object.
  * @ids: List of IDs for the objects that have been removed.
  *
- * Notifies all query listener of the removal of a list of objects.
+ * Notifies all view listener of the removal of a list of objects.
  */
 void
-e_data_cal_view_notify_objects_removed (EDataCalView *view, const GList *ids)
+e_data_cal_view_notify_objects_removed (EDataCalView *view, const GSList *ids)
 {
 	EDataCalViewPrivate *priv;
-	const GList *l;
+	const GSList *l;
 
 	g_return_if_fail (view && E_IS_DATA_CAL_VIEW (view));
 	priv = view->priv;
@@ -726,15 +816,15 @@ e_data_cal_view_notify_objects_removed (EDataCalView *view, const GList *ids)
 
 /**
  * e_data_cal_view_notify_objects_removed_1:
- * @query: A query object.
+ * @view: A view object.
  * @id: ID of the removed object.
  *
- * Notifies all query listener of the removal of a single object.
+ * Notifies all view listener of the removal of a single object.
  */
 void
 e_data_cal_view_notify_objects_removed_1 (EDataCalView *view, const ECalComponentId *id)
 {
-	GList l = {NULL,};
+	GSList l = {NULL,};
 
 	g_return_if_fail (view && E_IS_DATA_CAL_VIEW (view));
 	g_return_if_fail (id);
@@ -745,14 +835,14 @@ e_data_cal_view_notify_objects_removed_1 (EDataCalView *view, const ECalComponen
 
 /**
  * e_data_cal_view_notify_progress:
- * @query: A query object.
- * @message: Progress message to send to listeners.
+ * @view: A view object.
  * @percent: Percentage completed.
+ * @message: Progress message to send to listeners.
  *
- * Notifies all query listeners of progress messages.
+ * Notifies all view listeners of progress messages.
  */
 void
-e_data_cal_view_notify_progress (EDataCalView *view, const gchar *message, gint percent)
+e_data_cal_view_notify_progress (EDataCalView *view, gint percent, const gchar *message)
 {
 	EDataCalViewPrivate *priv;
 	gchar *gdbus_message = NULL;
@@ -763,21 +853,21 @@ e_data_cal_view_notify_progress (EDataCalView *view, const gchar *message, gint
 	if (!priv->started || priv->stopped)
 		return;
 
-	e_gdbus_cal_view_emit_progress (view->priv->gdbus_object, e_util_ensure_gdbus_string (message, &gdbus_message), percent);
+	e_gdbus_cal_view_emit_progress (view->priv->gdbus_object, percent, e_util_ensure_gdbus_string (message, &gdbus_message));
 
 	g_free (gdbus_message);
 }
 
 /**
- * e_data_cal_view_notify_done:
- * @query: A query object.
- * @error: Query completion error, if any.
+ * e_data_cal_view_notify_complete:
+ * @view: A view object.
+ * @error: View completion error, if any.
  *
- * Notifies all query listeners of the completion of the query, including a
+ * Notifies all view listeners of the completion of the view, including a
  * status code.
  */
 void
-e_data_cal_view_notify_done (EDataCalView *view, const GError *error)
+e_data_cal_view_notify_complete (EDataCalView *view, const GError *error)
 {
 	EDataCalViewPrivate *priv;
 
@@ -789,9 +879,9 @@ e_data_cal_view_notify_done (EDataCalView *view, const GError *error)
 
 	g_mutex_lock (priv->pending_mutex);
 
-	priv->done = TRUE;
+	priv->complete = TRUE;
 
-	notify_done (view, error);
+	notify_complete (view, error);
 
 	g_mutex_unlock (priv->pending_mutex);
 }
diff --git a/calendar/libedata-cal/e-data-cal-view.h b/calendar/libedata-cal/e-data-cal-view.h
index 2ec3f48..0be824b 100644
--- a/calendar/libedata-cal/e-data-cal-view.h
+++ b/calendar/libedata-cal/e-data-cal-view.h
@@ -1,4 +1,4 @@
-/* Evolution calendar - Live search query implementation
+/* Evolution calendar - Live search view implementation
  *
  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
  *
@@ -36,9 +36,6 @@ G_BEGIN_DECLS
 #define E_DATA_CAL_VIEW(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_DATA_CAL_VIEW_TYPE, EDataCalView))
 #define E_DATA_CAL_VIEW_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), E_DATA_CAL_VIEW_TYPE, EDataCalViewClass))
 #define E_IS_DATA_CAL_VIEW(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_DATA_CAL_VIEW_TYPE))
-/* Deprecated macros */
-#define QUERY(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), E_DATA_CAL_VIEW_TYPE, EDataCalView))
-#define IS_QUERY(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), E_DATA_CAL_VIEW_TYPE))
 
 typedef struct _EDataCalViewPrivate EDataCalViewPrivate;
 
@@ -51,37 +48,25 @@ struct _EDataCalViewClass {
 	GObjectClass parent_class;
 };
 
-GType                 e_data_cal_view_get_type (void);
-EDataCalView         *e_data_cal_view_new (ECalBackend *backend, ECalBackendSExp *sexp);
+GType			e_data_cal_view_get_type			(void);
+EDataCalView *		e_data_cal_view_new				(ECalBackend *backend, ECalBackendSExp *sexp);
+guint			e_data_cal_view_register_gdbus_object		(EDataCalView *view, GDBusConnection *connection, const gchar *object_path, GError **error);
+const gchar *		e_data_cal_view_get_text			(EDataCalView *view);
+ECalBackendSExp *	e_data_cal_view_get_object_sexp			(EDataCalView *view);
+gboolean		e_data_cal_view_object_matches			(EDataCalView *view, const gchar *object);
+gboolean		e_data_cal_view_is_started			(EDataCalView *view);
+gboolean		e_data_cal_view_is_completed			(EDataCalView *view);
+gboolean		e_data_cal_view_is_stopped			(EDataCalView *view);
+/* const */ GHashTable *e_data_cal_view_get_fields_of_interest		(EDataCalView *view);
 
-guint e_data_cal_view_register_gdbus_object (EDataCalView *query, GDBusConnection *connection, const gchar *object_path, GError **error);
-
-const gchar           *e_data_cal_view_get_text (EDataCalView *query);
-ECalBackendSExp      *e_data_cal_view_get_object_sexp (EDataCalView *query);
-gboolean              e_data_cal_view_object_matches (EDataCalView *query, const gchar *object);
-
-GList                *e_data_cal_view_get_matched_objects (EDataCalView *query);
-gboolean              e_data_cal_view_is_started (EDataCalView *query);
-gboolean              e_data_cal_view_is_done (EDataCalView *query);
-gboolean              e_data_cal_view_is_stopped (EDataCalView *query);
-
-void                  e_data_cal_view_notify_objects_added (EDataCalView       *query,
-							    const GList *objects);
-void                  e_data_cal_view_notify_objects_added_1 (EDataCalView       *query,
-							      const gchar *object);
-void                  e_data_cal_view_notify_objects_modified (EDataCalView       *query,
-							       const GList *objects);
-void                  e_data_cal_view_notify_objects_modified_1 (EDataCalView       *query,
-								 const gchar *object);
-void                  e_data_cal_view_notify_objects_removed (EDataCalView       *query,
-							      const GList *ids);
-void                  e_data_cal_view_notify_objects_removed_1 (EDataCalView       *query,
-								const ECalComponentId *id);
-void                  e_data_cal_view_notify_progress (EDataCalView      *query,
-						       const gchar *message,
-						       gint         percent);
-void                  e_data_cal_view_notify_done (EDataCalView                               *query,
-						   const GError *error);
+void			e_data_cal_view_notify_objects_added		(EDataCalView *view, const GSList *objects);
+void			e_data_cal_view_notify_objects_added_1		(EDataCalView *view, const gchar *object);
+void			e_data_cal_view_notify_objects_modified		(EDataCalView *view, const GSList *objects);
+void			e_data_cal_view_notify_objects_modified_1	(EDataCalView *view, const gchar *object);
+void			e_data_cal_view_notify_objects_removed		(EDataCalView *view, const GSList *ids);
+void			e_data_cal_view_notify_objects_removed_1	(EDataCalView *view, const ECalComponentId *id);
+void			e_data_cal_view_notify_progress			(EDataCalView *view, gint percent, const gchar *message);
+void			e_data_cal_view_notify_complete			(EDataCalView *view, const GError *error);
 
 G_END_DECLS
 
diff --git a/calendar/libedata-cal/e-data-cal.c b/calendar/libedata-cal/e-data-cal.c
index 2e7d580..f7e00da 100644
--- a/calendar/libedata-cal/e-data-cal.c
+++ b/calendar/libedata-cal/e-data-cal.c
@@ -31,11 +31,13 @@
 #include <unistd.h>
 
 #include <glib-object.h>
-#include <libedataserver/e-debug-log.h>
+#include <libedataserver/e-credentials.h>
 #include <libedataserver/e-data-server-util.h>
+#include <libedataserver/e-operation-pool.h>
+
 #include "e-data-cal.h"
 #include "e-data-cal-enumtypes.h"
-#include "e-gdbus-egdbuscal.h"
+#include "e-gdbus-cal.h"
 
 G_DEFINE_TYPE (EDataCal, e_data_cal, G_TYPE_OBJECT);
 
@@ -44,11 +46,314 @@ G_DEFINE_TYPE (EDataCal, e_data_cal, G_TYPE_OBJECT);
 
 struct _EDataCalPrivate {
 	EGdbusCal *gdbus_object;
+
 	ECalBackend *backend;
 	ESource *source;
-	GHashTable *live_queries;
+
+	GStaticRecMutex pending_ops_lock;
+	GHashTable *pending_ops; /* opid to GCancellable for still running operations */
 };
 
+static EOperationPool *ops_pool = NULL;
+
+typedef enum {
+	OP_OPEN,
+	OP_AUTHENTICATE,
+	OP_REMOVE,
+	OP_REFRESH,
+	OP_GET_BACKEND_PROPERTY,
+	OP_SET_BACKEND_PROPERTY,
+	OP_GET_OBJECT,
+	OP_GET_OBJECT_LIST,
+	OP_GET_FREE_BUSY,
+	OP_CREATE_OBJECT,
+	OP_MODIFY_OBJECT,
+	OP_REMOVE_OBJECT,
+	OP_RECEIVE_OBJECTS,
+	OP_SEND_OBJECTS,
+	OP_GET_ATTACHMENT_URIS,
+	OP_DISCARD_ALARM,
+	OP_GET_VIEW,
+	OP_GET_TIMEZONE,
+	OP_ADD_TIMEZONE,
+	OP_CANCEL_OPERATION,
+	OP_CANCEL_ALL,
+	OP_CLOSE
+} OperationID;
+
+typedef struct {
+	OperationID op;
+	guint32 id; /* operation id */
+	EDataCal *cal; /* calendar */
+	GCancellable *cancellable;
+
+	union {
+		/* OP_OPEN */
+		gboolean only_if_exists;
+		/* OP_AUTHENTICATE */
+		ECredentials *credentials;
+		/* OP_GET_OBJECT */
+		/* OP_GET_ATTACHMENT_URIS */
+		struct _ur {
+			gchar *uid;
+			gchar *rid;
+		} ur;
+		/* OP_DISCARD_ALARM */
+		struct _ura {
+			gchar *uid;
+			gchar *rid;
+			gchar *auid;
+		} ura;
+		/* OP_GET_OBJECT_LIST */
+		/* OP_GET_VIEW */
+		gchar *sexp;
+		/* OP_GET_FREE_BUSY */
+		struct _free_busy {
+			time_t start, end;
+			GSList *users;
+		} fb;
+		/* OP_CREATE_OBJECT */
+		/* OP_RECEIVE_OBJECTS */
+		/* OP_SEND_OBJECTS */
+		struct _co {
+			gchar *calobj;
+		} co;
+		/* OP_MODIFY_OBJECT */
+		struct _mo {
+			gchar *calobj;
+			EDataCalObjModType mod;
+		} mo;
+		/* OP_REMOVE_OBJECT */
+		struct _ro {
+			gchar *uid;
+			gchar *rid;
+			EDataCalObjModType mod;
+		} ro;
+		/* OP_GET_TIMEZONE */
+		gchar *tzid;
+		/* OP_ADD_TIMEZONE */
+		gchar *tzobject;
+		/* OP_CANCEL_OPERATION */
+		guint opid;
+		/* OP_GET_BACKEND_PROPERTY */
+		gchar *prop_name;
+		/* OP_SET_BACKEND_PROPERTY */
+		struct _sbp {
+			gchar *prop_name;
+			gchar *prop_value;
+		} sbp;
+
+		/* OP_REMOVE */
+		/* OP_REFRESH */
+		/* OP_CANCEL_ALL */
+		/* OP_CLOSE */
+	} d;
+} OperationData;
+
+/* Function to get a new EDataCalView path, used by getView below */
+static gchar *
+construct_calview_path (void)
+{
+	static guint counter = 1;
+	return g_strdup_printf ("/org/gnome/evolution/dataserver/CalendarView/%d/%d", getpid(), counter++);
+}
+
+static void
+cancel_ops_cb (gpointer opid, gpointer cancellable, gpointer user_data)
+{
+	g_return_if_fail (cancellable != NULL);
+
+	g_cancellable_cancel (cancellable);
+}
+
+static void
+operation_thread (gpointer data, gpointer user_data)
+{
+	OperationData *op = data;
+	ECalBackend *backend;
+
+	backend = e_data_cal_get_backend (op->cal);
+
+	switch (op->op) {
+	case OP_OPEN:
+		e_cal_backend_open (backend, op->cal, op->id, op->cancellable, op->d.only_if_exists);
+		break;
+	case OP_REMOVE:
+		e_cal_backend_remove (backend, op->cal, op->id, op->cancellable);
+		break;
+	case OP_REFRESH:
+		e_cal_backend_refresh (backend, op->cal, op->id, op->cancellable);
+		break;
+	case OP_GET_BACKEND_PROPERTY:
+		e_cal_backend_get_backend_property (backend, op->cal, op->id, op->cancellable, op->d.prop_name);
+		g_free (op->d.prop_name);
+		break;
+	case OP_SET_BACKEND_PROPERTY:
+		e_cal_backend_set_backend_property (backend, op->cal, op->id, op->cancellable, op->d.sbp.prop_name, op->d.sbp.prop_value);
+		g_free (op->d.sbp.prop_name);
+		g_free (op->d.sbp.prop_value);
+		break;
+	case OP_GET_OBJECT:
+		e_cal_backend_get_object (backend, op->cal, op->id, op->cancellable, op->d.ur.uid, op->d.ur.rid && *op->d.ur.rid ? op->d.ur.rid : NULL);
+		g_free (op->d.ur.uid);
+		g_free (op->d.ur.rid);
+		break;
+	case OP_GET_OBJECT_LIST:
+		e_cal_backend_get_object_list (backend, op->cal, op->id, op->cancellable, op->d.sexp);
+		g_free (op->d.sexp);
+		break;
+	case OP_GET_FREE_BUSY:
+		e_cal_backend_get_free_busy (backend, op->cal, op->id, op->cancellable, op->d.fb.users, op->d.fb.start, op->d.fb.end);
+		g_slist_foreach (op->d.fb.users, (GFunc) g_free, NULL);
+		g_slist_free (op->d.fb.users);
+		break;
+	case OP_CREATE_OBJECT:
+		e_cal_backend_create_object (backend, op->cal, op->id, op->cancellable, op->d.co.calobj);
+		g_free (op->d.co.calobj);
+		break;
+	case OP_MODIFY_OBJECT:
+		e_cal_backend_modify_object (backend, op->cal, op->id, op->cancellable, op->d.mo.calobj, op->d.mo.mod);
+		g_free (op->d.mo.calobj);
+		break;
+	case OP_REMOVE_OBJECT:
+		e_cal_backend_remove_object (backend, op->cal, op->id, op->cancellable, op->d.ro.uid, op->d.ro.rid && *op->d.ro.rid ? op->d.ro.rid : NULL, op->d.ro.mod);
+		g_free (op->d.ro.uid);
+		g_free (op->d.ro.rid);
+		break;
+	case OP_RECEIVE_OBJECTS:
+		e_cal_backend_receive_objects (backend, op->cal, op->id, op->cancellable, op->d.co.calobj);
+		g_free (op->d.co.calobj);
+		break;
+	case OP_SEND_OBJECTS:
+		e_cal_backend_send_objects (backend, op->cal, op->id, op->cancellable, op->d.co.calobj);
+		g_free (op->d.co.calobj);
+		break;
+	case OP_GET_ATTACHMENT_URIS:
+		e_cal_backend_get_attachment_uris (backend, op->cal, op->id, op->cancellable, op->d.ur.uid, op->d.ur.rid && *op->d.ur.rid ? op->d.ur.rid : NULL);
+		g_free (op->d.ur.uid);
+		g_free (op->d.ur.rid);
+		break;
+	case OP_DISCARD_ALARM:
+		e_cal_backend_discard_alarm (backend, op->cal, op->id, op->cancellable, op->d.ura.uid, op->d.ura.rid && *op->d.ura.rid ? op->d.ura.rid : NULL, op->d.ura.auid);
+		g_free (op->d.ura.uid);
+		g_free (op->d.ura.rid);
+		g_free (op->d.ura.auid);
+		break;
+	case OP_GET_VIEW:
+		if (op->d.sexp) {
+			EDataCalView *view;
+			ECalBackendSExp *obj_sexp;
+			gchar *path;
+			GError *error = NULL;
+
+			/* we handle this entirely here, since it doesn't require any
+			   backend involvement now that we have e_cal_view_start to
+			   actually kick off the search. */
+
+			obj_sexp = e_cal_backend_sexp_new (op->d.sexp);
+			if (!obj_sexp) {
+				g_free (op->d.sexp);
+				e_data_cal_respond_get_view (op->cal, op->id, EDC_ERROR (InvalidQuery), NULL);
+				break;
+			}
+
+			view = e_data_cal_view_new (backend, obj_sexp);
+			if (!view) {
+				g_object_unref (obj_sexp);
+				g_free (op->d.sexp);
+				e_data_cal_respond_get_view (op->cal, op->id, EDC_ERROR (OtherError), NULL);
+				break;
+			}
+
+			path = construct_calview_path ();
+			e_data_cal_view_register_gdbus_object (view, e_gdbus_cal_stub_get_connection (op->cal->priv->gdbus_object), path, &error);
+
+			if (error) {
+				g_object_unref (view);
+				g_free (op->d.sexp);
+				e_data_cal_respond_get_view (op->cal, op->id, EDC_ERROR_EX (OtherError, error->message), NULL);
+				g_error_free (error);
+				g_free (path);
+
+				break;
+			}
+
+			e_cal_backend_add_view (backend, view);
+
+			e_data_cal_respond_get_view (op->cal, op->id, EDC_ERROR (Success), path);
+
+			g_free (path);
+		}
+		g_free (op->d.sexp);
+		break;
+	case OP_GET_TIMEZONE:
+		e_cal_backend_get_timezone (backend, op->cal, op->id, op->cancellable, op->d.tzid);
+		g_free (op->d.tzid);
+		break;
+	case OP_ADD_TIMEZONE:
+		e_cal_backend_add_timezone (backend, op->cal, op->id, op->cancellable, op->d.tzobject);
+		g_free (op->d.tzobject);
+		break;
+	case OP_AUTHENTICATE:
+		e_cal_backend_authenticate_user (backend, op->cancellable, op->d.credentials);
+		e_credentials_free (op->d.credentials);
+		break;
+	case OP_CANCEL_OPERATION:
+		g_static_rec_mutex_lock (&op->cal->priv->pending_ops_lock);
+
+		if (g_hash_table_lookup (op->cal->priv->pending_ops, GUINT_TO_POINTER (op->d.opid))) {
+			GCancellable *cancellable = g_hash_table_lookup (op->cal->priv->pending_ops, GUINT_TO_POINTER (op->d.opid));
+
+			g_cancellable_cancel (cancellable);
+		}
+
+		g_static_rec_mutex_unlock (&op->cal->priv->pending_ops_lock);
+		break;
+	case OP_CLOSE:
+		/* close just cancels all pending ops and frees data cal */
+		e_cal_backend_remove_client (backend, op->cal);
+	case OP_CANCEL_ALL:
+		g_static_rec_mutex_lock (&op->cal->priv->pending_ops_lock);
+		g_hash_table_foreach (op->cal->priv->pending_ops, cancel_ops_cb, NULL);
+		g_static_rec_mutex_unlock (&op->cal->priv->pending_ops_lock);
+		break;
+	}
+
+	g_object_unref (op->cal);
+	g_object_unref (op->cancellable);
+	g_slice_free (OperationData, op);
+}
+
+static OperationData *
+op_new (OperationID op, EDataCal *cal)
+{
+	OperationData *data;
+
+	data = g_slice_new0 (OperationData);
+	data->op = op;
+	data->cal = g_object_ref (cal);
+	data->id = e_operation_pool_reserve_opid (ops_pool);
+	data->cancellable = g_cancellable_new ();
+
+	g_static_rec_mutex_lock (&cal->priv->pending_ops_lock);
+	g_hash_table_insert (cal->priv->pending_ops, GUINT_TO_POINTER (data->id), g_object_ref (data->cancellable));
+	g_static_rec_mutex_unlock (&cal->priv->pending_ops_lock);
+
+	return data;
+}
+
+static void
+op_complete (EDataCal *cal, guint32 opid)
+{
+	g_return_if_fail (cal != NULL);
+
+	e_operation_pool_release_opid (ops_pool, opid);
+
+	g_static_rec_mutex_lock (&cal->priv->pending_ops_lock);
+	g_hash_table_remove (cal->priv->pending_ops, GUINT_TO_POINTER (opid));
+	g_static_rec_mutex_unlock (&cal->priv->pending_ops_lock);
+}
+
 /* Create the EDataCal error quark */
 GQuark
 e_data_cal_error_quark (void)
@@ -57,6 +362,7 @@ e_data_cal_error_quark (void)
 
 	static const GDBusErrorEntry entries[] = {
 		{ Success,				ERR_PREFIX "Success" },
+		{ Busy,					ERR_PREFIX "Busy" },
 		{ RepositoryOffline,			ERR_PREFIX "RepositoryOffline" },
 		{ PermissionDenied,			ERR_PREFIX "PermissionDenied" },
 		{ InvalidRange,				ERR_PREFIX "InvalidRange" },
@@ -106,6 +412,7 @@ e_data_cal_status_to_string (EDataCalCallStatus status)
 		const gchar *msg;
 	} statuses[] = {
 		{ Success,				N_("Success") },
+		{ Busy,					N_("Backend is busy") },
 		{ RepositoryOffline,			N_("Repository offline") },
 		{ PermissionDenied,			N_("Permission denied") },
 		{ InvalidRange,				N_("Invalid range") },
@@ -195,6 +502,19 @@ data_cal_return_error (GDBusMethodInvocation *invocation, const GError *perror,
 	g_error_free (error);
 }
 
+
+EDataCal *
+e_data_cal_new (ECalBackend *backend, ESource *source)
+{
+	EDataCal *cal;
+
+	cal = g_object_new (E_TYPE_DATA_CAL, NULL);
+	cal->priv->backend = g_object_ref (backend);
+	cal->priv->source = g_object_ref (source);
+
+	return cal;
+}
+
 /**
  * e_data_cal_get_source:
  * @cal: an #EDataCal
@@ -208,360 +528,364 @@ data_cal_return_error (GDBusMethodInvocation *invocation, const GError *perror,
 ESource*
 e_data_cal_get_source (EDataCal *cal)
 {
-  return cal->priv->source;
+	return cal->priv->source;
 }
 
 ECalBackend*
 e_data_cal_get_backend (EDataCal *cal)
 {
-  return cal->priv->backend;
+	return cal->priv->backend;
 }
 
-/* EDataCal::getUri method */
-static gboolean
-impl_Cal_getUri (EGdbusCal *object, GDBusMethodInvocation *invocation, EDataCal *cal)
+/**
+ * e_data_cal_register_gdbus_object:
+ *
+ * Registers GDBus object of this EDataCal.
+ *
+ * Since: 2.32
+ **/
+guint
+e_data_cal_register_gdbus_object (EDataCal *cal, GDBusConnection *connection, const gchar *object_path, GError **error)
 {
-	e_gdbus_cal_complete_get_uri (object, invocation, e_cal_backend_get_uri (cal->priv->backend));
+	g_return_val_if_fail (cal != NULL, 0);
+	g_return_val_if_fail (E_IS_DATA_CAL (cal), 0);
+	g_return_val_if_fail (connection != NULL, 0);
+	g_return_val_if_fail (object_path != NULL, 0);
 
-	return TRUE;
+	return e_gdbus_cal_register_object (cal->priv->gdbus_object, connection, object_path, error);
 }
 
-/* EDataCal::getCacheDir method */
 static gboolean
-impl_Cal_getCacheDir (EGdbusCal *object, GDBusMethodInvocation *invocation, EDataCal *cal)
+impl_Cal_open (EGdbusCal *object, GDBusMethodInvocation *invocation, gboolean in_only_if_exists, EDataCal *cal)
 {
-	e_gdbus_cal_complete_get_cache_dir (object, invocation, e_cal_backend_get_cache_dir (cal->priv->backend));
+	OperationData *op;
+
+	op = op_new (OP_OPEN, cal);
+	op->d.only_if_exists = in_only_if_exists;
+
+	e_gdbus_cal_complete_open (cal->priv->gdbus_object, invocation, op->id);
+	e_operation_pool_push (ops_pool, op);
 
 	return TRUE;
 }
 
-/* EDataCal::open method */
 static gboolean
-impl_Cal_open (EGdbusCal *object, GDBusMethodInvocation *invocation, gboolean only_if_exists, const gchar *username, const gchar *password, EDataCal *cal)
+impl_Cal_remove (EGdbusCal *object, GDBusMethodInvocation *invocation, EDataCal *cal)
 {
-	e_cal_backend_open (cal->priv->backend, cal, invocation, only_if_exists, username, password);
+	OperationData *op;
+
+	op = op_new (OP_REMOVE, cal);
+
+	e_gdbus_cal_complete_remove (cal->priv->gdbus_object, invocation, op->id);
+	e_operation_pool_push (ops_pool, op);
 
 	return TRUE;
 }
 
-/* EDataCal::refresh method */
 static gboolean
 impl_Cal_refresh (EGdbusCal *object, GDBusMethodInvocation *invocation, EDataCal *cal)
 {
-	e_cal_backend_refresh (cal->priv->backend, cal, invocation);
+	OperationData *op;
+
+	op = op_new (OP_REFRESH, cal);
+
+	e_gdbus_cal_complete_refresh (cal->priv->gdbus_object, invocation, op->id);
+	e_operation_pool_push (ops_pool, op);
 
 	return TRUE;
 }
 
-/* EDataCal::close method */
 static gboolean
-impl_Cal_close (EGdbusCal *object, GDBusMethodInvocation *invocation, EDataCal *cal)
+impl_Cal_getBackendProperty (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar *in_prop_name, EDataCal *cal)
 {
-	e_cal_backend_remove_client (cal->priv->backend, cal);
-	e_gdbus_cal_complete_close (object, invocation);
+	OperationData *op;
 
-	g_object_unref (cal);
+	op = op_new (OP_GET_BACKEND_PROPERTY, cal);
+	op->d.prop_name = g_strdup (in_prop_name);
+
+	e_gdbus_cal_complete_get_backend_property (cal->priv->gdbus_object, invocation, op->id);
+	e_operation_pool_push (ops_pool, op);
 
 	return TRUE;
 }
 
-/* EDataCal::remove method */
 static gboolean
-impl_Cal_remove (EGdbusCal *object, GDBusMethodInvocation *invocation, EDataCal *cal)
+impl_Cal_setBackendProperty (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar * const *in_prop_name_value, EDataCal *cal)
 {
-	e_cal_backend_remove (cal->priv->backend, cal, invocation);
+	OperationData *op;
 
-	return TRUE;
-}
+	op = op_new (OP_SET_BACKEND_PROPERTY, cal);
+	g_return_val_if_fail (e_gdbus_cal_decode_set_backend_property (in_prop_name_value, &op->d.sbp.prop_name, &op->d.sbp.prop_value), FALSE);
 
-/* EDataCal::isReadOnly method */
-static gboolean
-impl_Cal_isReadOnly (EGdbusCal *object, GDBusMethodInvocation *invocation, EDataCal *cal)
-{
-	e_cal_backend_is_read_only (cal->priv->backend, cal);
-	e_gdbus_cal_complete_is_read_only (object, invocation);
+	e_gdbus_cal_complete_set_backend_property (cal->priv->gdbus_object, invocation, op->id);
+	e_operation_pool_push (ops_pool, op);
 
 	return TRUE;
 }
 
-/* EDataCal::getCalAddress method */
 static gboolean
-impl_Cal_getCalAddress (EGdbusCal *object, GDBusMethodInvocation *invocation, EDataCal *cal)
+impl_Cal_getObject (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar * const *in_uid_rid, EDataCal *cal)
 {
-	e_cal_backend_get_cal_address (cal->priv->backend, cal, invocation);
+	OperationData *op;
 
-	return TRUE;
-}
+	op = op_new (OP_GET_OBJECT, cal);
+	g_return_val_if_fail (e_gdbus_cal_decode_get_object (in_uid_rid, &op->d.ur.uid, &op->d.ur.rid), FALSE);
 
-/* EDataCal::getAlarmEmailAddress method */
-static gboolean
-impl_Cal_getAlarmEmailAddress (EGdbusCal *object, GDBusMethodInvocation *invocation, EDataCal *cal)
-{
-	e_cal_backend_get_alarm_email_address (cal->priv->backend, cal, invocation);
+	e_gdbus_cal_complete_get_object (cal->priv->gdbus_object, invocation, op->id);
+	e_operation_pool_push (ops_pool, op);
 
 	return TRUE;
 }
 
-/* EDataCal::getLdapAttribute method */
 static gboolean
-impl_Cal_getLdapAttribute (EGdbusCal *object, GDBusMethodInvocation *invocation, EDataCal *cal)
+impl_Cal_getObjectList (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar *in_sexp, EDataCal *cal)
 {
-	e_cal_backend_get_ldap_attribute (cal->priv->backend, cal, invocation);
+	OperationData *op;
 
-	return TRUE;
-}
+	op = op_new (OP_GET_OBJECT_LIST, cal);
+	op->d.sexp = g_strdup (in_sexp);
 
-/* EDataCal::getSchedulingInformation method */
-static gboolean
-impl_Cal_getSchedulingInformation (EGdbusCal *object, GDBusMethodInvocation *invocation, EDataCal *cal)
-{
-	e_cal_backend_get_static_capabilities (cal->priv->backend, cal, invocation);
+	e_gdbus_cal_complete_get_object_list (cal->priv->gdbus_object, invocation, op->id);
+	e_operation_pool_push (ops_pool, op);
 
 	return TRUE;
 }
 
-/* EDataCal::setMode method */
 static gboolean
-impl_Cal_setMode (EGdbusCal *object, GDBusMethodInvocation *invocation, EDataCalMode mode, EDataCal *cal)
+impl_Cal_getFreeBusy (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar * const *in_start_end_userlist, EDataCal *cal)
 {
-	e_cal_backend_set_mode (cal->priv->backend, mode);
-	e_gdbus_cal_complete_set_mode (object, invocation);
+	OperationData *op;
+	guint start, end;
 
-	return TRUE;
-}
+	op = op_new (OP_GET_FREE_BUSY, cal);
+	g_return_val_if_fail (e_gdbus_cal_decode_get_free_busy (in_start_end_userlist, &start, &end, &op->d.fb.users), FALSE);
 
-/* EDataCal::getDefaultObject method */
-static gboolean
-impl_Cal_getDefaultObject (EGdbusCal *object, GDBusMethodInvocation *invocation, EDataCal *cal)
-{
-	e_cal_backend_get_default_object (cal->priv->backend, cal, invocation);
+	op->d.fb.start = (time_t) start;
+	op->d.fb.end = (time_t) end;
+
+	e_gdbus_cal_complete_get_free_busy (cal->priv->gdbus_object, invocation, op->id);
+	e_operation_pool_push (ops_pool, op);
 
 	return TRUE;
 }
 
-/* EDataCal::getObject method */
 static gboolean
-impl_Cal_getObject (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar *uid, const gchar *rid, EDataCal *cal)
+impl_Cal_createObject (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar *in_calobj, EDataCal *cal)
 {
-	e_cal_backend_get_object (cal->priv->backend, cal, invocation, uid, rid);
+	OperationData *op;
 
-	return TRUE;
-}
+	op = op_new (OP_CREATE_OBJECT, cal);
+	op->d.co.calobj = g_strdup (in_calobj);
 
-/* EDataCal::getObjectList method */
-static gboolean
-impl_Cal_getObjectList (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar *sexp, EDataCal *cal)
-{
-	e_cal_backend_get_object_list (cal->priv->backend, cal, invocation, sexp);
+	e_gdbus_cal_complete_create_object (cal->priv->gdbus_object, invocation, op->id);
+	e_operation_pool_push (ops_pool, op);
 
 	return TRUE;
 }
 
-/* EDataCal::getChanges method */
 static gboolean
-impl_Cal_getChanges (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar *change_id, EDataCal *cal)
+impl_Cal_modifyObject (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar * const *in_calobj_mod, EDataCal *cal)
 {
-	e_cal_backend_get_changes (cal->priv->backend, cal, invocation, change_id);
+	OperationData *op;
+	guint mod;
+
+	op = op_new (OP_MODIFY_OBJECT, cal);
+	g_return_val_if_fail (e_gdbus_cal_decode_modify_object (in_calobj_mod, &op->d.mo.calobj, &mod), FALSE);
+	op->d.mo.mod = mod;
+
+	e_gdbus_cal_complete_modify_object (cal->priv->gdbus_object, invocation, op->id);
+	e_operation_pool_push (ops_pool, op);
 
 	return TRUE;
 }
 
-/* EDataCal::getFreeBusy method */
 static gboolean
-impl_Cal_getFreeBusy (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar **user_list, guint start, guint end, EDataCal *cal)
+impl_Cal_removeObject (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar * const *in_uid_rid_mod, EDataCal *cal)
 {
-	GList *users = NULL;
+	OperationData *op;
+	guint mod = 0;
 
-	if (user_list) {
-		gint i;
+	op = op_new (OP_REMOVE_OBJECT, cal);
+	g_return_val_if_fail (e_gdbus_cal_decode_remove_object (in_uid_rid_mod, &op->d.ro.uid, &op->d.ro.rid, &mod), FALSE);
+	op->d.ro.mod = mod;
 
-		for (i = 0; user_list[i]; i++)
-			users = g_list_append (users, (gpointer) user_list[i]);
-	}
-
-	/* call the backend's get_free_busy method */
-	e_cal_backend_get_free_busy (cal->priv->backend, cal, invocation, users, (time_t) start, (time_t) end);
+	e_gdbus_cal_complete_remove_object (cal->priv->gdbus_object, invocation, op->id);
+	e_operation_pool_push (ops_pool, op);
 
 	return TRUE;
 }
 
-/* EDataCal::discardAlarm method */
 static gboolean
-impl_Cal_discardAlarm (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar *uid, const gchar *auid, EDataCal *cal)
+impl_Cal_receiveObjects (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar *in_calobj, EDataCal *cal)
 {
-	e_cal_backend_discard_alarm (cal->priv->backend, cal, invocation, uid, auid);
+	OperationData *op;
 
-	return TRUE;
-}
+	op = op_new (OP_RECEIVE_OBJECTS, cal);
+	op->d.co.calobj = g_strdup (in_calobj);
 
-/* EDataCal::createObject method */
-static gboolean
-impl_Cal_createObject (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar *calobj, EDataCal *cal)
-{
-	e_cal_backend_create_object (cal->priv->backend, cal, invocation, calobj);
+	e_gdbus_cal_complete_receive_objects (cal->priv->gdbus_object, invocation, op->id);
+	e_operation_pool_push (ops_pool, op);
 
 	return TRUE;
 }
 
-/* EDataCal::modifyObject method */
 static gboolean
-impl_Cal_modifyObject (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar *calobj, EDataCalObjModType mod, EDataCal *cal)
+impl_Cal_sendObjects (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar *in_calobj, EDataCal *cal)
 {
-	e_cal_backend_modify_object (cal->priv->backend, cal, invocation, calobj, mod);
+	OperationData *op;
+
+	op = op_new (OP_SEND_OBJECTS, cal);
+	op->d.co.calobj = g_strdup (in_calobj);
+
+	e_gdbus_cal_complete_send_objects (cal->priv->gdbus_object, invocation, op->id);
+	e_operation_pool_push (ops_pool, op);
 
 	return TRUE;
 }
 
-/* EDataCal::removeObject method */
 static gboolean
-impl_Cal_removeObject (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar *uid, const gchar *rid, EDataCalObjModType mod, EDataCal *cal)
+impl_Cal_getAttachmentUris (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar * const *in_uid_rid, EDataCal *cal)
 {
-	if (rid[0] == '\0')
-		rid = NULL;
+	OperationData *op;
+
+	op = op_new (OP_GET_ATTACHMENT_URIS, cal);
+	g_return_val_if_fail (e_gdbus_cal_decode_get_attachment_uris (in_uid_rid, &op->d.ur.uid, &op->d.ur.rid), FALSE);
 
-	e_cal_backend_remove_object (cal->priv->backend, cal, invocation, uid, rid, mod);
+	e_gdbus_cal_complete_get_attachment_uris (cal->priv->gdbus_object, invocation, op->id);
+	e_operation_pool_push (ops_pool, op);
 
 	return TRUE;
 }
 
-/* EDataCal::receiveObjects method */
 static gboolean
-impl_Cal_receiveObjects (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar *calobj, EDataCal *cal)
+impl_Cal_discardAlarm (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar * const *in_uid_rid_auid, EDataCal *cal)
 {
-	e_cal_backend_receive_objects (cal->priv->backend, cal, invocation, calobj);
+	OperationData *op;
+
+	op = op_new (OP_DISCARD_ALARM, cal);
+	g_return_val_if_fail (e_gdbus_cal_decode_discard_alarm (in_uid_rid_auid, &op->d.ura.uid, &op->d.ura.rid, &op->d.ura.auid), FALSE);
+
+	e_gdbus_cal_complete_discard_alarm (cal->priv->gdbus_object, invocation, op->id);
+	e_operation_pool_push (ops_pool, op);
 
 	return TRUE;
 }
 
-/* EDataCal::sendObjects method */
 static gboolean
-impl_Cal_sendObjects (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar *calobj, EDataCal *cal)
+impl_Cal_getView (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar *in_sexp, EDataCal *cal)
 {
-	e_cal_backend_send_objects (cal->priv->backend, cal, invocation, calobj);
+	OperationData *op;
+
+	op = op_new (OP_GET_VIEW, cal);
+	op->d.sexp = g_strdup (in_sexp);
+
+	e_gdbus_cal_complete_get_view (cal->priv->gdbus_object, invocation, op->id);
+	e_operation_pool_push (ops_pool, op);
 
 	return TRUE;
 }
 
-/* EDataCal::getAttachmentList method */
 static gboolean
-impl_Cal_getAttachmentList (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar *uid, const gchar *rid, EDataCal *cal)
+impl_Cal_getTimezone (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar *in_tzid, EDataCal *cal)
 {
-	e_cal_backend_get_attachment_list (cal->priv->backend, cal, invocation, uid, rid);
+	OperationData *op;
 
-	return TRUE;
-}
+	op = op_new (OP_GET_TIMEZONE, cal);
+	op->d.tzid = g_strdup (in_tzid);
 
-/* Function to get a new EDataCalView path, used by getQuery below */
-static gchar *
-construct_calview_path (void)
-{
-	static guint counter = 1;
-	return g_strdup_printf ("/org/gnome/evolution/dataserver/CalendarView/%d/%d", getpid(), counter++);
+	e_gdbus_cal_complete_get_timezone (cal->priv->gdbus_object, invocation, op->id);
+	e_operation_pool_push (ops_pool, op);
+
+	return TRUE;
 }
 
-/* EDataCal::getQuery method */
 static gboolean
-impl_Cal_getQuery (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar *sexp, EDataCal *cal)
+impl_Cal_addTimezone (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar *in_tzobject, EDataCal *cal)
 {
-	EDataCalView *query;
-	ECalBackendSExp *obj_sexp;
-	gchar *path;
-	GError *error = NULL;
-
-	/* we handle this entirely here, since it doesn't require any
-	   backend involvement now that we have e_cal_view_start to
-	   actually kick off the search. */
+	OperationData *op;
 
-	obj_sexp = e_cal_backend_sexp_new (sexp);
-	if (!obj_sexp) {
-		e_data_cal_notify_query (cal, invocation, EDC_ERROR (InvalidQuery), NULL);
-		return TRUE;
-	}
+	op = op_new (OP_ADD_TIMEZONE, cal);
+	op->d.tzobject = g_strdup (in_tzobject);
 
-	query = e_data_cal_view_new (cal->priv->backend, obj_sexp);
-	e_debug_log (FALSE, E_DEBUG_LOG_DOMAIN_CAL_QUERIES, "%p;%p;NEW;%s;%s", cal, query, sexp, G_OBJECT_TYPE_NAME (cal->priv->backend));
-	if (!query) {
-		g_object_unref (obj_sexp);
-		e_data_cal_notify_query (cal, invocation, EDC_ERROR (OtherError), NULL);
-		return TRUE;
-	}
+	e_gdbus_cal_complete_add_timezone (cal->priv->gdbus_object, invocation, op->id);
+	e_operation_pool_push (ops_pool, op);
 
-	/* log query to evaluate cache performance */
-	e_debug_log (FALSE, E_DEBUG_LOG_DOMAIN_CAL_QUERIES, "%p;%p;REUSED;%s;%s", cal, query, sexp, G_OBJECT_TYPE_NAME (cal->priv->backend));
+	return TRUE;
+}
 
-	path = construct_calview_path ();
-	e_data_cal_view_register_gdbus_object (query, g_dbus_method_invocation_get_connection (invocation), path, &error);
+static gboolean
+impl_Cal_authenticateUser (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar * const *in_credentials, EDataCal *cal)
+{
+	OperationData *op;
 
-	if (error) {
-		g_object_unref (query);
-		e_data_cal_notify_query (cal, invocation, EDC_ERROR_EX (OtherError, error->message), NULL);
+	if (in_credentials == NULL) {
+		GError *error = e_data_cal_create_error (InvalidArg, NULL);
+		/* Translators: This is prefix to a detailed error message */
+		data_cal_return_error (invocation, error, _("Cannot authenticate user: "));
 		g_error_free (error);
-		g_free (path);
-
 		return TRUE;
 	}
 
-	e_cal_backend_add_query (cal->priv->backend, query);
-
-	e_data_cal_notify_query (cal, invocation, EDC_ERROR (Success), path);
+	op = op_new (OP_AUTHENTICATE, cal);
+	op->d.credentials = e_credentials_new_strv (in_credentials);
 
-	g_free (path);
+	e_gdbus_cal_complete_authenticate_user (cal->priv->gdbus_object, invocation, NULL);
+	e_operation_pool_push (ops_pool, op);
 
 	return TRUE;
 }
 
-/* EDataCal::getTimezone method */
 static gboolean
-impl_Cal_getTimezone (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar *tzid, EDataCal *cal)
+impl_Cal_cancelOperation (EGdbusCal *object, GDBusMethodInvocation *invocation, guint in_opid, EDataCal *cal)
 {
-	e_cal_backend_get_timezone (cal->priv->backend, cal, invocation, tzid);
+	OperationData *op;
+
+	op = op_new (OP_CANCEL_OPERATION, cal);
+	op->d.opid = in_opid;
+
+	e_gdbus_cal_complete_cancel_operation (cal->priv->gdbus_object, invocation, NULL);
+	e_operation_pool_push (ops_pool, op);
 
 	return TRUE;
 }
 
-/* EDataCal::addTimezone method */
 static gboolean
-impl_Cal_addTimezone (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar *tz, EDataCal *cal)
+impl_Cal_cancelAll (EGdbusCal *object, GDBusMethodInvocation *invocation, EDataCal *cal)
 {
-	e_cal_backend_add_timezone (cal->priv->backend, cal, invocation, tz);
+	OperationData *op;
+
+	op = op_new (OP_CANCEL_ALL, cal);
+
+	e_gdbus_cal_complete_cancel_all (cal->priv->gdbus_object, invocation, NULL);
+	e_operation_pool_push (ops_pool, op);
 
 	return TRUE;
 }
 
-/* EDataCal::setDefaultTimezone method */
 static gboolean
-impl_Cal_setDefaultTimezone (EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar *tz, EDataCal *cal)
+impl_Cal_close (EGdbusCal *object, GDBusMethodInvocation *invocation, EDataCal *cal)
 {
-	e_cal_backend_set_default_zone (cal->priv->backend, cal, invocation, tz);
+	OperationData *op;
 
-	return TRUE;
-}
+	op = op_new (OP_CLOSE, cal);
 
-/* free returned pointer with g_strfreev() */
-static gchar **
-create_str_array_from_glist (GList *lst)
-{
-	gchar **seq;
-	GList *l;
-	gint i;
+	e_gdbus_cal_complete_close (cal->priv->gdbus_object, invocation, NULL);
+	e_operation_pool_push (ops_pool, op);
 
-	seq = g_new0 (gchar *, g_list_length (lst) + 1);
-	for (l = lst, i = 0; l; l = l->next, i++) {
-		seq[i] = e_util_utf8_make_valid (l->data);
-	}
+	g_object_unref (cal);
 
-	return seq;
+	return TRUE;
 }
 
 /* free returned pointer with g_strfreev() */
 static gchar **
-create_str_array_from_gslist (GSList *lst)
+gslist_to_strv (const GSList *lst)
 {
 	gchar **seq;
-	GSList *l;
+	const GSList *l;
 	gint i;
 
-	seq = g_new0 (gchar *, g_slist_length (lst) + 1);
+	seq = g_new0 (gchar *, g_slist_length ((GSList *) lst) + 1);
 	for (l = lst, i = 0; l; l = l->next, i++) {
 		seq[i] = e_util_utf8_make_valid (l->data);
 	}
@@ -570,215 +894,223 @@ create_str_array_from_gslist (GSList *lst)
 }
 
 /**
- * e_data_cal_notify_read_only:
+ * e_data_cal_notify_open:
  * @cal: A calendar client interface.
  * @error: Operation error, if any, automatically freed if passed it.
- * @read_only: Read only value.
  *
- * Notifies listeners of the completion of the is_read_only method call.
+ * Notifies listeners of the completion of the open method call.
  */
 void
-e_data_cal_notify_read_only (EDataCal *cal, GError *error, gboolean read_only)
+e_data_cal_respond_open (EDataCal *cal, guint32 opid, GError *error)
 {
-	g_return_if_fail (cal != NULL);
-	g_return_if_fail (E_IS_DATA_CAL (cal));
+	op_complete (cal, opid);
+
+	/* Translators: This is prefix to a detailed error message */
+	g_prefix_error (&error, "%s", _("Cannot open calendar: "));
+
+	e_gdbus_cal_emit_open_done (cal->priv->gdbus_object, opid, error);
 
-	if (error) {
-		e_data_cal_notify_error (cal, error->message);
+	if (error)
 		g_error_free (error);
-	} else {
-		e_gdbus_cal_emit_readonly (cal->priv->gdbus_object, read_only);
-	}
 }
 
 /**
- * e_data_cal_notify_cal_address:
+ * e_data_cal_respond_remove:
  * @cal: A calendar client interface.
  * @error: Operation error, if any, automatically freed if passed it.
- * @address: Calendar address.
  *
- * Notifies listeners of the completion of the get_cal_address method call.
+ * Notifies listeners of the completion of the remove method call.
  */
 void
-e_data_cal_notify_cal_address (EDataCal *cal, EServerMethodContext context, GError *error, const gchar *address)
+e_data_cal_respond_remove (EDataCal *cal, guint32 opid, GError *error)
 {
-	GDBusMethodInvocation *invocation = context;
-	if (error) {
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_cal_return_error (invocation, error, _("Cannot retrieve calendar address: %s"));
-		g_error_free (error);
-	} else {
-		gchar *gdbus_address = NULL;
+	op_complete (cal, opid);
 
-		e_gdbus_cal_complete_get_cal_address (cal->priv->gdbus_object, invocation, e_util_ensure_gdbus_string (address, &gdbus_address));
+	/* Translators: This is prefix to a detailed error message */
+	g_prefix_error (&error, "%s", _("Cannot remove calendar: "));
 
-		g_free (gdbus_address);
-	}
+	e_gdbus_cal_emit_remove_done (cal->priv->gdbus_object, opid, error);
+
+	if (error)
+		g_error_free (error);
+	else
+		e_cal_backend_set_is_removed (cal->priv->backend, TRUE);
 }
 
 /**
- * e_data_cal_notify_alarm_email_address:
+ * e_data_cal_respond_refresh:
  * @cal: A calendar client interface.
  * @error: Operation error, if any, automatically freed if passed it.
- * @address: Alarm email address.
  *
- * Notifies listeners of the completion of the get_alarm_email_address method call.
+ * Notifies listeners of the completion of the refresh method call.
+ *
+ * Since: 2.30
  */
 void
-e_data_cal_notify_alarm_email_address (EDataCal *cal, EServerMethodContext context, GError *error, const gchar *address)
+e_data_cal_respond_refresh (EDataCal *cal, guint32 opid, GError *error)
 {
-	GDBusMethodInvocation *invocation = context;
-	if (error) {
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_cal_return_error (invocation, error, _("Cannot retrieve calendar alarm e-mail address: %s"));
-		g_error_free (error);
-	} else {
-		gchar *gdbus_address = NULL;
+	op_complete (cal, opid);
 
-		e_gdbus_cal_complete_get_alarm_email_address (cal->priv->gdbus_object, invocation, e_util_ensure_gdbus_string (address, &gdbus_address));
+	/* Translators: This is prefix to a detailed error message */
+	g_prefix_error (&error, "%s", _("Cannot refresh calendar: "));
 
-		g_free (gdbus_address);
-	}
+	e_gdbus_cal_emit_refresh_done (cal->priv->gdbus_object, opid, error);
+
+	if (error)
+		g_error_free (error);
 }
 
 /**
- * e_data_cal_notify_ldap_attribute:
+ * e_data_cal_respond_get_backend_property:
  * @cal: A calendar client interface.
  * @error: Operation error, if any, automatically freed if passed it.
- * @attibute: LDAP attribute.
+ * @prop_value: Value of a property
  *
- * Notifies listeners of the completion of the get_ldap_attribute method call.
+ * Notifies listeners of the completion of the get_backend_property method call.
  */
 void
-e_data_cal_notify_ldap_attribute (EDataCal *cal, EServerMethodContext context, GError *error, const gchar *attribute)
+e_data_cal_respond_get_backend_property (EDataCal *cal, guint32 opid, GError *error, const gchar *prop_value)
 {
-	GDBusMethodInvocation *invocation = context;
-	if (error) {
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_cal_return_error (invocation, error, _("Cannot retrieve calendar's LDAP attribute: %s"));
-		g_error_free (error);
-	} else {
-		gchar *gdbus_attribute = NULL;
+	gchar *gdbus_prop_value = NULL;
 
-		e_gdbus_cal_complete_get_ldap_attribute (cal->priv->gdbus_object, invocation, e_util_ensure_gdbus_string (attribute, &gdbus_attribute));
+	op_complete (cal, opid);
 
-		g_free (gdbus_attribute);
-	}
+	/* Translators: This is prefix to a detailed error message */
+	g_prefix_error (&error, "%s", _("Cannot retrieve backend property: "));
+
+	e_gdbus_cal_emit_get_backend_property_done (cal->priv->gdbus_object, opid, error, e_util_ensure_gdbus_string (prop_value, &gdbus_prop_value));
+
+	g_free (gdbus_prop_value);
+	if (error)
+		g_error_free (error);
 }
 
 /**
- * e_data_cal_notify_static_capabilities:
+ * e_data_cal_respond_set_backend_property:
  * @cal: A calendar client interface.
  * @error: Operation error, if any, automatically freed if passed it.
- * @capabilities: Static capabilities from the backend.
  *
- * Notifies listeners of the completion of the get_static_capabilities method call.
+ * Notifies listeners of the completion of the set_backend_property method call.
  */
 void
-e_data_cal_notify_static_capabilities (EDataCal *cal, EServerMethodContext context, GError *error, const gchar *capabilities)
+e_data_cal_respond_set_backend_property (EDataCal *cal, guint32 opid, GError *error)
 {
-	GDBusMethodInvocation *invocation = context;
-	if (error) {
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_cal_return_error (invocation, error, _("Cannot retrieve calendar scheduling information: %s"));
-		g_error_free (error);
-	} else {
-		gchar *gdbus_capabilities = NULL;
+	op_complete (cal, opid);
 
-		e_gdbus_cal_complete_get_scheduling_information (cal->priv->gdbus_object, invocation, e_util_ensure_gdbus_string (capabilities, &gdbus_capabilities));
+	/* Translators: This is prefix to a detailed error message */
+	g_prefix_error (&error, "%s", _("Cannot set backend property: "));
 
-		g_free (gdbus_capabilities);
-	}
+	e_gdbus_cal_emit_set_backend_property_done (cal->priv->gdbus_object, opid, error);
+
+	if (error)
+		g_error_free (error);
 }
 
 /**
- * e_data_cal_notify_open:
+ * e_data_cal_respond_get_object:
  * @cal: A calendar client interface.
  * @error: Operation error, if any, automatically freed if passed it.
+ * @object: The object retrieved as an iCalendar string.
  *
- * Notifies listeners of the completion of the open method call.
+ * Notifies listeners of the completion of the get_object method call.
  */
 void
-e_data_cal_notify_open (EDataCal *cal, EServerMethodContext context, GError *error)
+e_data_cal_respond_get_object (EDataCal *cal, guint32 opid, GError *error, const gchar *object)
 {
-	GDBusMethodInvocation *invocation = context;
-	if (error) {
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_cal_return_error (invocation, error, _("Cannot open calendar: %s"));
+	gchar *gdbus_object = NULL;
+
+	op_complete (cal, opid);
+
+	/* Translators: This is prefix to a detailed error message */
+	g_prefix_error (&error, "%s", _("Cannot retrieve calendar object path: "));
+
+	e_gdbus_cal_emit_get_object_done (cal->priv->gdbus_object, opid, error, e_util_ensure_gdbus_string (object, &gdbus_object));
+
+	g_free (gdbus_object);
+	if (error)
 		g_error_free (error);
-	} else
-		e_gdbus_cal_complete_open (cal->priv->gdbus_object, invocation);
 }
 
 /**
- * e_data_cal_notify_refresh:
+ * e_data_cal_respond_get_object_list:
  * @cal: A calendar client interface.
  * @error: Operation error, if any, automatically freed if passed it.
+ * @objects: List of retrieved objects.
  *
- * Notifies listeners of the completion of the refresh method call.
- *
- * Since: 2.30
+ * Notifies listeners of the completion of the get_object_list method call.
  */
 void
-e_data_cal_notify_refresh (EDataCal *cal, EServerMethodContext context, GError *error)
+e_data_cal_respond_get_object_list (EDataCal *cal, guint32 opid, GError *error, const GSList *objects)
 {
-	GDBusMethodInvocation *invocation = context;
-	if (error) {
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_cal_return_error (invocation, error, _("Cannot refresh calendar: %s"));
+	gchar **strv_objects;
+
+	op_complete (cal, opid);
+
+	/* Translators: This is prefix to a detailed error message */
+	g_prefix_error (&error, "%s", _("Cannot retrieve calendar object list: "));
+
+	strv_objects = gslist_to_strv (objects);
+
+	e_gdbus_cal_emit_get_object_list_done (cal->priv->gdbus_object, opid, error, (const gchar * const *) strv_objects);
+
+	g_strfreev (strv_objects);
+	if (error)
 		g_error_free (error);
-	} else
-		e_gdbus_cal_complete_refresh (cal->priv->gdbus_object, invocation);
 }
 
 /**
- * e_data_cal_notify_remove:
+ * e_data_cal_respond_get_free_busy:
  * @cal: A calendar client interface.
  * @error: Operation error, if any, automatically freed if passed it.
  *
- * Notifies listeners of the completion of the remove method call.
+ * Notifies listeners of the completion of the get_free_busy method call.
+ * To pass actual free/busy objects to the client use e_data_cal_report_free_busy_data().
  */
 void
-e_data_cal_notify_remove (EDataCal *cal, EServerMethodContext context, GError *error)
+e_data_cal_respond_get_free_busy (EDataCal *cal, guint32 opid, GError *error)
 {
-	GDBusMethodInvocation *invocation = context;
-	if (error) {
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_cal_return_error (invocation, error, _("Cannot remove calendar: %s"));
+	op_complete (cal, opid);
+
+	/* Translators: This is prefix to a detailed error message */
+	g_prefix_error (&error, "%s", _("Cannot retrieve calendar free/busy list: "));
+
+	e_gdbus_cal_emit_get_free_busy_done (cal->priv->gdbus_object, opid, error);
+
+	if (error)
 		g_error_free (error);
-	} else
-		e_gdbus_cal_complete_remove (cal->priv->gdbus_object, invocation);
 }
 
 /**
- * e_data_cal_notify_object_created:
+ * e_data_cal_respond_create_object:
  * @cal: A calendar client interface.
  * @error: Operation error, if any, automatically freed if passed it.
  * @uid: UID of the object created.
  * @object: The object created as an iCalendar string.
  *
  * Notifies listeners of the completion of the create_object method call.
- */void
-e_data_cal_notify_object_created (EDataCal *cal, EServerMethodContext context, GError *error,
+ */
+void
+e_data_cal_respond_create_object (EDataCal *cal, guint32 opid, GError *error,
 				  const gchar *uid, const gchar *object)
 {
-	GDBusMethodInvocation *invocation = context;
-	if (error) {
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_cal_return_error (invocation, error, _("Cannot create calendar object: %s"));
-		g_error_free (error);
-	} else {
-		gchar *gdbus_uid = NULL;
+	gchar *gdbus_uid = NULL;
 
-		e_cal_backend_notify_object_created (cal->priv->backend, object);
-		e_gdbus_cal_complete_create_object (cal->priv->gdbus_object, invocation, e_util_ensure_gdbus_string (uid, &gdbus_uid));
+	op_complete (cal, opid);
 
-		g_free (gdbus_uid);
-	}
+	/* Translators: This is prefix to a detailed error message */
+	g_prefix_error (&error, "%s", _("Cannot create calendar object: "));
+
+	e_gdbus_cal_emit_create_object_done (cal->priv->gdbus_object, opid, error, e_util_ensure_gdbus_string (uid, &gdbus_uid));
+
+	g_free (gdbus_uid);
+	if (error)
+		g_error_free (error);
+	else
+		e_cal_backend_notify_object_created (cal->priv->backend, object);
 }
 
 /**
- * e_data_cal_notify_object_modified:
+ * e_data_cal_respond_modify_object:
  * @cal: A calendar client interface.
  * @error: Operation error, if any, automatically freed if passed it.
  * @old_object: The old object as an iCalendar string.
@@ -787,22 +1119,24 @@ e_data_cal_notify_object_created (EDataCal *cal, EServerMethodContext context, G
  * Notifies listeners of the completion of the modify_object method call.
  */
 void
-e_data_cal_notify_object_modified (EDataCal *cal, EServerMethodContext context, GError *error,
-				   const gchar *old_object, const gchar *object)
+e_data_cal_respond_modify_object (EDataCal *cal, guint32 opid, GError *error,
+				  const gchar *old_object, const gchar *object)
 {
-	GDBusMethodInvocation *invocation = context;
-	if (error) {
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_cal_return_error (invocation, error, _("Cannot modify calendar object: %s"));
+	op_complete (cal, opid);
+
+	/* Translators: This is prefix to a detailed error message */
+	g_prefix_error (&error, "%s", _("Cannot modify calendar object: "));
+
+	e_gdbus_cal_emit_modify_object_done (cal->priv->gdbus_object, opid, error);
+
+	if (error)
 		g_error_free (error);
-	} else {
+	else
 		e_cal_backend_notify_object_modified (cal->priv->backend, old_object, object);
-		e_gdbus_cal_complete_modify_object (cal->priv->gdbus_object, invocation);
-	}
 }
 
 /**
- * e_data_cal_notify_object_removed:
+ * e_data_cal_respond_remove_object:
  * @cal: A calendar client interface.
  * @error: Operation error, if any, automatically freed if passed it.
  * @uid: UID of the removed object.
@@ -813,60 +1147,45 @@ e_data_cal_notify_object_modified (EDataCal *cal, EServerMethodContext context,
  * Notifies listeners of the completion of the remove_object method call.
  */
 void
-e_data_cal_notify_object_removed (EDataCal *cal, EServerMethodContext context, GError *error,
+e_data_cal_respond_remove_object (EDataCal *cal, guint32 opid, GError *error,
 				  const ECalComponentId *id, const gchar *old_object, const gchar *object)
 {
-	GDBusMethodInvocation *invocation = context;
-	if (error) {
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_cal_return_error (invocation, error, _("Cannot remove calendar object: %s"));
+	op_complete (cal, opid);
+
+	/* Translators: This is prefix to a detailed error message */
+	g_prefix_error (&error, "%s", _("Cannot remove calendar object: "));
+
+	e_gdbus_cal_emit_remove_object_done (cal->priv->gdbus_object, opid, error);
+
+	if (error)
 		g_error_free (error);
-	} else {
+	else
 		e_cal_backend_notify_object_removed (cal->priv->backend, id, old_object, object);
-		e_gdbus_cal_complete_remove_object (cal->priv->gdbus_object, invocation);
-	}
 }
 
 /**
- * e_data_cal_notify_objects_received:
+ * e_data_cal_respond_receive_objects:
  * @cal: A calendar client interface.
  * @error: Operation error, if any, automatically freed if passed it.
  *
  * Notifies listeners of the completion of the receive_objects method call.
  */
 void
-e_data_cal_notify_objects_received (EDataCal *cal, EServerMethodContext context, GError *error)
+e_data_cal_respond_receive_objects (EDataCal *cal, guint32 opid, GError *error)
 {
-	GDBusMethodInvocation *invocation = context;
-	if (error) {
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_cal_return_error (invocation, error, _("Cannot receive calendar objects: %s"));
-		g_error_free (error);
-	} else
-		e_gdbus_cal_complete_receive_objects (cal->priv->gdbus_object, invocation);
-}
+	op_complete (cal, opid);
 
-/**
- * e_data_cal_notify_alarm_discarded:
- * @cal: A calendar client interface.
- * @error: Operation error, if any, automatically freed if passed it.
- *
- * Notifies listeners of the completion of the discard_alarm method call.
- */
-void
-e_data_cal_notify_alarm_discarded (EDataCal *cal, EServerMethodContext context, GError *error)
-{
-	GDBusMethodInvocation *invocation = context;
-	if (error) {
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_cal_return_error (invocation, error, _("Cannot discard calendar alarm: %s"));
+	/* Translators: This is prefix to a detailed error message */
+	g_prefix_error (&error, "%s", _("Cannot receive calendar objects: "));
+
+	e_gdbus_cal_emit_receive_objects_done (cal->priv->gdbus_object, opid, error);
+
+	if (error)
 		g_error_free (error);
-	} else
-		e_gdbus_cal_complete_discard_alarm (cal->priv->gdbus_object, invocation);
 }
 
 /**
- * e_data_cal_notify_objects_sent:
+ * e_data_cal_respond_send_objects:
  * @cal: A calendar client interface.
  * @error: Operation error, if any, automatically freed if passed it.
  * @users: List of users.
@@ -875,330 +1194,219 @@ e_data_cal_notify_alarm_discarded (EDataCal *cal, EServerMethodContext context,
  * Notifies listeners of the completion of the send_objects method call.
  */
 void
-e_data_cal_notify_objects_sent (EDataCal *cal, EServerMethodContext context, GError *error, GList *users, const gchar *calobj)
+e_data_cal_respond_send_objects (EDataCal *cal, guint32 opid, GError *error, const GSList *users, const gchar *calobj)
 {
-	GDBusMethodInvocation *invocation = context;
-	if (error) {
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_cal_return_error (invocation, error, _("Cannot send calendar objects: %s"));
-		g_error_free (error);
-	} else {
-		gchar **users_array = create_str_array_from_glist (users);
-		gchar *gdbus_calobj = NULL;
+	gchar **strv_users_calobj;
 
-		e_gdbus_cal_complete_send_objects (cal->priv->gdbus_object, invocation, (const gchar * const *) users_array, e_util_ensure_gdbus_string (calobj, &gdbus_calobj));
+	op_complete (cal, opid);
 
-		g_free (gdbus_calobj);
-		g_strfreev (users_array);
-	}
-}
+	/* Translators: This is prefix to a detailed error message */
+	g_prefix_error (&error, "%s", _("Cannot send calendar objects: "));
 
-/**
- * e_data_cal_notify_default_object:
- * @cal: A calendar client interface.
- * @error: Operation error, if any, automatically freed if passed it.
- * @object: The default object as an iCalendar string.
- *
- * Notifies listeners of the completion of the get_default_object method call.
- */
-void
-e_data_cal_notify_default_object (EDataCal *cal, EServerMethodContext context, GError *error, const gchar *object)
-{
-	GDBusMethodInvocation *invocation = context;
-	if (error) {
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_cal_return_error (invocation, error, _("Cannot retrieve default calendar object path: %s"));
-		g_error_free (error);
-	} else {
-		gchar *gdbus_object = NULL;
+	strv_users_calobj = e_gdbus_cal_encode_send_objects (calobj, users);
 
-		e_gdbus_cal_complete_get_default_object (cal->priv->gdbus_object, invocation, e_util_ensure_gdbus_string (object, &gdbus_object));
+	e_gdbus_cal_emit_send_objects_done (cal->priv->gdbus_object, opid, error, (const gchar * const *) strv_users_calobj);
 
-		g_free (gdbus_object);
-	}
+	g_strfreev (strv_users_calobj);
+	if (error)
+		g_error_free (error);
 }
 
 /**
- * e_data_cal_notify_object:
+ * e_data_cal_respond_get_attachment_uris:
  * @cal: A calendar client interface.
  * @error: Operation error, if any, automatically freed if passed it.
- * @object: The object retrieved as an iCalendar string.
+ * @attachment_uris: List of retrieved attachment uri's.
  *
- * Notifies listeners of the completion of the get_object method call.
- */
+ * Notifies listeners of the completion of the get_attachment_uris method call.
+ **/
 void
-e_data_cal_notify_object (EDataCal *cal, EServerMethodContext context, GError *error, const gchar *object)
+e_data_cal_respond_get_attachment_uris (EDataCal *cal, guint32 opid, GError *error, const GSList *attachment_uris)
 {
-	GDBusMethodInvocation *invocation = context;
-	if (error) {
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_cal_return_error (invocation, error, _("Cannot retrieve calendar object path: %s"));
-		g_error_free (error);
-	} else {
-		gchar *gdbus_object = NULL;
+	gchar **strv_attachment_uris;
 
-		e_gdbus_cal_complete_get_object (cal->priv->gdbus_object, invocation, e_util_ensure_gdbus_string (object, &gdbus_object));
+	op_complete (cal, opid);
 
-		g_free (gdbus_object);
-	}
-}
+	/* Translators: This is prefix to a detailed error message */
+	g_prefix_error (&error, "%s", _("Could not retrieve attachment uris: "));
 
-/**
- * e_data_cal_notify_object_list:
- * @cal: A calendar client interface.
- * @error: Operation error, if any, automatically freed if passed it.
- * @objects: List of retrieved objects.
- *
- * Notifies listeners of the completion of the get_object_list method call.
- */
-void
-e_data_cal_notify_object_list (EDataCal *cal, EServerMethodContext context, GError *error, GList *objects)
-{
-	GDBusMethodInvocation *invocation = context;
-	if (error) {
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_cal_return_error (invocation, error, _("Cannot retrieve calendar object list: %s"));
-		g_error_free (error);
-	} else {
-		gchar **seq = create_str_array_from_glist (objects);
+	strv_attachment_uris = gslist_to_strv (attachment_uris);
 
-		e_gdbus_cal_complete_get_object_list (cal->priv->gdbus_object, invocation, (const gchar * const *) seq);
+	e_gdbus_cal_emit_get_attachment_uris_done (cal->priv->gdbus_object, opid, error, (const gchar * const *) strv_attachment_uris);
 
-		g_strfreev (seq);
-	}
+	g_strfreev (strv_attachment_uris);
+	if (error)
+		g_error_free (error);
 }
 
 /**
- * e_data_cal_notify_attachment_list:
+ * e_data_cal_respond_discard_alarm:
  * @cal: A calendar client interface.
  * @error: Operation error, if any, automatically freed if passed it.
- * @attachments: List of retrieved attachment uri's.
  *
- * Notifies listeners of the completion of the get_attachment_list method call.+ */
+ * Notifies listeners of the completion of the discard_alarm method call.
+ **/
 void
-e_data_cal_notify_attachment_list (EDataCal *cal, EServerMethodContext context, GError *error, GSList *attachments)
+e_data_cal_respond_discard_alarm (EDataCal *cal, guint32 opid, GError *error)
 {
-	GDBusMethodInvocation *invocation = context;
-	gchar **seq;
+	op_complete (cal, opid);
 
-	seq = create_str_array_from_gslist (attachments);
+	/* Translators: This is prefix to a detailed error message */
+	g_prefix_error (&error, "%s", _("Could not discard alarm: "));
 
-	if (error) {
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_cal_return_error (invocation, error, _("Could not retrieve attachment list: %s"));
-		g_error_free (error);
-	} else
-		e_gdbus_cal_complete_get_attachment_list (cal->priv->gdbus_object, invocation, (const gchar * const *) seq);
+	e_gdbus_cal_emit_discard_alarm_done (cal->priv->gdbus_object, opid, error);
 
-	g_strfreev (seq);
+	if (error)
+		g_error_free (error);
 }
 
 /**
- * e_data_cal_notify_query:
+ * e_data_cal_respond_get_view:
  * @cal: A calendar client interface.
  * @error: Operation error, if any, automatically freed if passed it.
- * @query: The new live query.
+ * @view_path: The new live view path.
  *
- * Notifies listeners of the completion of the get_query method call.
+ * Notifies listeners of the completion of the get_view method call.
  */
 void
-e_data_cal_notify_query (EDataCal *cal, EServerMethodContext context, GError *error, const gchar *query)
-{
-	/*
-	 * Only have a seperate notify function to follow suit with the rest of this
-	 * file - it'd be much easier to just do the return in the above function
-	 */
-	GDBusMethodInvocation *invocation = context;
-	if (error) {
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_cal_return_error (invocation, error, _("Could not complete calendar query: %s"));
-		g_error_free (error);
-	} else {
-		gchar *gdbus_query = NULL;
+e_data_cal_respond_get_view (EDataCal *cal, guint32 opid, GError *error, const gchar *view_path)
+{
+	gchar *gdbus_view_path = NULL;
 
-		e_gdbus_cal_complete_get_query (cal->priv->gdbus_object, invocation, e_util_ensure_gdbus_string (query, &gdbus_query));
+	op_complete (cal, opid);
 
-		g_free (gdbus_query);
-	}
+	/* Translators: This is prefix to a detailed error message */
+	g_prefix_error (&error, "%s", _("Could not get calendar view path: "));
+
+	e_gdbus_cal_emit_get_view_done (cal->priv->gdbus_object, opid, error, e_util_ensure_gdbus_string (view_path, &gdbus_view_path));
+
+	g_free (gdbus_view_path);
+	if (error)
+		g_error_free (error);
 }
 
 /**
- * e_data_cal_notify_timezone_requested:
+ * e_data_cal_respond_get_timezone:
  * @cal: A calendar client interface.
  * @error: Operation error, if any, automatically freed if passed it.
- * @object: The requested timezone as an iCalendar string.
+ * @tzobject: The requested timezone as an iCalendar string.
  *
  * Notifies listeners of the completion of the get_timezone method call.
  */
 void
-e_data_cal_notify_timezone_requested (EDataCal *cal, EServerMethodContext context, GError *error, const gchar *object)
+e_data_cal_respond_get_timezone (EDataCal *cal, guint32 opid, GError *error, const gchar *tzobject)
 {
-	GDBusMethodInvocation *invocation = context;
-	if (error) {
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_cal_return_error (invocation, error, _("Could not retrieve calendar time zone: %s"));
-		g_error_free (error);
-	} else {
-		gchar *gdbus_object = NULL;
+	gchar *gdbus_tzobject = NULL;
 
-		e_gdbus_cal_complete_get_timezone (cal->priv->gdbus_object, invocation, e_util_ensure_gdbus_string (object, &gdbus_object));
+	op_complete (cal, opid);
 
-		g_free (gdbus_object);
-	}
+	/* Translators: This is prefix to a detailed error message */
+	g_prefix_error (&error, "%s", _("Could not retrieve calendar time zone: "));
+
+	e_gdbus_cal_emit_get_timezone_done (cal->priv->gdbus_object, opid, error, e_util_ensure_gdbus_string (tzobject, &gdbus_tzobject));
+
+	g_free (gdbus_tzobject);
+	if (error)
+		g_error_free (error);
 }
 
 /**
  * e_data_cal_notify_timezone_added:
  * @cal: A calendar client interface.
  * @error: Operation error, if any, automatically freed if passed it.
- * @tzid: ID of the added timezone.
  *
  * Notifies listeners of the completion of the add_timezone method call.
  */
 void
-e_data_cal_notify_timezone_added (EDataCal *cal, EServerMethodContext context, GError *error, const gchar *tzid)
+e_data_cal_respond_add_timezone (EDataCal *cal, guint32 opid, GError *error)
 {
-	GDBusMethodInvocation *invocation = context;
-	if (error) {
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_cal_return_error (invocation, error, _("Could not add calendar time zone: %s"));
+	op_complete (cal, opid);
+
+	/* Translators: This is prefix to a detailed error message */
+	g_prefix_error (&error, "%s", _("Could not add calendar time zone: "));
+
+	e_gdbus_cal_emit_add_timezone_done (cal->priv->gdbus_object, opid, error);
+
+	if (error)
 		g_error_free (error);
-	} else
-		e_gdbus_cal_complete_add_timezone (cal->priv->gdbus_object, invocation);
 }
 
-/**
- * e_data_cal_notify_default_timezone_set:
- * @cal: A calendar client interface.
- * @error: Operation error, if any, automatically freed if passed it.
- *
- * Notifies listeners of the completion of the set_default_timezone method call.
- */
 void
-e_data_cal_notify_default_timezone_set (EDataCal *cal, EServerMethodContext context, GError *error)
+e_data_cal_report_error (EDataCal *cal, const gchar *message)
 {
-	GDBusMethodInvocation *invocation = context;
-	if (error) {
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_cal_return_error (invocation, error, _("Could not set default calendar time zone: %s"));
-		g_error_free (error);
-	} else
-		e_gdbus_cal_complete_set_default_timezone (cal->priv->gdbus_object, invocation);
+	g_return_if_fail (cal != NULL);
+	g_return_if_fail (message != NULL);
+
+	e_gdbus_cal_emit_backend_error (cal->priv->gdbus_object, message);
 }
 
-/**
- * e_data_cal_notify_changes:
- * @cal: A calendar client interface.
- * @error: Operation error, if any, automatically freed if passed it.
- * @adds: List of additions.
- * @modifies: List of modifications.
- * @deletes: List of removals.
- *
- * Notifies listeners of the completion of the get_changes method call.
- */
 void
-e_data_cal_notify_changes (EDataCal *cal, EServerMethodContext context, GError *error,
-			   GList *adds, GList *modifies, GList *deletes)
+e_data_cal_report_readonly (EDataCal *cal, gboolean readonly)
 {
-	GDBusMethodInvocation *invocation = context;
-	if (error) {
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_cal_return_error (invocation, error, _("Cannot retrieve calendar changes: %s"));
-		g_error_free (error);
-	} else {
-		gchar **additions, **modifications, **removals;
-
-		additions = create_str_array_from_glist (adds);
-		modifications = create_str_array_from_glist (modifies);
-		removals = create_str_array_from_glist (deletes);
-
-		e_gdbus_cal_complete_get_changes (cal->priv->gdbus_object, invocation, (const gchar * const *) additions, (const gchar * const *) modifications, (const gchar * const *) removals);
+	g_return_if_fail (cal != NULL);
 
-		g_strfreev (additions);
-		g_strfreev (modifications);
-		g_strfreev (removals);
-	}
+	e_gdbus_cal_emit_readonly (cal->priv->gdbus_object, readonly);
 }
 
-/**
- * e_data_cal_notify_free_busy:
- * @cal: A calendar client interface.
- * @error: Operation error, if any, automatically freed if passed it.
- * @freebusy: List of free/busy objects.
- *
- * Notifies listeners of the completion of the get_free_busy method call.
- */
 void
-e_data_cal_notify_free_busy (EDataCal *cal, EServerMethodContext context, GError *error, GList *freebusy)
+e_data_cal_report_online (EDataCal *cal, gboolean is_online)
 {
-	GDBusMethodInvocation *invocation = context;
-	if (error) {
-		/* Translators: The '%s' is replaced with a detailed error message */
-		data_cal_return_error (invocation, error, _("Cannot retrieve calendar free/busy list: %s"));
-		g_error_free (error);
-	} else {
-		gchar **seq;
-
-		seq = create_str_array_from_glist (freebusy);
-
-		e_gdbus_cal_complete_get_free_busy (cal->priv->gdbus_object, invocation, (const gchar * const *) seq);
+	g_return_if_fail (cal != NULL);
 
-		g_strfreev (seq);
-	}
+	e_gdbus_cal_emit_online (cal->priv->gdbus_object, is_online);
 }
 
-/**
- * e_data_cal_notify_mode:
- * @cal: A calendar client interface.
- * @status: Status of the mode set.
- * @mode: The current mode.
- *
- * Notifies the listener of the results of a set_mode call.
- **/
+/* credentilas contains extra information for a source for which authentication is requested.
+   This parameter can be NULL to indicate "for this calendar".
+*/
 void
-e_data_cal_notify_mode (EDataCal *cal,
-			EDataCalViewListenerSetModeStatus status,
-			EDataCalMode mode)
+e_data_cal_report_auth_required (EDataCal *cal, const ECredentials *credentials)
 {
+	gchar *empty_strv[2];
+	gchar **strv = NULL;
+
 	g_return_if_fail (cal != NULL);
-	g_return_if_fail (E_IS_DATA_CAL (cal));
 
-	e_gdbus_cal_emit_mode (cal->priv->gdbus_object, mode);
+	empty_strv[0] = NULL;
+	empty_strv[1] = NULL;
+
+	if (credentials)
+		strv = e_credentials_to_strv (credentials);
+
+	e_gdbus_cal_emit_auth_required (cal->priv->gdbus_object, (const gchar * const *) (strv ? strv : empty_strv));
+
+	g_strfreev (strv);
 }
 
-/**
- * e_data_cal_notify_auth_required:
- * @cal: A calendar client interface.
- *
- * Notifies listeners that authorization is required to open the calendar.
- */
+/* Reports to associated client that opening phase of the cal is finished.
+   error being NULL means successfully, otherwise reports an error which happened
+   during opening phase. By opening phase is meant a process including successfull
+   authentication to the server/storage.
+*/
 void
-e_data_cal_notify_auth_required (EDataCal *cal)
+e_data_cal_report_opened (EDataCal *cal, const GError *error)
 {
-	g_return_if_fail (cal != NULL);
-	g_return_if_fail (E_IS_DATA_CAL (cal));
+	gchar **strv_error;
 
-	e_gdbus_cal_emit_auth_required (cal->priv->gdbus_object);
+	strv_error = e_gdbus_templates_encode_error (error);
+
+	e_gdbus_cal_emit_opened (cal->priv->gdbus_object, (const gchar * const *) strv_error);
+
+	g_strfreev (strv_error);
 }
 
-/**
- * e_data_cal_notify_error
- * @cal: A calendar client interface.
- * @message: Error message.
- *
- * Notify a calendar client of an error occurred in the backend.
- */
 void
-e_data_cal_notify_error (EDataCal *cal, const gchar *message)
+e_data_cal_report_free_busy_data (EDataCal *cal, const GSList *freebusy)
 {
-	gchar *gdbus_message = NULL;
+	gchar **strv_freebusy;
 
 	g_return_if_fail (cal != NULL);
-	g_return_if_fail (E_IS_DATA_CAL (cal));
 
-	e_gdbus_cal_emit_backend_error (cal->priv->gdbus_object, e_util_ensure_gdbus_string (message, &gdbus_message));
+	strv_freebusy = gslist_to_strv (freebusy);
 
-	g_free (gdbus_message);
+	e_gdbus_cal_emit_free_busy_data (cal->priv->gdbus_object, (const gchar * const *) strv_freebusy);
+
+	g_strfreev (strv_freebusy);
 }
 
 /* Instance init */
@@ -1207,52 +1415,76 @@ e_data_cal_init (EDataCal *ecal)
 {
 	EGdbusCal *gdbus_object;
 
-	ecal->priv = G_TYPE_INSTANCE_GET_PRIVATE (
-		ecal, E_TYPE_DATA_CAL, EDataCalPrivate);
+	ecal->priv = G_TYPE_INSTANCE_GET_PRIVATE (ecal, E_TYPE_DATA_CAL, EDataCalPrivate);
 
 	ecal->priv->gdbus_object = e_gdbus_cal_stub_new ();
+	ecal->priv->pending_ops = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
+	g_static_rec_mutex_init (&ecal->priv->pending_ops_lock);
 
 	gdbus_object = ecal->priv->gdbus_object;
-	g_signal_connect (gdbus_object, "handle-get-uri", G_CALLBACK (impl_Cal_getUri), ecal);
-	g_signal_connect (gdbus_object, "handle-get-cache-dir", G_CALLBACK (impl_Cal_getCacheDir), ecal);
 	g_signal_connect (gdbus_object, "handle-open", G_CALLBACK (impl_Cal_open), ecal);
-	g_signal_connect (gdbus_object, "handle-refresh", G_CALLBACK (impl_Cal_refresh), ecal);
-	g_signal_connect (gdbus_object, "handle-close", G_CALLBACK (impl_Cal_close), ecal);
+	g_signal_connect (gdbus_object, "handle-authenticate-user", G_CALLBACK (impl_Cal_authenticateUser), ecal);
 	g_signal_connect (gdbus_object, "handle-remove", G_CALLBACK (impl_Cal_remove), ecal);
-	g_signal_connect (gdbus_object, "handle-is-read-only", G_CALLBACK (impl_Cal_isReadOnly), ecal);
-	g_signal_connect (gdbus_object, "handle-get-cal-address", G_CALLBACK (impl_Cal_getCalAddress), ecal);
-	g_signal_connect (gdbus_object, "handle-get-alarm-email-address", G_CALLBACK (impl_Cal_getAlarmEmailAddress), ecal);
-	g_signal_connect (gdbus_object, "handle-get-ldap-attribute", G_CALLBACK (impl_Cal_getLdapAttribute), ecal);
-	g_signal_connect (gdbus_object, "handle-get-scheduling-information", G_CALLBACK (impl_Cal_getSchedulingInformation), ecal);
-	g_signal_connect (gdbus_object, "handle-set-mode", G_CALLBACK (impl_Cal_setMode), ecal);
-	g_signal_connect (gdbus_object, "handle-get-default-object", G_CALLBACK (impl_Cal_getDefaultObject), ecal);
+	g_signal_connect (gdbus_object, "handle-refresh", G_CALLBACK (impl_Cal_refresh), ecal);
+	g_signal_connect (gdbus_object, "handle-get-backend-property", G_CALLBACK (impl_Cal_getBackendProperty), ecal);
+	g_signal_connect (gdbus_object, "handle-set-backend-property", G_CALLBACK (impl_Cal_setBackendProperty), ecal);
 	g_signal_connect (gdbus_object, "handle-get-object", G_CALLBACK (impl_Cal_getObject), ecal);
 	g_signal_connect (gdbus_object, "handle-get-object-list", G_CALLBACK (impl_Cal_getObjectList), ecal);
-	g_signal_connect (gdbus_object, "handle-get-changes", G_CALLBACK (impl_Cal_getChanges), ecal);
 	g_signal_connect (gdbus_object, "handle-get-free-busy", G_CALLBACK (impl_Cal_getFreeBusy), ecal);
-	g_signal_connect (gdbus_object, "handle-discard-alarm", G_CALLBACK (impl_Cal_discardAlarm), ecal);
 	g_signal_connect (gdbus_object, "handle-create-object", G_CALLBACK (impl_Cal_createObject), ecal);
 	g_signal_connect (gdbus_object, "handle-modify-object", G_CALLBACK (impl_Cal_modifyObject), ecal);
 	g_signal_connect (gdbus_object, "handle-remove-object", G_CALLBACK (impl_Cal_removeObject), ecal);
 	g_signal_connect (gdbus_object, "handle-receive-objects", G_CALLBACK (impl_Cal_receiveObjects), ecal);
 	g_signal_connect (gdbus_object, "handle-send-objects", G_CALLBACK (impl_Cal_sendObjects), ecal);
-	g_signal_connect (gdbus_object, "handle-get-attachment-list", G_CALLBACK (impl_Cal_getAttachmentList), ecal);
-	g_signal_connect (gdbus_object, "handle-get-query", G_CALLBACK (impl_Cal_getQuery), ecal);
+	g_signal_connect (gdbus_object, "handle-get-attachment-uris", G_CALLBACK (impl_Cal_getAttachmentUris), ecal);
+	g_signal_connect (gdbus_object, "handle-discard-alarm", G_CALLBACK (impl_Cal_discardAlarm), ecal);
+	g_signal_connect (gdbus_object, "handle-get-view", G_CALLBACK (impl_Cal_getView), ecal);
 	g_signal_connect (gdbus_object, "handle-get-timezone", G_CALLBACK (impl_Cal_getTimezone), ecal);
 	g_signal_connect (gdbus_object, "handle-add-timezone", G_CALLBACK (impl_Cal_addTimezone), ecal);
-	g_signal_connect (gdbus_object, "handle-set-default-timezone", G_CALLBACK (impl_Cal_setDefaultTimezone), ecal);
+	g_signal_connect (gdbus_object, "handle-cancel-operation", G_CALLBACK (impl_Cal_cancelOperation), ecal);
+	g_signal_connect (gdbus_object, "handle-cancel-all", G_CALLBACK (impl_Cal_cancelAll), ecal);
+	g_signal_connect (gdbus_object, "handle-close", G_CALLBACK (impl_Cal_close), ecal);
 }
 
 static void
-e_data_cal_finalize (GObject *object)
+data_cal_dispose (GObject *object)
 {
 	EDataCal *cal = E_DATA_CAL (object);
 
 	g_return_if_fail (cal != NULL);
 
-	g_object_unref (cal->priv->gdbus_object);
+	if (cal->priv->backend) {
+		g_object_unref (cal->priv->backend);
+		cal->priv->backend = NULL;
+	}
+
+	if (cal->priv->source) {
+		g_object_unref (cal->priv->source);
+		cal->priv->source = NULL;
+	}
+
+	G_OBJECT_CLASS (e_data_cal_parent_class)->dispose (object);
+}
+
+static void
+data_cal_finalize (GObject *object)
+{
+	EDataCal *cal = E_DATA_CAL (object);
+
+	g_return_if_fail (cal != NULL);
+
+	if (cal->priv->pending_ops) {
+		g_hash_table_destroy (cal->priv->pending_ops);
+		cal->priv->pending_ops = NULL;
+	}
+
+	g_static_rec_mutex_free (&cal->priv->pending_ops_lock);
+
+	if (cal->priv->gdbus_object) {
+		g_object_unref (cal->priv->gdbus_object);
+		cal->priv->gdbus_object = NULL;
+	}
 
-	/* Chain up to parent's finalize() method. */
 	G_OBJECT_CLASS (e_data_cal_parent_class)->finalize (object);
 }
 
@@ -1265,33 +1497,9 @@ e_data_cal_class_init (EDataCalClass *klass)
 	g_type_class_add_private (klass, sizeof (EDataCalPrivate));
 
 	object_class = G_OBJECT_CLASS (klass);
-	object_class->finalize = e_data_cal_finalize;
-}
-
-EDataCal *
-e_data_cal_new (ECalBackend *backend, ESource *source)
-{
-	EDataCal *cal;
-	cal = g_object_new (E_TYPE_DATA_CAL, NULL);
-	cal->priv->backend = backend;
-	cal->priv->source = source;
-	return cal;
-}
+	object_class->dispose = data_cal_dispose;
+	object_class->finalize = data_cal_finalize;
 
-/**
- * e_data_cal_register_gdbus_object:
- *
- * Registers GDBus object of this EDataCal.
- *
- * Since: 2.32
- **/
-guint
-e_data_cal_register_gdbus_object (EDataCal *cal, GDBusConnection *connection, const gchar *object_path, GError **error)
-{
-	g_return_val_if_fail (cal != NULL, 0);
-	g_return_val_if_fail (E_IS_DATA_CAL (cal), 0);
-	g_return_val_if_fail (connection != NULL, 0);
-	g_return_val_if_fail (object_path != NULL, 0);
-
-	return e_gdbus_cal_register_object (cal->priv->gdbus_object, connection, object_path, error);
+	if (!ops_pool)
+		ops_pool = e_operation_pool_new (10, operation_thread, NULL);
 }
diff --git a/calendar/libedata-cal/e-data-cal.h b/calendar/libedata-cal/e-data-cal.h
index 05a270d..9d8b553 100644
--- a/calendar/libedata-cal/e-data-cal.h
+++ b/calendar/libedata-cal/e-data-cal.h
@@ -90,6 +90,28 @@ const gchar *e_data_cal_status_to_string (EDataCalCallStatus status);
 		}								\
 	} G_STMT_END
 
+/**
+ * e_return_data_cal_error_val_if_fail:
+ *
+ * Same as e_return_data_cal_error_if_fail(), only returns FALSE on a failure
+ *
+ * Since: 3.2
+ **/
+#define e_return_data_cal_error_val_if_fail(expr, _code)			\
+	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__, G_STRFUNC, #expr);		\
+			g_set_error (error, E_DATA_CAL_ERROR, (_code),		\
+				"file %s: line %d (%s): assertion `%s' failed",	\
+				__FILE__, __LINE__, G_STRFUNC, #expr);		\
+			return FALSE;						\
+		}								\
+	} G_STMT_END
+
 typedef struct _EDataCalPrivate EDataCalPrivate;
 
 struct _EDataCal {
@@ -103,70 +125,36 @@ struct _EDataCalClass {
 
 GType e_data_cal_get_type (void);
 
-EDataCal *e_data_cal_new (ECalBackend *backend, ESource *source);
-
-guint e_data_cal_register_gdbus_object (EDataCal *cal, GDBusConnection *connection, const gchar *object_path, GError **error);
-
-ECalBackend *e_data_cal_get_backend (EDataCal *cal);
-ESource* e_data_cal_get_source (EDataCal *cal);
-
-void e_data_cal_notify_read_only           (EDataCal *cal, GError *error,
-					    gboolean read_only);
-void e_data_cal_notify_cal_address         (EDataCal *cal, EServerMethodContext context, GError *error,
-					    const gchar *address);
-void e_data_cal_notify_alarm_email_address (EDataCal *cal, EServerMethodContext context, GError *error,
-					    const gchar *address);
-void e_data_cal_notify_ldap_attribute      (EDataCal *cal, EServerMethodContext context, GError *error,
-					    const gchar *attribute);
-void e_data_cal_notify_static_capabilities (EDataCal *cal, EServerMethodContext context, GError *error,
-					    const gchar *capabilities);
-
-void e_data_cal_notify_open   (EDataCal *cal, EServerMethodContext context, GError *error);
-void e_data_cal_notify_refresh (EDataCal *cal, EServerMethodContext context, GError *error);
-void e_data_cal_notify_remove (EDataCal *cal, EServerMethodContext context, GError *error);
-
-void e_data_cal_notify_object_created  (EDataCal *cal, EServerMethodContext context, GError *error,
-					const gchar *uid, const gchar *object);
-void e_data_cal_notify_object_modified (EDataCal *cal, EServerMethodContext context, GError *error,
-					const gchar *old_object, const gchar *object);
-void e_data_cal_notify_object_removed  (EDataCal *cal, EServerMethodContext context, GError *error,
-					const ECalComponentId *id, const gchar *old_object, const gchar *object);
-void e_data_cal_notify_alarm_discarded (EDataCal *cal, EServerMethodContext context, GError *error);
-
-void e_data_cal_notify_objects_received (EDataCal *cal, EServerMethodContext context, GError *error);
-void e_data_cal_notify_objects_sent     (EDataCal *cal, EServerMethodContext context, GError *error, GList *users,
-					 const gchar *calobj);
-
-void e_data_cal_notify_default_object (EDataCal *cal, EServerMethodContext context, GError *error,
-				       const gchar *object);
-void e_data_cal_notify_object         (EDataCal *cal, EServerMethodContext context, GError *error,
-				       const gchar *object);
-void e_data_cal_notify_object_list    (EDataCal *cal, EServerMethodContext context, GError *error,
-				       GList *objects);
-
-void e_data_cal_notify_query (EDataCal *cal, EServerMethodContext context, GError *error,
-			      const gchar *query_path);
-
-void e_data_cal_notify_timezone_requested   (EDataCal *cal, EServerMethodContext context, GError *error,
-					     const gchar *object);
-void e_data_cal_notify_timezone_added       (EDataCal *cal, EServerMethodContext context, GError *error,
-					     const gchar *tzid);
-void e_data_cal_notify_default_timezone_set (EDataCal *cal, EServerMethodContext context, GError *error);
-
-void e_data_cal_notify_changes   (EDataCal *cal, EServerMethodContext context, GError *error,
-				  GList *adds, GList *modifies, GList *deletes);
-void e_data_cal_notify_free_busy (EDataCal *cal, EServerMethodContext context, GError *error,
-				  GList *freebusy);
-
-void e_data_cal_notify_mode  (EDataCal *cal,
-			      EDataCalViewListenerSetModeStatus status,
-			      EDataCalMode mode);
-
-void e_data_cal_notify_auth_required (EDataCal *cal);
-
-void e_data_cal_notify_error (EDataCal *cal, const gchar *message);
-
-void e_data_cal_notify_attachment_list (EDataCal *cal, EServerMethodContext context, GError *error, GSList *objects);
+EDataCal *	e_data_cal_new					(ECalBackend *backend, ESource *source);
+ECalBackend *	e_data_cal_get_backend				(EDataCal *cal);
+ESource *	e_data_cal_get_source				(EDataCal *cal);
+guint		e_data_cal_register_gdbus_object		(EDataCal *cal, GDBusConnection *connection, const gchar *object_path, GError **error);
+
+void		e_data_cal_respond_open				(EDataCal *cal, guint32 opid, GError *error);
+void		e_data_cal_respond_remove			(EDataCal *cal, guint32 opid, GError *error);
+void		e_data_cal_respond_refresh			(EDataCal *cal, guint32 opid, GError *error);
+void		e_data_cal_respond_get_backend_property		(EDataCal *cal, guint32 opid, GError *error, const gchar *prop_value);
+void		e_data_cal_respond_set_backend_property		(EDataCal *cal, guint32 opid, GError *error);
+void		e_data_cal_respond_get_object			(EDataCal *cal, guint32 opid, GError *error, const gchar *object);
+void		e_data_cal_respond_get_object_list		(EDataCal *cal, guint32 opid, GError *error, const GSList *objects);
+void		e_data_cal_respond_get_free_busy		(EDataCal *cal, guint32 opid, GError *error);
+void		e_data_cal_respond_create_object		(EDataCal *cal, guint32 opid, GError *error, const gchar *uid, const gchar *object);
+void		e_data_cal_respond_modify_object		(EDataCal *cal, guint32 opid, GError *error, const gchar *old_object, const gchar *object);
+void		e_data_cal_respond_remove_object		(EDataCal *cal, guint32 opid, GError *error, const ECalComponentId *id, const gchar *old_object, const gchar *object);
+void		e_data_cal_respond_receive_objects		(EDataCal *cal, guint32 opid, GError *error);
+void		e_data_cal_respond_send_objects			(EDataCal *cal, guint32 opid, GError *error, const GSList *users, const gchar *calobj);
+void		e_data_cal_respond_get_attachment_uris		(EDataCal *cal, guint32 opid, GError *error, const GSList *attachments);
+void		e_data_cal_respond_discard_alarm		(EDataCal *cal, guint32 opid, GError *error);
+void		e_data_cal_respond_get_view			(EDataCal *cal, guint32 opid, GError *error, const gchar *view_path);
+void		e_data_cal_respond_get_timezone			(EDataCal *cal, guint32 opid, GError *error, const gchar *tzobject);
+void		e_data_cal_respond_add_timezone			(EDataCal *cal, guint32 opid, GError *error);
+
+void		e_data_cal_report_error				(EDataCal *cal, const gchar *message);
+void		e_data_cal_report_readonly			(EDataCal *cal, gboolean is_readonly);
+void		e_data_cal_report_online			(EDataCal *cal, gboolean is_online);
+void		e_data_cal_report_auth_required			(EDataCal *cal, const ECredentials *credentials);
+void		e_data_cal_report_opened			(EDataCal *cal, const GError *error);
+void		e_data_cal_report_free_busy_data		(EDataCal *cal, const GSList *freebusy);
 
 G_END_DECLS
 
diff --git a/calendar/libegdbus/Makefile.am b/calendar/libegdbus/Makefile.am
index 82f2b1b..e29a27c 100644
--- a/calendar/libegdbus/Makefile.am
+++ b/calendar/libegdbus/Makefile.am
@@ -1,13 +1,3 @@
-GDBUS_XML_FILES =				\
-	../libedata-cal/e-data-cal-factory.xml	\
-	../libedata-cal/e-data-cal-view.xml	\
-	../libedata-cal/e-data-cal.xml
-
-gdbus-files: $(GDBUS_XML_FILES)
-	gdbus-codegen --namespace=EGdbus --strip-prefix=org.gnome.evolution.dataserver.calendar --output-prefix=e-gdbus $(GDBUS_XML_FILES)
-	rm e-gdbus-bindings.h
-	rm e-gdbus-bindings.stamp
-
 # The library
 noinst_LTLIBRARIES = libegdbus-cal.la
 
@@ -19,21 +9,16 @@ libegdbus_cal_la_CPPFLAGS =			\
 	$(E_DATA_SERVER_CFLAGS)
 
 libegdbus_cal_la_SOURCES =			\
-	e-gdbus-egdbuscal.h			\
-	e-gdbus-egdbuscal.c			\
-	e-gdbus-egdbuscalfactory.h		\
-	e-gdbus-egdbuscalfactory.c		\
-	e-gdbus-egdbuscalview.h			\
-	e-gdbus-egdbuscalview.c			\
-	e-gdbus-marshallers.h			\
-	e-gdbus-marshallers.c			\
-	e-gdbus-typemappers.h
+	e-gdbus-cal.h				\
+	e-gdbus-cal.c				\
+	e-gdbus-cal-factory.h			\
+	e-gdbus-cal-factory.c			\
+	e-gdbus-cal-view.h			\
+	e-gdbus-cal-view.c
 
 libegdbus_cal_la_LIBADD =			\
 	$(E_DATA_SERVER_LIBS)
 
 libegdbus_cal_la_LDFLAGS = $(NO_UNDEFINED)
 
-EXTRA_DIST = e-gdbus-marshallers.list
-
 -include $(top_srcdir)/git.mk
diff --git a/calendar/libegdbus/e-gdbus-cal-factory.c b/calendar/libegdbus/e-gdbus-cal-factory.c
new file mode 100644
index 0000000..e241828
--- /dev/null
+++ b/calendar/libegdbus/e-gdbus-cal-factory.c
@@ -0,0 +1,604 @@
+/*
+ * e-gdbus-cal-factory.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 2011 Red Hat, Inc. (www.redhat.com)
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <gio/gio.h>
+
+#include <libedataserver/e-data-server-util.h>
+#include <libedataserver/e-gdbus-marshallers.h>
+
+#include "e-gdbus-cal-factory.h"
+
+#define GDBUS_CAL_FACTORY_INTERFACE_NAME "org.gnome.evolution.dataserver.CalendarFactory"
+
+typedef EGdbusCalFactoryIface EGdbusCalFactoryInterface;
+G_DEFINE_INTERFACE (EGdbusCalFactory, e_gdbus_cal_factory, G_TYPE_OBJECT);
+
+enum
+{
+	_0_SIGNAL,
+	__GET_CAL_METHOD,
+	__LAST_SIGNAL
+};
+
+static guint signals[__LAST_SIGNAL] = {0};
+
+/* ------------------------------------------------------------------------- */
+
+/* Various lookup tables */
+
+static GHashTable *_method_name_to_id = NULL;
+static GHashTable *_method_name_to_type = NULL;
+
+static guint
+lookup_method_id_from_method_name (const gchar *method_name)
+{
+	return GPOINTER_TO_UINT (g_hash_table_lookup (_method_name_to_id, method_name));
+}
+
+static guint
+lookup_method_type_from_method_name (const gchar *method_name)
+{
+	return GPOINTER_TO_UINT (g_hash_table_lookup (_method_name_to_type, method_name));
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void
+e_gdbus_cal_factory_default_init (EGdbusCalFactoryIface *iface)
+{
+	/* Build lookup structures */
+	_method_name_to_id = g_hash_table_new (g_str_hash, g_str_equal);
+	_method_name_to_type = g_hash_table_new (g_str_hash, g_str_equal);
+
+	E_INIT_GDBUS_METHOD_STRV (EGdbusCalFactoryIface, "getCal", get_cal, __GET_CAL_METHOD)
+}
+
+/* encodes source and source type into a strv usable for a wire transfer;
+   Free returned pointer with g_strfreev() */
+gchar **
+e_gdbus_cal_factory_encode_get_cal (const gchar *in_source, guint in_type)
+{
+	gchar **strv;
+
+	g_return_val_if_fail (in_source != NULL, NULL);
+
+	strv = g_new0 (gchar *, 3);
+	strv[0] = g_strdup (in_source);
+	strv[1] = g_strdup_printf ("%u", (guint32) in_type);
+	strv[2] = NULL;
+
+	return strv;
+}
+
+/* decodes source and source type from a strv recevied from a wire transfer;
+   free out_source with g_free(); returns TRUE is successful. */
+gboolean
+e_gdbus_cal_factory_decode_get_cal (const gchar * const * in_strv, gchar **out_source, guint *out_type)
+{
+	g_return_val_if_fail (in_strv != NULL, FALSE);
+	g_return_val_if_fail (in_strv[0] != NULL, FALSE);
+	g_return_val_if_fail (in_strv[1] != NULL, FALSE);
+	g_return_val_if_fail (in_strv[2] == NULL, FALSE);
+	g_return_val_if_fail (out_source != NULL, FALSE);
+	g_return_val_if_fail (out_type != NULL, FALSE);
+
+	*out_source = g_strdup (in_strv[0]);
+	*out_type = atoi (in_strv[1]);
+
+	return TRUE;
+}
+
+/* C Bindings for properties */
+
+void
+e_gdbus_cal_factory_call_get_cal (GDBusProxy *proxy, const gchar * const *in_source_type, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	/* in_source_type has only two items, the first is ESource, the second is source type */
+	/* use e_gdbus_cal_factory_encode_get_cal() to encode them */
+
+	g_return_if_fail (in_source_type != NULL);
+	g_return_if_fail (in_source_type[0] != NULL);
+	g_return_if_fail (in_source_type[1] != NULL);
+	g_return_if_fail (in_source_type[2] == NULL);
+
+	e_gdbus_proxy_method_call_strv ("getCal", proxy, in_source_type, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_cal_factory_call_get_cal_finish (GDBusProxy *proxy, GAsyncResult *result, gchar **out_path, GError **error)
+{
+	return e_gdbus_proxy_method_call_finish_string (proxy, result, out_path, error);
+}
+
+gboolean
+e_gdbus_cal_factory_call_get_cal_sync (GDBusProxy *proxy, const gchar * const *in_source_type, gchar **out_path, GCancellable *cancellable, GError **error)
+{
+	/* in_source_type has only two items, the first is ESource, the second is source type */
+	/* use e_gdbus_cal_factory_encode_get_cal() to encode them */
+
+	g_return_val_if_fail (in_source_type != NULL, FALSE);
+	g_return_val_if_fail (in_source_type[0] != NULL, FALSE);
+	g_return_val_if_fail (in_source_type[1] != NULL, FALSE);
+	g_return_val_if_fail (in_source_type[2] == NULL, FALSE);
+
+	return e_gdbus_proxy_method_call_sync_strv__string ("getCal", proxy, in_source_type, out_path, cancellable, error);
+}
+
+void
+e_gdbus_cal_factory_complete_get_cal (EGdbusCalFactory *object, GDBusMethodInvocation *invocation, const gchar *out_path, const GError *error)
+{
+	e_gdbus_complete_sync_method_string (object, invocation, out_path, error);
+}
+
+E_DECLARE_GDBUS_SYNC_METHOD_1_WITH_RETURN (cal_factory, getCal, source_type, "as", path, "s")
+
+static const GDBusMethodInfo * const e_gdbus_cal_factory_method_info_pointers[] =
+{
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal_factory, getCal),
+	NULL
+};
+
+static const GDBusInterfaceInfo _e_gdbus_cal_factory_interface_info =
+{
+	-1,
+	(gchar *) GDBUS_CAL_FACTORY_INTERFACE_NAME,
+	(GDBusMethodInfo **) &e_gdbus_cal_factory_method_info_pointers,
+	(GDBusSignalInfo **) NULL,
+	(GDBusPropertyInfo **) NULL,
+};
+
+static void
+handle_method_call (GDBusConnection       *connection,
+                    const gchar           *sender,
+                    const gchar           *object_path,
+                    const gchar           *interface_name,
+                    const gchar           *method_name,
+                    GVariant              *parameters,
+                    GDBusMethodInvocation *invocation,
+                    gpointer               user_data)
+{
+	guint method_id, method_type;
+
+	method_id = lookup_method_id_from_method_name (method_name);
+	method_type = lookup_method_type_from_method_name (method_name);
+
+	g_return_if_fail (method_id != 0);
+	g_return_if_fail (method_type != 0);
+
+	e_gdbus_stub_handle_method_call (user_data, invocation, parameters, method_name, signals[method_id], method_type);
+}
+
+static GVariant *
+get_property (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *property_name, GError **error, gpointer user_data)
+{
+	g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "This implementation does not support property `%s'", property_name);
+	return NULL;
+}
+
+static gboolean
+set_property (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *property_name, GVariant *value, GError **error, gpointer user_data)
+{
+	g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "This implementation does not support property `%s'", property_name);
+	return FALSE;
+}
+
+static const GDBusInterfaceVTable e_gdbus_cal_factory_interface_vtable =
+{
+	handle_method_call,
+	get_property,
+	set_property
+};
+
+static gboolean
+emit_notifications_in_idle (gpointer user_data)
+{
+	GObject *object = G_OBJECT (user_data);
+	GDBusConnection *connection;
+	const gchar *path;
+	GHashTable *notification_queue;
+	GHashTableIter iter;
+	const gchar *property_name;
+	GVariant *value;
+	GVariantBuilder *builder;
+	GVariantBuilder *invalidated_builder;
+	GHashTable *pvc;
+	gboolean has_changes;
+
+	notification_queue = g_object_get_data (object, "gdbus-codegen-notification-queue");
+	path = g_object_get_data (object, "gdbus-codegen-path");
+	connection = g_object_get_data (object, "gdbus-codegen-connection");
+	pvc = g_object_get_data (object, "gdbus-codegen-pvc");
+	g_assert (notification_queue != NULL && path != NULL && connection != NULL && pvc != NULL);
+
+	builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
+	invalidated_builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
+	g_hash_table_iter_init (&iter, notification_queue);
+	has_changes = FALSE;
+	while (g_hash_table_iter_next (&iter, (gpointer) &property_name, (gpointer) &value)) {
+		GVariant *cached_value;
+		cached_value = g_hash_table_lookup (pvc, property_name);
+		if (cached_value == NULL || !g_variant_equal (cached_value, value)) {
+			g_hash_table_insert (pvc, (gpointer) property_name, (gpointer) g_variant_ref (value));
+			g_variant_builder_add (builder, "{sv}", property_name, value);
+			has_changes = TRUE;
+		}
+	}
+
+	if (has_changes) {
+		g_dbus_connection_emit_signal (connection,
+					NULL,
+					path,
+					"org.freedesktop.DBus.Properties",
+					"PropertiesChanged",
+					g_variant_new ("(sa{sv}as)",
+							GDBUS_CAL_FACTORY_INTERFACE_NAME,
+							builder,
+							invalidated_builder),
+					NULL);
+	} else {
+		g_variant_builder_unref (builder);
+		g_variant_builder_unref (invalidated_builder);
+	}
+
+	g_hash_table_remove_all (notification_queue);
+	g_object_set_data (object, "gdbus-codegen-notification-idle-id", GUINT_TO_POINTER (0));
+	return FALSE;
+}
+
+/**
+ * e_gdbus_cal_factory_drain_notify:
+ * @object: A #EGdbusCalFactory that is exported.
+ *
+ * If @object has queued notifications, empty the queue forcing
+ * the <literal>PropertiesChanged</literal> signal to be emitted.
+ * See <xref linkend="EGdbusCalFactory.description"/> for more background information.
+ */
+void
+e_gdbus_cal_factory_drain_notify (EGdbusCalFactory *object)
+{
+	gint idle_id;
+	idle_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (object), "gdbus-codegen-notification-idle-id"));
+	if (idle_id > 0) {
+		emit_notifications_in_idle (object);
+		g_source_remove (idle_id);
+	}
+}
+
+static void
+on_object_unregistered (GObject *object)
+{
+	gint idle_id;
+	idle_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (object), "gdbus-codegen-notification-idle-id"));
+	if (idle_id > 0) {
+		g_source_remove (idle_id);
+	}
+	g_object_set_data (G_OBJECT (object), "gdbus-codegen-path", NULL);
+	g_object_set_data (G_OBJECT (object), "gdbus-codegen-connection", NULL);
+}
+
+/**
+ * e_gdbus_cal_factory_register_object:
+ * @object: An instance of a #GObject<!-- -->-derived type implementing the #EGdbusCalFactory interface.
+ * @connection: A #GDBusConnection.
+ * @object_path: The object to register the object at.
+ * @error: Return location for error or %NULL.
+ *
+ * Registers @object at @object_path on @connection.
+ *
+ * See <xref linkend="EGdbusCalFactory.description"/>
+ * for how properties, methods and signals are handled.
+ *
+ * Returns: 0 if @error is set, otherwise a registration id (never 0) that can be used with g_dbus_connection_unregister_object().
+ */
+guint
+e_gdbus_cal_factory_register_object (EGdbusCalFactory *object, GDBusConnection *connection, const gchar *object_path, GError **error)
+{
+	GHashTable *pvc;
+
+	pvc = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) g_variant_unref);
+
+	g_object_set_data_full (G_OBJECT (object), "gdbus-codegen-path", (gpointer) g_strdup (object_path), g_free);
+	g_object_set_data (G_OBJECT (object), "gdbus-codegen-connection", (gpointer) connection);
+	g_object_set_data_full (G_OBJECT (object), "gdbus-codegen-pvc", (gpointer) pvc, (GDestroyNotify) g_hash_table_unref);
+	return g_dbus_connection_register_object (connection,
+		object_path,
+		(GDBusInterfaceInfo *) &_e_gdbus_cal_factory_interface_info,
+		&e_gdbus_cal_factory_interface_vtable,
+		object,
+		(GDestroyNotify) on_object_unregistered,
+		error);
+}
+
+/**
+ * e_gdbus_cal_factory_interface_info:
+ *
+ * Gets interface description for the <literal>org.gnome.evolution.dataserver.CalendarFactory</literal> D-Bus interface.
+ *
+ * Returns: A #GDBusInterfaceInfo. Do not free, the object is statically allocated.
+ */
+const GDBusInterfaceInfo *
+e_gdbus_cal_factory_interface_info (void)
+{
+	return &_e_gdbus_cal_factory_interface_info;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void proxy_iface_init (EGdbusCalFactoryIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (EGdbusCalFactoryProxy, e_gdbus_cal_factory_proxy, G_TYPE_DBUS_PROXY,
+                         G_IMPLEMENT_INTERFACE (E_TYPE_GDBUS_CAL_FACTORY, proxy_iface_init));
+
+static void
+e_gdbus_cal_factory_proxy_init (EGdbusCalFactoryProxy *proxy)
+{
+	g_dbus_proxy_set_interface_info (G_DBUS_PROXY (proxy), (GDBusInterfaceInfo *) &_e_gdbus_cal_factory_interface_info);
+}
+
+static void
+g_signal (GDBusProxy *proxy, const gchar *sender_name, const gchar *signal_name, GVariant *parameters)
+{
+	/*
+	guint signal_id, signal_type;
+
+	signal_id = lookup_signal_id_from_signal_name (signal_name);
+	signal_type = lookup_signal_type_from_signal_name (signal_name);
+
+	g_return_if_fail (signal_id != 0);
+	g_return_if_fail (signal_type != 0);
+
+	e_gdbus_proxy_emit_signal (proxy, parameters, signals[signal_id], signal_type);
+	*/
+}
+
+static void
+e_gdbus_cal_factory_proxy_class_init (EGdbusCalFactoryProxyClass *klass)
+{
+	GDBusProxyClass *proxy_class;
+
+	proxy_class = G_DBUS_PROXY_CLASS (klass);
+	proxy_class->g_signal = g_signal;
+}
+
+static void
+proxy_iface_init (EGdbusCalFactoryIface *iface)
+{
+}
+
+/**
+ * e_gdbus_cal_factory_proxy_new:
+ * @connection: A #GDBusConnection.
+ * @flags: Flags used when constructing the proxy.
+ * @name: A bus name (well-known or unique) or %NULL if @connection is not a message bus connection.
+ * @object_path: An object path.
+ * @cancellable: A #GCancellable or %NULL.
+ * @callback: Callback function to invoke when the proxy is ready.
+ * @user_data: User data to pass to @callback.
+ *
+ * Like g_dbus_proxy_new() but returns a #EGdbusCalFactoryProxy.
+ *
+ * This is a failable asynchronous constructor - when the proxy is ready, callback will be invoked and you can use e_gdbus_cal_factory_proxy_new_finish() to get the result.
+ */
+void
+e_gdbus_cal_factory_proxy_new (GDBusConnection *connection, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	g_async_initable_new_async (E_TYPE_GDBUS_CAL_FACTORY_PROXY,
+				G_PRIORITY_DEFAULT,
+				cancellable,
+				callback,
+				user_data,
+				"g-flags", flags,
+				"g-name", name,
+				"g-connection", connection,
+				"g-object-path", object_path,
+				"g-interface-name", GDBUS_CAL_FACTORY_INTERFACE_NAME,
+				NULL);
+}
+
+/**
+ * e_gdbus_cal_factory_proxy_new_finish:
+ * @result: A #GAsyncResult obtained from the #GAsyncReadyCallback function passed to e_gdbus_cal_factory_proxy_new().
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes creating a #EGdbusCalFactoryProxy.
+ *
+ * Returns: A #EGdbusCalFactoryProxy or %NULL if @error is set. Free with g_object_unref().
+ */
+EGdbusCalFactory *
+e_gdbus_cal_factory_proxy_new_finish (GAsyncResult *result, GError **error)
+{
+	GObject *object;
+	GObject *source_object;
+	source_object = g_async_result_get_source_object (result);
+	g_assert (source_object != NULL);
+	object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), result, error);
+	g_object_unref (source_object);
+	if (object != NULL)
+		return E_GDBUS_CAL_FACTORY (object);
+	else
+		return NULL;
+}
+
+/**
+ * e_gdbus_cal_factory_proxy_new_sync:
+ * @connection: A #GDBusConnection.
+ * @flags: Flags used when constructing the proxy.
+ * @name: A bus name (well-known or unique) or %NULL if @connection is not a message bus connection.
+ * @object_path: An object path.
+ * @cancellable: A #GCancellable or %NULL.
+ * @error: Return location for error or %NULL.
+ *
+ * Like g_dbus_proxy_new_sync() but returns a #EGdbusCalFactoryProxy.
+ *
+ * This is a synchronous failable constructor. See e_gdbus_cal_factory_proxy_new() and e_gdbus_cal_factory_proxy_new_finish() for the asynchronous version.
+ *
+ * Returns: A #EGdbusCalFactoryProxy or %NULL if error is set. Free with g_object_unref().
+ */
+EGdbusCalFactory *
+e_gdbus_cal_factory_proxy_new_sync (GDBusConnection *connection, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GError **error)
+{
+	GInitable *initable;
+	initable = g_initable_new (E_TYPE_GDBUS_CAL_FACTORY_PROXY,
+				cancellable,
+				error,
+				"g-flags", flags,
+				"g-name", name,
+				"g-connection", connection,
+				"g-object-path", object_path,
+				"g-interface-name", GDBUS_CAL_FACTORY_INTERFACE_NAME,
+				NULL);
+	if (initable != NULL)
+		return E_GDBUS_CAL_FACTORY (initable);
+	else
+		return NULL;
+}
+
+/**
+ * e_gdbus_cal_factory_proxy_new_for_bus:
+ * @bus_type: A #GBusType.
+ * @flags: Flags used when constructing the proxy.
+ * @name: A bus name (well-known or unique).
+ * @object_path: An object path.
+ * @cancellable: A #GCancellable or %NULL.
+ * @callback: Callback function to invoke when the proxy is ready.
+ * @user_data: User data to pass to @callback.
+ *
+ * Like g_dbus_proxy_new_for_bus() but returns a #EGdbusCalFactoryProxy.
+ *
+ * This is a failable asynchronous constructor - when the proxy is ready, callback will be invoked and you can use e_gdbus_cal_factory_proxy_new_for_bus_finish() to get the result.
+ */
+void
+e_gdbus_cal_factory_proxy_new_for_bus (GBusType bus_type, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	g_async_initable_new_async (E_TYPE_GDBUS_CAL_FACTORY_PROXY,
+				G_PRIORITY_DEFAULT,
+				cancellable,
+				callback,
+				user_data,
+				"g-flags", flags,
+				"g-name", name,
+				"g-bus-type", bus_type,
+				"g-object-path", object_path,
+				"g-interface-name", GDBUS_CAL_FACTORY_INTERFACE_NAME,
+				NULL);
+}
+
+/**
+ * e_gdbus_cal_factory_proxy_new_for_bus_finish:
+ * @result: A #GAsyncResult obtained from the #GAsyncReadyCallback function passed to e_gdbus_cal_factory_proxy_new_for_bus().
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes creating a #EGdbusCalFactoryProxy.
+ *
+ * Returns: A #EGdbusCalFactoryProxy or %NULL if @error is set. Free with g_object_unref().
+ */
+EGdbusCalFactory *
+e_gdbus_cal_factory_proxy_new_for_bus_finish (GAsyncResult *result, GError **error)
+{
+	GObject *object;
+	GObject *source_object;
+	source_object = g_async_result_get_source_object (result);
+	g_assert (source_object != NULL);
+	object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), result, error);
+	g_object_unref (source_object);
+	if (object != NULL)
+		return E_GDBUS_CAL_FACTORY (object);
+	else
+		return NULL;
+}
+
+/**
+ * e_gdbus_cal_factory_proxy_new_for_bus_sync:
+ * @bus_type: A #GBusType.
+ * @flags: Flags used when constructing the proxy.
+ * @name: A bus name (well-known or unique).
+ * @object_path: An object path.
+ * @cancellable: A #GCancellable or %NULL.
+ * @error: Return location for error or %NULL.
+ *
+ * Like g_dbus_proxy_new_for_bus_sync() but returns a #EGdbusCalFactoryProxy.
+ *
+ * This is a synchronous failable constructor. See e_gdbus_cal_factory_proxy_new_for_bus() and e_gdbus_cal_factory_proxy_new_for_bus_finish() for the asynchronous version.
+ *
+ * Returns: A #EGdbusCalFactoryProxy or %NULL if error is set. Free with g_object_unref().
+ */
+EGdbusCalFactory *
+e_gdbus_cal_factory_proxy_new_for_bus_sync (GBusType bus_type, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GError **error)
+{
+	GInitable *initable;
+	initable = g_initable_new (E_TYPE_GDBUS_CAL_FACTORY_PROXY,
+				cancellable,
+				error,
+				"g-flags", flags,
+				"g-name", name,
+				"g-bus-type", bus_type,
+				"g-object-path", object_path,
+				"g-interface-name", GDBUS_CAL_FACTORY_INTERFACE_NAME,
+				NULL);
+	if (initable != NULL)
+		return E_GDBUS_CAL_FACTORY (initable);
+	else
+		return NULL;
+}
+
+/* ---------------------------------------------------------------------- */
+
+struct _EGdbusCalFactoryStubPrivate
+{
+	gint foo;
+};
+
+static void stub_iface_init (EGdbusCalFactoryIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (EGdbusCalFactoryStub, e_gdbus_cal_factory_stub, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (E_TYPE_GDBUS_CAL_FACTORY, stub_iface_init));
+
+static void
+e_gdbus_cal_factory_stub_init (EGdbusCalFactoryStub *stub)
+{
+	stub->priv = G_TYPE_INSTANCE_GET_PRIVATE (stub, E_TYPE_GDBUS_CAL_FACTORY_STUB, EGdbusCalFactoryStubPrivate);
+}
+
+static void
+e_gdbus_cal_factory_stub_class_init (EGdbusCalFactoryStubClass *klass)
+{
+	g_type_class_add_private (klass, sizeof (EGdbusCalFactoryStubPrivate));
+}
+
+static void
+stub_iface_init (EGdbusCalFactoryIface *iface)
+{
+}
+
+/**
+ * e_gdbus_cal_factory_stub_new:
+ *
+ * Creates a new stub object that can be exported via e_gdbus_cal_factory_register_object().
+ *
+ * Returns: A #EGdbusCalFactoryStub instance. Free with g_object_unref().
+ */
+EGdbusCalFactory *
+e_gdbus_cal_factory_stub_new (void)
+{
+	return E_GDBUS_CAL_FACTORY (g_object_new (E_TYPE_GDBUS_CAL_FACTORY_STUB, NULL));
+}
diff --git a/calendar/libegdbus/e-gdbus-cal-factory.h b/calendar/libegdbus/e-gdbus-cal-factory.h
new file mode 100644
index 0000000..1977c35
--- /dev/null
+++ b/calendar/libegdbus/e-gdbus-cal-factory.h
@@ -0,0 +1,116 @@
+/*
+ * e-gdbus-cal-factory.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 2011 Red Hat, Inc. (www.redhat.com)
+ *
+ */
+
+#ifndef E_GDBUS_CAL_FACTORY_H
+#define E_GDBUS_CAL_FACTORY_H
+
+#include <gio/gio.h>
+
+#include <libedataserver/e-gdbus-templates.h>
+
+G_BEGIN_DECLS
+
+#define E_TYPE_GDBUS_CAL_FACTORY         (e_gdbus_cal_factory_get_type ())
+#define E_GDBUS_CAL_FACTORY(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_GDBUS_CAL_FACTORY, EGdbusCalFactory))
+#define E_IS_GDBUS_CAL_FACTORY(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_GDBUS_CAL_FACTORY))
+#define E_GDBUS_CAL_FACTORY_GET_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE((o), E_TYPE_GDBUS_CAL_FACTORY, EGdbusCalFactoryIface))
+
+typedef struct _EGdbusCalFactory EGdbusCalFactory; /* Dummy typedef */
+typedef struct _EGdbusCalFactoryIface EGdbusCalFactoryIface;
+
+GType e_gdbus_cal_factory_get_type (void) G_GNUC_CONST;
+
+/* ---------------------------------------------------------------------- */
+
+typedef struct _EGdbusCalFactoryProxy EGdbusCalFactoryProxy;
+typedef struct _EGdbusCalFactoryProxyClass EGdbusCalFactoryProxyClass;
+typedef struct _EGdbusCalFactoryProxyPrivate EGdbusCalFactoryProxyPrivate;
+
+struct _EGdbusCalFactoryProxy
+{
+	GDBusProxy parent_instance;
+	EGdbusCalFactoryProxyPrivate *priv;
+};
+
+struct _EGdbusCalFactoryProxyClass
+{
+	GDBusProxyClass parent_class;
+};
+
+#define E_TYPE_GDBUS_CAL_FACTORY_PROXY (e_gdbus_cal_factory_proxy_get_type ())
+GType e_gdbus_cal_factory_proxy_get_type (void) G_GNUC_CONST;
+
+void			e_gdbus_cal_factory_proxy_new		(GDBusConnection *connection, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+EGdbusCalFactory *	e_gdbus_cal_factory_proxy_new_finish	(GAsyncResult *result, GError **error);
+EGdbusCalFactory *	e_gdbus_cal_factory_proxy_new_sync	(GDBusConnection *connection, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GError **error);
+
+void			e_gdbus_cal_factory_proxy_new_for_bus	(GBusType bus_type, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+EGdbusCalFactory *	e_gdbus_cal_factory_proxy_new_for_bus_finish (GAsyncResult  *result, GError **error);
+EGdbusCalFactory *	e_gdbus_cal_factory_proxy_new_for_bus_sync (GBusType bus_type, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GError **error);
+
+/* ---------------------------------------------------------------------- */
+
+typedef struct _EGdbusCalFactoryStub EGdbusCalFactoryStub;
+typedef struct _EGdbusCalFactoryStubClass EGdbusCalFactoryStubClass;
+typedef struct _EGdbusCalFactoryStubPrivate EGdbusCalFactoryStubPrivate;
+
+struct _EGdbusCalFactoryStub
+{
+	GObject parent_instance;
+	EGdbusCalFactoryStubPrivate *priv;
+};
+
+struct _EGdbusCalFactoryStubClass
+{
+	GObjectClass parent_class;
+};
+
+#define E_TYPE_GDBUS_CAL_FACTORY_STUB (e_gdbus_cal_factory_stub_get_type ())
+GType e_gdbus_cal_factory_stub_get_type (void) G_GNUC_CONST;
+
+EGdbusCalFactory *e_gdbus_cal_factory_stub_new (void);
+
+guint e_gdbus_cal_factory_register_object (EGdbusCalFactory *object, GDBusConnection *connection, const gchar *object_path, GError **error);
+void e_gdbus_cal_factory_drain_notify (EGdbusCalFactory *object);
+const GDBusInterfaceInfo *e_gdbus_cal_factory_interface_info (void) G_GNUC_CONST;
+
+struct _EGdbusCalFactoryIface
+{
+	GTypeInterface parent_iface;
+
+	/* Signal handlers for handling D-Bus method calls: */
+	gboolean (*handle_get_cal) (EGdbusCalFactory *object, GDBusMethodInvocation *invocation, const gchar * const *in_source_type);
+};
+
+gchar **	e_gdbus_cal_factory_encode_get_cal (const gchar *in_source, guint in_type);
+gboolean	e_gdbus_cal_factory_decode_get_cal (const gchar * const * in_strv, gchar **out_source, guint *out_type);
+
+/* D-Bus Methods */
+void		e_gdbus_cal_factory_call_get_cal	(GDBusProxy *proxy, const gchar * const *in_source_type, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_cal_factory_call_get_cal_finish	(GDBusProxy *proxy, GAsyncResult *result, gchar **out_path, GError **error);
+gboolean	e_gdbus_cal_factory_call_get_cal_sync	(GDBusProxy *proxy, const gchar * const *in_source_type, gchar **out_path, GCancellable *cancellable, GError **error);
+
+/* D-Bus Methods Completion Helpers */
+void		e_gdbus_cal_factory_complete_get_cal	(EGdbusCalFactory *object, GDBusMethodInvocation *invocation, const gchar *out_path, const GError *error);
+
+G_END_DECLS
+
+#endif /* E_GDBUS_CAL_FACTORY_H */
diff --git a/calendar/libegdbus/e-gdbus-cal-view.c b/calendar/libegdbus/e-gdbus-cal-view.c
new file mode 100644
index 0000000..efb3e86
--- /dev/null
+++ b/calendar/libegdbus/e-gdbus-cal-view.c
@@ -0,0 +1,690 @@
+/*
+ * e-gdbus-cal-view.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 2011 Red Hat, Inc. (www.redhat.com)
+ *
+ */
+
+#include <stdio.h>
+#include <gio/gio.h>
+
+#include <libedataserver/e-data-server-util.h>
+#include <libedataserver/e-gdbus-marshallers.h>
+
+#include "e-gdbus-cal-view.h"
+
+#define GDBUS_CAL_VIEW_INTERFACE_NAME "org.gnome.evolution.dataserver.CalendarView"
+
+typedef EGdbusCalViewIface EGdbusCalViewInterface;
+G_DEFINE_INTERFACE (EGdbusCalView, e_gdbus_cal_view, G_TYPE_OBJECT);
+
+enum
+{
+	_0_SIGNAL,
+	__OBJECTS_ADDED_SIGNAL,
+	__OBJECTS_MODIFIED_SIGNAL,
+	__OBJECTS_REMOVED_SIGNAL,
+	__PROGRESS_SIGNAL,
+	__COMPLETE_SIGNAL,
+	__START_METHOD,
+	__STOP_METHOD,
+	__DISPOSE_METHOD,
+	__SET_FIELDS_OF_INTEREST_METHOD,
+	__LAST_SIGNAL
+};
+
+static guint signals[__LAST_SIGNAL] = {0};
+
+/* ------------------------------------------------------------------------- */
+
+/* Various lookup tables */
+
+static GHashTable *_method_name_to_id = NULL;
+static GHashTable *_method_name_to_type = NULL;
+static GHashTable *_signal_name_to_id = NULL;
+static GHashTable *_signal_name_to_type = NULL;
+
+static guint
+lookup_method_id_from_method_name (const gchar *method_name)
+{
+	return GPOINTER_TO_UINT (g_hash_table_lookup (_method_name_to_id, method_name));
+}
+
+static guint
+lookup_method_type_from_method_name (const gchar *method_name)
+{
+	return GPOINTER_TO_UINT (g_hash_table_lookup (_method_name_to_type, method_name));
+}
+
+static guint
+lookup_signal_id_from_signal_name (const gchar *signal_name)
+{
+	return GPOINTER_TO_UINT (g_hash_table_lookup (_signal_name_to_id, signal_name));
+}
+
+static guint
+lookup_signal_type_from_signal_name (const gchar *signal_name)
+{
+	return GPOINTER_TO_UINT (g_hash_table_lookup (_signal_name_to_type, signal_name));
+}
+
+/* ------------------------------------------------------------------------- */
+
+E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_STRV	 (GDBUS_CAL_VIEW_INTERFACE_NAME, objects_added)
+E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_STRV	 (GDBUS_CAL_VIEW_INTERFACE_NAME, objects_modified)
+E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_STRV	 (GDBUS_CAL_VIEW_INTERFACE_NAME, objects_removed)
+E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_UINT_STRING (GDBUS_CAL_VIEW_INTERFACE_NAME, progress)
+E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_STRV	 (GDBUS_CAL_VIEW_INTERFACE_NAME, complete)
+
+static void
+e_gdbus_cal_view_default_init (EGdbusCalViewIface *iface)
+{
+	/* Build lookup structures */
+	_method_name_to_id = g_hash_table_new (g_str_hash, g_str_equal);
+	_method_name_to_type = g_hash_table_new (g_str_hash, g_str_equal);
+	_signal_name_to_id = g_hash_table_new (g_str_hash, g_str_equal);
+	_signal_name_to_type = g_hash_table_new (g_str_hash, g_str_equal);
+
+	
+	/* GObject signals definitions for D-Bus signals: */
+	E_INIT_GDBUS_SIGNAL_STRV	(EGdbusCalViewIface, "ObjectsAdded",	objects_added, __OBJECTS_ADDED_SIGNAL)
+	E_INIT_GDBUS_SIGNAL_STRV	(EGdbusCalViewIface, "ObjectsModified",	objects_modified, __OBJECTS_MODIFIED_SIGNAL)
+	E_INIT_GDBUS_SIGNAL_STRV	(EGdbusCalViewIface, "ObjectsRemoved",	objects_removed, __OBJECTS_REMOVED_SIGNAL)
+	E_INIT_GDBUS_SIGNAL_UINT_STRING	(EGdbusCalViewIface, "Progress",	progress, __PROGRESS_SIGNAL)
+	E_INIT_GDBUS_SIGNAL_STRV	(EGdbusCalViewIface, "Complete",	complete, __COMPLETE_SIGNAL)
+
+	/* GObject signals definitions for D-Bus methods: */
+	E_INIT_GDBUS_METHOD_VOID	(EGdbusCalViewIface, "start",			start, __START_METHOD)
+	E_INIT_GDBUS_METHOD_VOID	(EGdbusCalViewIface, "stop",			stop, __STOP_METHOD)
+	E_INIT_GDBUS_METHOD_VOID	(EGdbusCalViewIface, "dispose",			dispose, __DISPOSE_METHOD)
+	E_INIT_GDBUS_METHOD_STRV	(EGdbusCalViewIface, "setFieldsOfInterest",	set_fields_of_interest, __SET_FIELDS_OF_INTEREST_METHOD)
+}
+
+void
+e_gdbus_cal_view_call_start (GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_method_call_void ("start", proxy, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_cal_view_call_start_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_method_call_finish_void (proxy, result, error);
+}
+
+gboolean
+e_gdbus_cal_view_call_start_sync (GDBusProxy *proxy, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_method_call_sync_void__void ("start", proxy, cancellable, error);
+}
+
+void
+e_gdbus_cal_view_call_stop (GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_method_call_void ("stop", proxy, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_cal_view_call_stop_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_method_call_finish_void (proxy, result, error);
+}
+
+gboolean
+e_gdbus_cal_view_call_stop_sync (GDBusProxy *proxy, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_method_call_sync_void__void ("stop", proxy, cancellable, error);
+}
+
+void
+e_gdbus_cal_view_call_dispose (GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_method_call_void ("dispose", proxy, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_cal_view_call_dispose_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_method_call_finish_void (proxy, result, error);
+}
+
+gboolean
+e_gdbus_cal_view_call_dispose_sync (GDBusProxy *proxy, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_method_call_sync_void__void ("dispose", proxy, cancellable, error);
+}
+
+void
+e_gdbus_cal_view_call_set_fields_of_interest (GDBusProxy *proxy, const gchar * const *in_only_fields, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_method_call_strv ("setFieldsOfInterest", proxy, in_only_fields, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_cal_view_call_set_fields_of_interest_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_method_call_finish_void (proxy, result, error);
+}
+
+gboolean
+e_gdbus_cal_view_call_set_fields_of_interest_sync (GDBusProxy *proxy, const gchar * const *in_only_fields, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_method_call_sync_strv__void ("setFieldsOfInterest", proxy, in_only_fields, cancellable, error);
+}
+
+void
+e_gdbus_cal_view_emit_objects_added (EGdbusCalView *object, const gchar * const *arg_objects)
+{
+	g_signal_emit (object, signals[__OBJECTS_ADDED_SIGNAL], 0, arg_objects);
+}
+
+void
+e_gdbus_cal_view_emit_objects_modified (EGdbusCalView *object, const gchar * const *arg_objects)
+{
+	g_signal_emit (object, signals[__OBJECTS_MODIFIED_SIGNAL], 0, arg_objects);
+}
+
+void
+e_gdbus_cal_view_emit_objects_removed (EGdbusCalView *object, const gchar * const *arg_uids)
+{
+	g_signal_emit (object, signals[__OBJECTS_REMOVED_SIGNAL], 0, arg_uids);
+}
+
+void
+e_gdbus_cal_view_emit_progress (EGdbusCalView *object, guint arg_percent, const gchar *arg_message)
+{
+	g_signal_emit (object, signals[__PROGRESS_SIGNAL], 0, arg_percent, arg_message);
+}
+
+void
+e_gdbus_cal_view_emit_complete (EGdbusCalView *object, const gchar * const *arg_error)
+{
+	g_signal_emit (object, signals[__COMPLETE_SIGNAL], 0, arg_error);
+}
+
+E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (cal_view, ObjectsAdded, objects, "as")
+E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (cal_view, ObjectsModified, objects, "as")
+E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (cal_view, ObjectsRemoved, uids, "as")
+E_DECLARE_GDBUS_NOTIFY_SIGNAL_2 (cal_view, Progress, percent, "u", message, "s")
+E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (cal_view, Complete, error, "as")
+
+E_DECLARE_GDBUS_SYNC_METHOD_0	(cal_view, start)
+E_DECLARE_GDBUS_SYNC_METHOD_0	(cal_view, stop)
+E_DECLARE_GDBUS_SYNC_METHOD_0	(cal_view, dispose)
+E_DECLARE_GDBUS_SYNC_METHOD_1	(cal_view, setFieldsOfInterest, fields_of_interest, "as")
+
+static const GDBusMethodInfo * const e_gdbus_cal_view_method_info_pointers[] =
+{
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal_view, start),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal_view, stop),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal_view, dispose),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal_view, setFieldsOfInterest),
+	NULL
+};
+
+static const GDBusSignalInfo * const e_gdbus_cal_view_signal_info_pointers[] =
+{
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal_view, ObjectsAdded),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal_view, ObjectsModified),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal_view, ObjectsRemoved),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal_view, Progress),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal_view, Complete),
+	NULL
+};
+
+static const GDBusInterfaceInfo _e_gdbus_cal_view_interface_info =
+{
+	-1,
+	(gchar *) GDBUS_CAL_VIEW_INTERFACE_NAME,
+	(GDBusMethodInfo **) &e_gdbus_cal_view_method_info_pointers,
+	(GDBusSignalInfo **) &e_gdbus_cal_view_signal_info_pointers,
+	(GDBusPropertyInfo **) NULL
+};
+
+static void
+handle_method_call (GDBusConnection       *connection,
+                    const gchar           *sender,
+                    const gchar           *object_path,
+                    const gchar           *interface_name,
+                    const gchar           *method_name,
+                    GVariant              *parameters,
+                    GDBusMethodInvocation *invocation,
+                    gpointer               user_data)
+{
+	guint method_id, method_type;
+
+	method_id = lookup_method_id_from_method_name (method_name);
+	method_type = lookup_method_type_from_method_name (method_name);
+
+	g_return_if_fail (method_id != 0);
+	g_return_if_fail (method_type != 0);
+
+	e_gdbus_stub_handle_method_call (user_data, invocation, parameters, method_name, signals[method_id], method_type);
+}
+
+static GVariant *
+get_property (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *property_name, GError **error, gpointer user_data)
+{
+	g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "This implementation does not support property `%s'", property_name);
+	return NULL;
+}
+
+static gboolean
+set_property (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *property_name, GVariant *value, GError **error, gpointer user_data)
+{
+	g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "This implementation does not support property `%s'", property_name);
+	return FALSE;
+}
+
+static const GDBusInterfaceVTable e_gdbus_cal_view_interface_vtable =
+{
+  handle_method_call,
+  get_property,
+  set_property
+};
+
+static gboolean
+emit_notifications_in_idle (gpointer user_data)
+{
+	GObject *object = G_OBJECT (user_data);
+	GDBusConnection *connection;
+	const gchar *path;
+	GHashTable *notification_queue;
+	GHashTableIter iter;
+	const gchar *property_name;
+	GVariant *value;
+	GVariantBuilder *builder;
+	GVariantBuilder *invalidated_builder;
+	GHashTable *pvc;
+	gboolean has_changes;
+
+	notification_queue = g_object_get_data (object, "gdbus-codegen-notification-queue");
+	path = g_object_get_data (object, "gdbus-codegen-path");
+	connection = g_object_get_data (object, "gdbus-codegen-connection");
+	pvc = g_object_get_data (object, "gdbus-codegen-pvc");
+	g_assert (notification_queue != NULL && path != NULL && connection != NULL && pvc != NULL);
+
+	builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
+	invalidated_builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
+	g_hash_table_iter_init (&iter, notification_queue);
+	has_changes = FALSE;
+	while (g_hash_table_iter_next (&iter, (gpointer) &property_name, (gpointer) &value)) {
+		GVariant *cached_value;
+		cached_value = g_hash_table_lookup (pvc, property_name);
+		if (cached_value == NULL || !g_variant_equal (cached_value, value)) {
+			g_hash_table_insert (pvc, (gpointer) property_name, (gpointer) g_variant_ref (value));
+			g_variant_builder_add (builder, "{sv}", property_name, value);
+			has_changes = TRUE;
+		}
+    }
+
+	if (has_changes) {
+		g_dbus_connection_emit_signal (connection,
+					NULL,
+					path,
+					"org.freedesktop.DBus.Properties",
+					"PropertiesChanged",
+					g_variant_new ("(sa{sv}as)",
+							GDBUS_CAL_VIEW_INTERFACE_NAME,
+							builder,
+							invalidated_builder),
+					NULL);
+	} else {
+		g_variant_builder_unref (builder);
+		g_variant_builder_unref (invalidated_builder);
+	}
+
+	g_hash_table_remove_all (notification_queue);
+	g_object_set_data (object, "gdbus-codegen-notification-idle-id", GUINT_TO_POINTER (0));
+	return FALSE;
+}
+
+/**
+ * e_gdbus_cal_view_drain_notify:
+ * @object: A #EGdbusCalView that is exported.
+ *
+ * If @object has queued notifications, empty the queue forcing
+ * the <literal>PropertiesChanged</literal> signal to be emitted.
+ * See <xref linkend="EGdbusCalView.description"/> for more background information.
+ */
+void
+e_gdbus_cal_view_drain_notify (EGdbusCalView *object)
+{
+	gint idle_id;
+	idle_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (object), "gdbus-codegen-notification-idle-id"));
+	if (idle_id > 0) {
+		emit_notifications_in_idle (object);
+		g_source_remove (idle_id);
+	}
+}
+
+static void
+on_object_unregistered (GObject *object)
+{
+	gint idle_id;
+	idle_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (object), "gdbus-codegen-notification-idle-id"));
+	if (idle_id > 0) {
+		g_source_remove (idle_id);
+	}
+	g_object_set_data (G_OBJECT (object), "gdbus-codegen-path", NULL);
+	g_object_set_data (G_OBJECT (object), "gdbus-codegen-connection", NULL);
+}
+
+/**
+ * e_gdbus_cal_view_register_object:
+ * @object: An instance of a #GObject<!-- -->-derived type implementing the #EGdbusCalView interface.
+ * @connection: A #GDBusConnection.
+ * @object_path: The object to register the object at.
+ * @error: Return location for error or %NULL.
+ *
+ * Registers @object at @object_path on @connection.
+ *
+ * See <xref linkend="EGdbusCalView.description"/>
+ * for how properties, methods and signals are handled.
+ *
+ * Returns: 0 if @error is set, otherwise a registration id (never 0) that can be used with g_dbus_connection_unregister_object().
+ */
+guint
+e_gdbus_cal_view_register_object (EGdbusCalView *object, GDBusConnection *connection, const gchar *object_path, GError **error)
+{
+	GHashTable *pvc;
+
+	pvc = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) g_variant_unref);
+
+	g_object_set_data_full (G_OBJECT (object), "gdbus-codegen-path", (gpointer) g_strdup (object_path), g_free);
+	g_object_set_data (G_OBJECT (object), "gdbus-codegen-connection", (gpointer) connection);
+	g_object_set_data_full (G_OBJECT (object), "gdbus-codegen-pvc", (gpointer) pvc, (GDestroyNotify) g_hash_table_unref);
+	return g_dbus_connection_register_object (connection,
+		object_path,
+		(GDBusInterfaceInfo *) &_e_gdbus_cal_view_interface_info,
+		&e_gdbus_cal_view_interface_vtable,
+		object,
+		(GDestroyNotify) on_object_unregistered,
+		error);
+}
+
+/**
+ * e_gdbus_cal_view_interface_info:
+ *
+ * Gets interface description for the <literal>org.gnome.evolution.dataserver.CalendarView</literal> D-Bus interface.
+ *
+ * Returns: A #GDBusInterfaceInfo. Do not free, the object is statically allocated.
+ */
+const GDBusInterfaceInfo *
+e_gdbus_cal_view_interface_info (void)
+{
+	return &_e_gdbus_cal_view_interface_info;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void proxy_iface_init (EGdbusCalViewIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (EGdbusCalViewProxy, e_gdbus_cal_view_proxy, G_TYPE_DBUS_PROXY,
+                         G_IMPLEMENT_INTERFACE (E_TYPE_GDBUS_CAL_VIEW, proxy_iface_init));
+
+static void
+e_gdbus_cal_view_proxy_init (EGdbusCalViewProxy *proxy)
+{
+	g_dbus_proxy_set_interface_info (G_DBUS_PROXY (proxy), (GDBusInterfaceInfo *) &_e_gdbus_cal_view_interface_info);
+}
+
+static void
+g_signal (GDBusProxy *proxy, const gchar *sender_name, const gchar *signal_name, GVariant *parameters)
+{
+	guint signal_id, signal_type;
+
+	signal_id = lookup_signal_id_from_signal_name (signal_name);
+	signal_type = lookup_signal_type_from_signal_name (signal_name);
+
+	g_return_if_fail (signal_id != 0);
+	g_return_if_fail (signal_type != 0);
+
+	e_gdbus_proxy_emit_signal (proxy, parameters, signals[signal_id], signal_type);
+}
+
+static void
+e_gdbus_cal_view_proxy_class_init (EGdbusCalViewProxyClass *klass)
+{
+	GDBusProxyClass *proxy_class;
+
+	proxy_class = G_DBUS_PROXY_CLASS (klass);
+	proxy_class->g_signal = g_signal;
+}
+
+static void
+proxy_iface_init (EGdbusCalViewIface *iface)
+{
+}
+
+/**
+ * e_gdbus_cal_view_proxy_new:
+ * @connection: A #GDBusConnection.
+ * @flags: Flags used when constructing the proxy.
+ * @name: A bus name (well-known or unique) or %NULL if @connection is not a message bus connection.
+ * @object_path: An object path.
+ * @cancellable: A #GCancellable or %NULL.
+ * @callback: Callback function to invoke when the proxy is ready.
+ * @user_data: User data to pass to @callback.
+ *
+ * Like g_dbus_proxy_new() but returns a #EGdbusCalViewProxy.
+ *
+ * This is a failable asynchronous constructor - when the proxy is ready, callback will be invoked and you can use e_gdbus_cal_view_proxy_new_finish() to get the result.
+ */
+void
+e_gdbus_cal_view_proxy_new (GDBusConnection *connection, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	g_async_initable_new_async (E_TYPE_GDBUS_CAL_VIEW_PROXY,
+				G_PRIORITY_DEFAULT,
+				cancellable,
+				callback,
+				user_data,
+				"g-flags", flags,
+				"g-name", name,
+				"g-connection", connection,
+				"g-object-path", object_path,
+				"g-interface-name", GDBUS_CAL_VIEW_INTERFACE_NAME,
+				NULL);
+}
+
+/**
+ * e_gdbus_cal_view_proxy_new_finish:
+ * @result: A #GAsyncResult obtained from the #GAsyncReadyCallback function passed to e_gdbus_cal_view_proxy_new().
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes creating a #EGdbusCalViewProxy.
+ *
+ * Returns: A #EGdbusCalViewProxy or %NULL if @error is set. Free with g_object_unref().
+ */
+EGdbusCalView *
+e_gdbus_cal_view_proxy_new_finish (GAsyncResult *result, GError **error)
+{
+	GObject *object;
+	GObject *source_object;
+	source_object = g_async_result_get_source_object (result);
+	g_assert (source_object != NULL);
+	object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), result, error);
+	g_object_unref (source_object);
+	if (object != NULL)
+		return E_GDBUS_CAL_VIEW (object);
+	else
+		return NULL;
+}
+
+/**
+ * e_gdbus_cal_view_proxy_new_sync:
+ * @connection: A #GDBusConnection.
+ * @flags: Flags used when constructing the proxy.
+ * @name: A bus name (well-known or unique) or %NULL if @connection is not a message bus connection.
+ * @object_path: An object path.
+ * @cancellable: A #GCancellable or %NULL.
+ * @error: Return location for error or %NULL.
+ *
+ * Like g_dbus_proxy_new_sync() but returns a #EGdbusCalViewProxy.
+ *
+ * This is a synchronous failable constructor. See e_gdbus_cal_view_proxy_new() and e_gdbus_cal_view_proxy_new_finish() for the asynchronous version.
+ *
+ * Returns: A #EGdbusCalViewProxy or %NULL if error is set. Free with g_object_unref().
+ */
+EGdbusCalView *
+e_gdbus_cal_view_proxy_new_sync (GDBusConnection *connection, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GError **error)
+{
+	GInitable *initable;
+	initable = g_initable_new (E_TYPE_GDBUS_CAL_VIEW_PROXY,
+				cancellable,
+				error,
+				"g-flags", flags,
+				"g-name", name,
+				"g-connection", connection,
+				"g-object-path", object_path,
+				"g-interface-name", GDBUS_CAL_VIEW_INTERFACE_NAME,
+				NULL);
+	if (initable != NULL)
+		return E_GDBUS_CAL_VIEW (initable);
+	else
+		return NULL;
+}
+
+/**
+ * e_gdbus_cal_view_proxy_new_for_bus:
+ * @bus_type: A #GBusType.
+ * @flags: Flags used when constructing the proxy.
+ * @name: A bus name (well-known or unique).
+ * @object_path: An object path.
+ * @cancellable: A #GCancellable or %NULL.
+ * @callback: Callback function to invoke when the proxy is ready.
+ * @user_data: User data to pass to @callback.
+ *
+ * Like g_dbus_proxy_new_for_bus() but returns a #EGdbusCalViewProxy.
+ *
+ * This is a failable asynchronous constructor - when the proxy is ready, callback will be invoked and you can use e_gdbus_cal_view_proxy_new_for_bus_finish() to get the result.
+ */
+void
+e_gdbus_cal_view_proxy_new_for_bus (GBusType bus_type, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	g_async_initable_new_async (E_TYPE_GDBUS_CAL_VIEW_PROXY,
+				G_PRIORITY_DEFAULT,
+				cancellable,
+				callback,
+				user_data,
+				"g-flags", flags,
+				"g-name", name,
+				"g-bus-type", bus_type,
+				"g-object-path", object_path,
+				"g-interface-name", GDBUS_CAL_VIEW_INTERFACE_NAME,
+				NULL);
+}
+
+/**
+ * e_gdbus_cal_view_proxy_new_for_bus_finish:
+ * @result: A #GAsyncResult obtained from the #GAsyncReadyCallback function passed to e_gdbus_cal_view_proxy_new_for_bus().
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes creating a #EGdbusCalViewProxy.
+ *
+ * Returns: A #EGdbusCalViewProxy or %NULL if @error is set. Free with g_object_unref().
+ */
+EGdbusCalView *
+e_gdbus_cal_view_proxy_new_for_bus_finish (GAsyncResult  *result, GError **error)
+{
+	GObject *object;
+	GObject *source_object;
+	source_object = g_async_result_get_source_object (result);
+	g_assert (source_object != NULL);
+	object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), result, error);
+	g_object_unref (source_object);
+	if (object != NULL)
+		return E_GDBUS_CAL_VIEW (object);
+	else
+		return NULL;
+}
+
+/**
+ * e_gdbus_cal_view_proxy_new_for_bus_sync:
+ * @bus_type: A #GBusType.
+ * @flags: Flags used when constructing the proxy.
+ * @name: A bus name (well-known or unique).
+ * @object_path: An object path.
+ * @cancellable: A #GCancellable or %NULL.
+ * @error: Return location for error or %NULL.
+ *
+ * Like g_dbus_proxy_new_for_bus_sync() but returns a #EGdbusCalViewProxy.
+ *
+ * This is a synchronous failable constructor. See e_gdbus_cal_view_proxy_new_for_bus() and e_gdbus_cal_view_proxy_new_for_bus_finish() for the asynchronous version.
+ *
+ * Returns: A #EGdbusCalViewProxy or %NULL if error is set. Free with g_object_unref().
+ */
+EGdbusCalView *
+e_gdbus_cal_view_proxy_new_for_bus_sync (GBusType bus_type, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GError **error)
+{
+	GInitable *initable;
+	initable = g_initable_new (E_TYPE_GDBUS_CAL_VIEW_PROXY,
+				cancellable,
+				error,
+				"g-flags", flags,
+				"g-name", name,
+				"g-bus-type", bus_type,
+				"g-object-path", object_path,
+				"g-interface-name", GDBUS_CAL_VIEW_INTERFACE_NAME,
+				NULL);
+	if (initable != NULL)
+		return E_GDBUS_CAL_VIEW (initable);
+	else
+		return NULL;
+}
+
+/* ---------------------------------------------------------------------- */
+
+struct _EGdbusCalViewStubPrivate
+{
+	gint foo;
+};
+
+static void stub_iface_init (EGdbusCalViewIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (EGdbusCalViewStub, e_gdbus_cal_view_stub, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (E_TYPE_GDBUS_CAL_VIEW, stub_iface_init));
+
+static void
+e_gdbus_cal_view_stub_init (EGdbusCalViewStub *stub)
+{
+	stub->priv = G_TYPE_INSTANCE_GET_PRIVATE (stub, E_TYPE_GDBUS_CAL_VIEW_STUB, EGdbusCalViewStubPrivate);
+}
+
+static void
+e_gdbus_cal_view_stub_class_init (EGdbusCalViewStubClass *klass)
+{
+	g_type_class_add_private (klass, sizeof (EGdbusCalViewStubPrivate));
+}
+
+static void
+stub_iface_init (EGdbusCalViewIface *iface)
+{
+}
+
+/**
+ * e_gdbus_cal_view_stub_new:
+ *
+ * Creates a new stub object that can be exported via e_gdbus_cal_view_register_object().
+ *
+ * Returns: A #EGdbusCalViewStub instance. Free with g_object_unref().
+ */
+EGdbusCalView *
+e_gdbus_cal_view_stub_new (void)
+{
+	return E_GDBUS_CAL_VIEW (g_object_new (E_TYPE_GDBUS_CAL_VIEW_STUB, NULL));
+}
diff --git a/calendar/libegdbus/e-gdbus-cal-view.h b/calendar/libegdbus/e-gdbus-cal-view.h
new file mode 100644
index 0000000..c2a5345
--- /dev/null
+++ b/calendar/libegdbus/e-gdbus-cal-view.h
@@ -0,0 +1,147 @@
+/*
+ * e-gdbus-cal-view.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 2011 Red Hat, Inc. (www.redhat.com)
+ *
+ */
+
+#ifndef E_GDBUS_CAL_VIEW_H
+#define E_GDBUS_CAL_VIEW_H
+
+#include <gio/gio.h>
+
+#include <libedataserver/e-gdbus-templates.h>
+
+G_BEGIN_DECLS
+
+#define E_TYPE_GDBUS_CAL_VIEW         (e_gdbus_cal_view_get_type ())
+#define E_GDBUS_CAL_VIEW(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_GDBUS_CAL_VIEW, EGdbusCalView))
+#define E_IS_GDBUS_CAL_VIEW(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_GDBUS_CAL_VIEW))
+#define E_GDBUS_CAL_VIEW_GET_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE((o), E_TYPE_GDBUS_CAL_VIEW, EGdbusCalViewIface))
+
+typedef struct _EGdbusCalView EGdbusCalView; /* Dummy typedef */
+typedef struct _EGdbusCalViewIface EGdbusCalViewIface;
+
+GType e_gdbus_cal_view_get_type (void) G_GNUC_CONST;
+
+/* ---------------------------------------------------------------------- */
+
+typedef struct _EGdbusCalViewProxy EGdbusCalViewProxy;
+typedef struct _EGdbusCalViewProxyClass EGdbusCalViewProxyClass;
+typedef struct _EGdbusCalViewProxyPrivate EGdbusCalViewProxyPrivate;
+
+struct _EGdbusCalViewProxy
+{
+	GDBusProxy parent_instance;
+	EGdbusCalViewProxyPrivate *priv;
+};
+
+struct _EGdbusCalViewProxyClass
+{
+	GDBusProxyClass parent_class;
+};
+
+#define E_TYPE_GDBUS_CAL_VIEW_PROXY (e_gdbus_cal_view_proxy_get_type ())
+GType e_gdbus_cal_view_proxy_get_type (void) G_GNUC_CONST;
+
+void		e_gdbus_cal_view_proxy_new (GDBusConnection *connection, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+EGdbusCalView *	e_gdbus_cal_view_proxy_new_finish (GAsyncResult *result, GError **error);
+EGdbusCalView *	e_gdbus_cal_view_proxy_new_sync (GDBusConnection *connection, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_cal_view_proxy_new_for_bus (GBusType bus_type, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+EGdbusCalView *	e_gdbus_cal_view_proxy_new_for_bus_finish (GAsyncResult *result, GError **error);
+EGdbusCalView *	e_gdbus_cal_view_proxy_new_for_bus_sync (GBusType bus_type, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GError **error);
+
+/* ---------------------------------------------------------------------- */
+
+typedef struct _EGdbusCalViewStub EGdbusCalViewStub;
+typedef struct _EGdbusCalViewStubClass EGdbusCalViewStubClass;
+typedef struct _EGdbusCalViewStubPrivate EGdbusCalViewStubPrivate;
+
+struct _EGdbusCalViewStub
+{
+	GObject parent_instance;
+	EGdbusCalViewStubPrivate *priv;
+};
+
+struct _EGdbusCalViewStubClass
+{
+	GObjectClass parent_class;
+};
+
+#define E_TYPE_GDBUS_CAL_VIEW_STUB (e_gdbus_cal_view_stub_get_type ())
+GType e_gdbus_cal_view_stub_get_type (void) G_GNUC_CONST;
+
+EGdbusCalView *e_gdbus_cal_view_stub_new (void);
+guint e_gdbus_cal_view_register_object (EGdbusCalView *object, GDBusConnection *connection, const gchar *object_path, GError **error);
+void e_gdbus_cal_view_drain_notify (EGdbusCalView *object);
+
+const GDBusInterfaceInfo *e_gdbus_cal_view_interface_info (void) G_GNUC_CONST;
+
+struct _EGdbusCalViewIface
+{
+	GTypeInterface parent_iface;
+
+	/* Signal handlers for receiving D-Bus signals: */
+	void	(*objects_added)	(EGdbusCalView *object, const gchar * const *arg_objects);
+	void	(*objects_modified)	(EGdbusCalView *object, const gchar * const *arg_objects);
+	void	(*objects_removed)	(EGdbusCalView *object, const gchar * const *arg_uids);
+
+	void	(*progress)		(EGdbusCalView *object, guint arg_percent, const gchar *arg_message);
+	void	(*complete)		(EGdbusCalView *object, guint arg_status, const gchar *arg_message);
+
+	/* Signal handlers for handling D-Bus method calls: */
+	gboolean (*handle_start)		(EGdbusCalView *object, GDBusMethodInvocation *invocation);
+	gboolean (*handle_stop)			(EGdbusCalView *object, GDBusMethodInvocation *invocation);
+	gboolean (*handle_dispose)		(EGdbusCalView *object, GDBusMethodInvocation *invocation);
+	gboolean (*handle_set_fields_of_interest)(EGdbusCalView *object, GDBusMethodInvocation *invocation, const gchar * const *in_only_fields);
+};
+
+/* D-Bus Methods */
+void		e_gdbus_cal_view_call_start		(GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_cal_view_call_start_finish	(GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_cal_view_call_start_sync	(GDBusProxy *proxy, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_cal_view_call_stop		(GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_cal_view_call_stop_finish	(GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_cal_view_call_stop_sync		(GDBusProxy *proxy, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_cal_view_call_dispose		(GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_cal_view_call_dispose_finish	(GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_cal_view_call_dispose_sync	(GDBusProxy *proxy, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_cal_view_call_set_fields_of_interest		(GDBusProxy *proxy, const gchar * const *in_only_fileds, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_cal_view_call_set_fields_of_interest_finish	(GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_cal_view_call_set_fields_of_interest_sync	(GDBusProxy *proxy, const gchar * const *in_only_fileds, GCancellable *cancellable, GError **error);
+
+/* D-Bus Methods Completion Helpers */
+#define e_gdbus_cal_view_complete_start				e_gdbus_complete_sync_method_void
+#define e_gdbus_cal_view_complete_stop				e_gdbus_complete_sync_method_void
+#define e_gdbus_cal_view_complete_dispose			e_gdbus_complete_sync_method_void
+#define e_gdbus_cal_view_complete_set_fields_of_interest	e_gdbus_complete_sync_method_void
+
+/* D-Bus Signal Emission Helpers */
+void e_gdbus_cal_view_emit_objects_added	(EGdbusCalView *object, const gchar * const *arg_objects);
+void e_gdbus_cal_view_emit_objects_modified	(EGdbusCalView *object, const gchar * const *arg_objects);
+void e_gdbus_cal_view_emit_objects_removed	(EGdbusCalView *object, const gchar * const *arg_uids);
+
+void e_gdbus_cal_view_emit_progress		(EGdbusCalView *object, guint arg_percent, const gchar *arg_message);
+void e_gdbus_cal_view_emit_complete		(EGdbusCalView *object, const gchar * const *arg_error);
+
+G_END_DECLS
+
+#endif /* E_GDBUS_CAL_VIEW_H */
diff --git a/calendar/libegdbus/e-gdbus-cal.c b/calendar/libegdbus/e-gdbus-cal.c
new file mode 100644
index 0000000..3604be0
--- /dev/null
+++ b/calendar/libegdbus/e-gdbus-cal.c
@@ -0,0 +1,1584 @@
+/*
+ * e-gdbus-cal.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 2011 Red Hat, Inc. (www.redhat.com)
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <gio/gio.h>
+
+#include <libedataserver/e-data-server-util.h>
+#include <libedataserver/e-gdbus-marshallers.h>
+
+#include "e-gdbus-cal.h"
+
+#define GDBUS_CAL_INTERFACE_NAME "org.gnome.evolution.dataserver.Calendar"
+
+typedef EGdbusCalIface EGdbusCalInterface;
+G_DEFINE_INTERFACE (EGdbusCal, e_gdbus_cal, G_TYPE_OBJECT);
+
+enum
+{
+	_0_SIGNAL,
+	__BACKEND_ERROR_SIGNAL,
+	__READONLY_SIGNAL,
+	__ONLINE_SIGNAL,
+	__AUTH_REQUIRED_SIGNAL,
+	__OPENED_SIGNAL,
+	__FREE_BUSY_DATA_SIGNAL,
+	__OPEN_METHOD,
+	__OPEN_DONE_SIGNAL,
+	__REMOVE_METHOD,
+	__REMOVE_DONE_SIGNAL,
+	__REFRESH_METHOD,
+	__REFRESH_DONE_SIGNAL,
+	__GET_BACKEND_PROPERTY_METHOD,
+	__GET_BACKEND_PROPERTY_DONE_SIGNAL,
+	__SET_BACKEND_PROPERTY_METHOD,
+	__SET_BACKEND_PROPERTY_DONE_SIGNAL,
+	__GET_OBJECT_METHOD,
+	__GET_OBJECT_DONE_SIGNAL,
+	__GET_OBJECT_LIST_METHOD,
+	__GET_OBJECT_LIST_DONE_SIGNAL,
+	__GET_FREE_BUSY_METHOD,
+	__GET_FREE_BUSY_DONE_SIGNAL,
+	__CREATE_OBJECT_METHOD,
+	__CREATE_OBJECT_DONE_SIGNAL,
+	__MODIFY_OBJECT_METHOD,
+	__MODIFY_OBJECT_DONE_SIGNAL,
+	__REMOVE_OBJECT_METHOD,
+	__REMOVE_OBJECT_DONE_SIGNAL,
+	__RECEIVE_OBJECTS_METHOD,
+	__RECEIVE_OBJECTS_DONE_SIGNAL,
+	__SEND_OBJECTS_METHOD,
+	__SEND_OBJECTS_DONE_SIGNAL,
+	__GET_ATTACHMENT_URIS_METHOD,
+	__GET_ATTACHMENT_URIS_DONE_SIGNAL,
+	__DISCARD_ALARM_METHOD,
+	__DISCARD_ALARM_DONE_SIGNAL,
+	__GET_VIEW_METHOD,
+	__GET_VIEW_DONE_SIGNAL,
+	__GET_TIMEZONE_METHOD,
+	__GET_TIMEZONE_DONE_SIGNAL,
+	__ADD_TIMEZONE_METHOD,
+	__ADD_TIMEZONE_DONE_SIGNAL,
+	__AUTHENTICATE_USER_METHOD,
+	__CANCEL_OPERATION_METHOD,
+	__CANCEL_ALL_METHOD,
+	__CLOSE_METHOD,
+	__LAST_SIGNAL
+};
+
+static guint signals[__LAST_SIGNAL] = {0};
+
+struct _EGdbusCalProxyPrivate
+{
+	GHashTable *pending_ops;
+};
+
+/* ------------------------------------------------------------------------- */
+
+/* Various lookup tables */
+
+static GHashTable *_method_name_to_id = NULL;
+static GHashTable *_method_name_to_type = NULL;
+static GHashTable *_signal_name_to_id = NULL;
+static GHashTable *_signal_name_to_type = NULL;
+
+static guint
+lookup_method_id_from_method_name (const gchar *method_name)
+{
+	return GPOINTER_TO_UINT (g_hash_table_lookup (_method_name_to_id, method_name));
+}
+
+static guint
+lookup_method_type_from_method_name (const gchar *method_name)
+{
+	return GPOINTER_TO_UINT (g_hash_table_lookup (_method_name_to_type, method_name));
+}
+
+static guint
+lookup_signal_id_from_signal_name (const gchar *signal_name)
+{
+	return GPOINTER_TO_UINT (g_hash_table_lookup (_signal_name_to_id, signal_name));
+}
+
+static guint
+lookup_signal_type_from_signal_name (const gchar *signal_name)
+{
+	return GPOINTER_TO_UINT (g_hash_table_lookup (_signal_name_to_type, signal_name));
+}
+
+/* ------------------------------------------------------------------------- */
+
+E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_STRING  (GDBUS_CAL_INTERFACE_NAME, backend_error)
+E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_BOOLEAN (GDBUS_CAL_INTERFACE_NAME, readonly)
+E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_BOOLEAN (GDBUS_CAL_INTERFACE_NAME, online)
+E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_STRV    (GDBUS_CAL_INTERFACE_NAME, auth_required)
+E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_STRV    (GDBUS_CAL_INTERFACE_NAME, opened)
+E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_STRV    (GDBUS_CAL_INTERFACE_NAME, free_busy_data)
+
+E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_VOID	(GDBUS_CAL_INTERFACE_NAME, open)
+E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_VOID	(GDBUS_CAL_INTERFACE_NAME, remove)
+E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_VOID	(GDBUS_CAL_INTERFACE_NAME, refresh)
+E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_STRING	(GDBUS_CAL_INTERFACE_NAME, get_backend_property)
+E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_VOID	(GDBUS_CAL_INTERFACE_NAME, set_backend_property)
+E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_STRING	(GDBUS_CAL_INTERFACE_NAME, get_object)
+E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_STRV	(GDBUS_CAL_INTERFACE_NAME, get_object_list)
+E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_VOID	(GDBUS_CAL_INTERFACE_NAME, get_free_busy)
+E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_STRING	(GDBUS_CAL_INTERFACE_NAME, create_object)
+E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_VOID	(GDBUS_CAL_INTERFACE_NAME, modify_object)
+E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_VOID	(GDBUS_CAL_INTERFACE_NAME, remove_object)
+E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_VOID	(GDBUS_CAL_INTERFACE_NAME, receive_objects)
+E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_STRV	(GDBUS_CAL_INTERFACE_NAME, send_objects)
+E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_STRV	(GDBUS_CAL_INTERFACE_NAME, get_attachment_uris)
+E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_VOID	(GDBUS_CAL_INTERFACE_NAME, discard_alarm)
+E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_STRING	(GDBUS_CAL_INTERFACE_NAME, get_view)
+E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_STRING	(GDBUS_CAL_INTERFACE_NAME, get_timezone)
+E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_VOID	(GDBUS_CAL_INTERFACE_NAME, add_timezone)
+
+static void
+e_gdbus_cal_default_init (EGdbusCalIface *iface)
+{
+	/* Build lookup structures */
+	_method_name_to_id = g_hash_table_new (g_str_hash, g_str_equal);
+	_method_name_to_type = g_hash_table_new (g_str_hash, g_str_equal);
+	_signal_name_to_id = g_hash_table_new (g_str_hash, g_str_equal);
+	_signal_name_to_type = g_hash_table_new (g_str_hash, g_str_equal);
+
+	/* GObject signals definitions for D-Bus signals: */
+	E_INIT_GDBUS_SIGNAL_STRING		(EGdbusCalIface, "backend_error",	backend_error,	__BACKEND_ERROR_SIGNAL)
+	E_INIT_GDBUS_SIGNAL_BOOLEAN		(EGdbusCalIface, "readonly",		readonly,	__READONLY_SIGNAL)
+	E_INIT_GDBUS_SIGNAL_BOOLEAN		(EGdbusCalIface, "online",		online,		__ONLINE_SIGNAL)
+	E_INIT_GDBUS_SIGNAL_STRV   		(EGdbusCalIface, "auth_required", 	auth_required,	__AUTH_REQUIRED_SIGNAL)
+	E_INIT_GDBUS_SIGNAL_STRV   		(EGdbusCalIface, "opened", 		opened,		__OPENED_SIGNAL)
+	E_INIT_GDBUS_SIGNAL_STRV   		(EGdbusCalIface, "free_busy_data", 	free_busy_data,	__FREE_BUSY_DATA_SIGNAL)
+
+	/* GObject signals definitions for D-Bus methods: */
+	E_INIT_GDBUS_METHOD_ASYNC_BOOLEAN__VOID	(EGdbusCalIface, "open",			open, __OPEN_METHOD, __OPEN_DONE_SIGNAL)
+	E_INIT_GDBUS_METHOD_ASYNC_VOID__VOID	(EGdbusCalIface, "remove",			remove, __REMOVE_METHOD, __REMOVE_DONE_SIGNAL)
+	E_INIT_GDBUS_METHOD_ASYNC_VOID__VOID	(EGdbusCalIface, "refresh",			refresh, __REFRESH_METHOD, __REFRESH_DONE_SIGNAL)
+	E_INIT_GDBUS_METHOD_ASYNC_STRING__STRING(EGdbusCalIface, "getBackendProperty",		get_backend_property, __GET_BACKEND_PROPERTY_METHOD, __GET_BACKEND_PROPERTY_DONE_SIGNAL)
+	E_INIT_GDBUS_METHOD_ASYNC_STRV__VOID	(EGdbusCalIface, "setBackendProperty",		set_backend_property, __SET_BACKEND_PROPERTY_METHOD, __SET_BACKEND_PROPERTY_DONE_SIGNAL)
+	E_INIT_GDBUS_METHOD_ASYNC_STRV__STRING	(EGdbusCalIface, "getObject",			get_object, __GET_OBJECT_METHOD, __GET_OBJECT_DONE_SIGNAL)
+	E_INIT_GDBUS_METHOD_ASYNC_STRING__STRV	(EGdbusCalIface, "getObjectList",		get_object_list, __GET_OBJECT_LIST_METHOD, __GET_OBJECT_LIST_DONE_SIGNAL)
+	E_INIT_GDBUS_METHOD_ASYNC_STRV__VOID	(EGdbusCalIface, "getFreeBusy",			get_free_busy, __GET_FREE_BUSY_METHOD, __GET_FREE_BUSY_DONE_SIGNAL)
+	E_INIT_GDBUS_METHOD_ASYNC_STRING__STRING(EGdbusCalIface, "createObject",		create_object, __CREATE_OBJECT_METHOD, __CREATE_OBJECT_DONE_SIGNAL)
+	E_INIT_GDBUS_METHOD_ASYNC_STRV__VOID	(EGdbusCalIface, "modifyObject",		modify_object, __MODIFY_OBJECT_METHOD, __MODIFY_OBJECT_DONE_SIGNAL)
+	E_INIT_GDBUS_METHOD_ASYNC_STRV__VOID	(EGdbusCalIface, "removeObject",		remove_object, __REMOVE_OBJECT_METHOD, __REMOVE_OBJECT_DONE_SIGNAL)
+	E_INIT_GDBUS_METHOD_ASYNC_STRING__VOID	(EGdbusCalIface, "receiveObjects",		receive_objects, __RECEIVE_OBJECTS_METHOD, __RECEIVE_OBJECTS_DONE_SIGNAL)
+	E_INIT_GDBUS_METHOD_ASYNC_STRING__STRV	(EGdbusCalIface, "sendObjects",			send_objects, __SEND_OBJECTS_METHOD, __SEND_OBJECTS_DONE_SIGNAL)
+	E_INIT_GDBUS_METHOD_ASYNC_STRV__STRV	(EGdbusCalIface, "getAttachmentUris",		get_attachment_uris, __GET_ATTACHMENT_URIS_METHOD, __GET_ATTACHMENT_URIS_DONE_SIGNAL)
+	E_INIT_GDBUS_METHOD_ASYNC_STRV__VOID	(EGdbusCalIface, "discardAlarm",		discard_alarm, __DISCARD_ALARM_METHOD, __DISCARD_ALARM_DONE_SIGNAL)
+	E_INIT_GDBUS_METHOD_ASYNC_STRING__STRING(EGdbusCalIface, "getView",			get_view, __GET_VIEW_METHOD, __GET_VIEW_DONE_SIGNAL)
+	E_INIT_GDBUS_METHOD_ASYNC_STRING__STRING(EGdbusCalIface, "getTimezone",			get_timezone, __GET_TIMEZONE_METHOD, __GET_TIMEZONE_DONE_SIGNAL)
+	E_INIT_GDBUS_METHOD_ASYNC_STRING__VOID	(EGdbusCalIface, "addTimezone",			add_timezone, __ADD_TIMEZONE_METHOD, __ADD_TIMEZONE_DONE_SIGNAL)
+	E_INIT_GDBUS_METHOD_STRV		(EGdbusCalIface, "authenticateUser",		authenticate_user, __AUTHENTICATE_USER_METHOD)
+	E_INIT_GDBUS_METHOD_UINT		(EGdbusCalIface, "cancelOperation",		cancel_operation, __CANCEL_OPERATION_METHOD)
+	E_INIT_GDBUS_METHOD_VOID		(EGdbusCalIface, "cancelAll",			cancel_all, __CANCEL_ALL_METHOD)
+	E_INIT_GDBUS_METHOD_VOID		(EGdbusCalIface, "close",			close, __CLOSE_METHOD)
+}
+
+static gchar **
+encode_string_string (const gchar *str1, const gchar *str2)
+{
+	gchar **strv;
+
+	strv = g_new0 (gchar *, 3);
+	strv[0] = e_util_utf8_make_valid (str1 ? str1 : "");
+	strv[1] = e_util_utf8_make_valid (str2 ? str2 : "");
+	strv[2] = NULL;
+
+	return strv;
+}
+
+static gboolean
+decode_string_string (const gchar * const *in_strv, gchar **out_str1, gchar **out_str2)
+{
+	g_return_val_if_fail (in_strv != NULL, FALSE);
+	g_return_val_if_fail (in_strv[0] != NULL, FALSE);
+	g_return_val_if_fail (in_strv[1] != NULL, FALSE);
+	g_return_val_if_fail (in_strv[2] == NULL, FALSE);
+	g_return_val_if_fail (out_str1 != NULL, FALSE);
+	g_return_val_if_fail (out_str2 != NULL, FALSE);
+
+	*out_str1 = g_strdup (in_strv[0]);
+	*out_str2 = g_strdup (in_strv[1]);
+
+	return TRUE;
+}
+
+void
+e_gdbus_cal_call_open (GDBusProxy *proxy, gboolean in_only_if_exists, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_call_boolean ("open", e_gdbus_cal_call_open, E_GDBUS_ASYNC_OP_KEEPER (proxy), in_only_if_exists, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_cal_call_open_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_finish_call_void (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, error, e_gdbus_cal_call_open);
+}
+
+gboolean
+e_gdbus_cal_call_open_sync (GDBusProxy *proxy, gboolean in_only_if_exists, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_call_sync_boolean__void (proxy, in_only_if_exists, cancellable, error,
+		e_gdbus_cal_call_open,
+		e_gdbus_cal_call_open_finish);
+}
+
+void
+e_gdbus_cal_call_remove (GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_call_void ("remove", e_gdbus_cal_call_remove, E_GDBUS_ASYNC_OP_KEEPER (proxy), cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_cal_call_remove_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_finish_call_void (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, error, e_gdbus_cal_call_remove);
+}
+
+gboolean
+e_gdbus_cal_call_remove_sync (GDBusProxy *proxy, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_call_sync_void__void (proxy, cancellable, error,
+		e_gdbus_cal_call_remove,
+		e_gdbus_cal_call_remove_finish);
+}
+
+void
+e_gdbus_cal_call_refresh (GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_call_void ("refresh", e_gdbus_cal_call_refresh, E_GDBUS_ASYNC_OP_KEEPER (proxy), cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_cal_call_refresh_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_finish_call_void (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, error, e_gdbus_cal_call_refresh);
+}
+
+gboolean
+e_gdbus_cal_call_refresh_sync (GDBusProxy *proxy, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_call_sync_void__void (proxy, cancellable, error,
+		e_gdbus_cal_call_refresh,
+		e_gdbus_cal_call_refresh_finish);
+}
+
+void
+e_gdbus_cal_call_get_backend_property (GDBusProxy *proxy, const gchar *in_prop_name, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_call_string ("getBackendProperty", e_gdbus_cal_call_get_backend_property, E_GDBUS_ASYNC_OP_KEEPER (proxy), in_prop_name, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_cal_call_get_backend_property_finish (GDBusProxy *proxy, GAsyncResult *result, gchar **out_prop_value, GError **error)
+{
+	return e_gdbus_proxy_finish_call_string (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, out_prop_value, error, e_gdbus_cal_call_get_backend_property);
+}
+
+gboolean
+e_gdbus_cal_call_get_backend_property_sync (GDBusProxy *proxy, const gchar *in_prop_name, gchar **out_prop_value, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_call_sync_string__string (proxy, in_prop_name, out_prop_value, cancellable, error,
+		e_gdbus_cal_call_get_backend_property,
+		e_gdbus_cal_call_get_backend_property_finish);
+}
+
+/* free returned pointer with g_strfreev() */
+gchar **
+e_gdbus_cal_encode_set_backend_property (const gchar *in_prop_name, const gchar *in_prop_value)
+{
+	return encode_string_string (in_prop_name, in_prop_value);
+}
+
+/* free out_prop_name and out_prop_value with g_free() */
+gboolean
+e_gdbus_cal_decode_set_backend_property (const gchar * const *in_strv, gchar **out_prop_name, gchar **out_prop_value)
+{
+	return decode_string_string (in_strv, out_prop_name, out_prop_value);
+}
+
+void
+e_gdbus_cal_call_set_backend_property (GDBusProxy *proxy, const gchar * const *in_prop_name_value, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_call_strv ("setBackendProperty", e_gdbus_cal_call_set_backend_property, E_GDBUS_ASYNC_OP_KEEPER (proxy), in_prop_name_value, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_cal_call_set_backend_property_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_finish_call_void (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, error, e_gdbus_cal_call_set_backend_property);
+}
+
+gboolean
+e_gdbus_cal_call_set_backend_property_sync (GDBusProxy *proxy, const gchar * const *in_prop_name_value, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_call_sync_strv__void (proxy, in_prop_name_value, cancellable, error,
+		e_gdbus_cal_call_set_backend_property,
+		e_gdbus_cal_call_set_backend_property_finish);
+}
+
+/* free returned pointer with g_strfreev() */
+gchar **
+e_gdbus_cal_encode_get_object (const gchar *in_uid, const gchar *in_rid)
+{
+	return encode_string_string (in_uid, in_rid);
+}
+
+/* free out_uid and out_rid with g_free() */
+gboolean
+e_gdbus_cal_decode_get_object (const gchar * const *in_strv, gchar **out_uid, gchar **out_rid)
+{
+	return decode_string_string (in_strv, out_uid, out_rid);
+}
+
+void
+e_gdbus_cal_call_get_object (GDBusProxy *proxy, const gchar * const *in_uid_rid, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_call_strv ("getObject", e_gdbus_cal_call_get_object, E_GDBUS_ASYNC_OP_KEEPER (proxy), in_uid_rid, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_cal_call_get_object_finish (GDBusProxy *proxy, GAsyncResult *result, gchar **out_object, GError **error)
+{
+	return e_gdbus_proxy_finish_call_string (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, out_object, error, e_gdbus_cal_call_get_object);
+}
+
+gboolean
+e_gdbus_cal_call_get_object_sync (GDBusProxy *proxy, const gchar * const *in_uid_rid, gchar **out_object, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_call_sync_strv__string (proxy, in_uid_rid, out_object, cancellable, error,
+		e_gdbus_cal_call_get_object,
+		e_gdbus_cal_call_get_object_finish);
+}
+
+void
+e_gdbus_cal_call_get_object_list (GDBusProxy *proxy, const gchar *in_sexp, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_call_string ("getObjectList", e_gdbus_cal_call_get_object_list, E_GDBUS_ASYNC_OP_KEEPER (proxy), in_sexp, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_cal_call_get_object_list_finish (GDBusProxy *proxy, GAsyncResult *result, gchar ***out_objects, GError **error)
+{
+	return e_gdbus_proxy_finish_call_strv (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, out_objects, error, e_gdbus_cal_call_get_object_list);
+}
+
+gboolean
+e_gdbus_cal_call_get_object_list_sync (GDBusProxy *proxy, const gchar *in_sexp, gchar ***out_objects, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_call_sync_string__strv (proxy, in_sexp, out_objects, cancellable, error,
+		e_gdbus_cal_call_get_object_list,
+		e_gdbus_cal_call_get_object_list_finish);
+}
+
+/* free returned pointer with g_strfreev() */
+gchar **
+e_gdbus_cal_encode_get_free_busy (guint in_start, guint in_end, const GSList *in_users)
+{
+	gchar **strv;
+	gint ii;
+
+	g_return_val_if_fail (in_users != NULL, NULL);
+
+	strv = g_new0 (gchar *, g_slist_length ((GSList *) in_users) + 3);
+	strv[0] = g_strdup_printf ("%u", in_start);
+	strv[1] = g_strdup_printf ("%u", in_end);
+
+	for (ii = 0; in_users; ii++, in_users = in_users->next) {
+		strv[ii + 2] = e_util_utf8_make_valid (in_users->data);
+	}
+
+	strv[ii + 2] = NULL;
+
+	return strv;
+}
+
+/* free out_users with g_slist_foreach (out_users, (GFunc) g_free, NULL), g_slist_free (out_users); */
+gboolean
+e_gdbus_cal_decode_get_free_busy (const gchar * const *in_strv, guint *out_start, guint *out_end, GSList **out_users)
+{
+	gint ii;
+
+	g_return_val_if_fail (in_strv != NULL, FALSE);
+	g_return_val_if_fail (in_strv[0] != NULL, FALSE);
+	g_return_val_if_fail (in_strv[1] != NULL, FALSE);
+	g_return_val_if_fail (out_start != NULL, FALSE);
+	g_return_val_if_fail (out_end != NULL, FALSE);
+	g_return_val_if_fail (out_users != NULL, FALSE);
+
+	*out_users = NULL;
+
+	for (ii = 0; in_strv[ii + 2]; ii++) {
+		*out_users = g_slist_prepend (*out_users, g_strdup (in_strv[ii + 2]));
+	}
+
+	*out_start = atoi (in_strv[0]);
+	*out_end = atoi (in_strv[1]);
+	*out_users = g_slist_reverse (*out_users);
+
+	return TRUE;
+}
+
+void
+e_gdbus_cal_call_get_free_busy (GDBusProxy *proxy, const gchar * const *in_start_end_userlist, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_call_strv ("getFreeBusy", e_gdbus_cal_call_get_free_busy, E_GDBUS_ASYNC_OP_KEEPER (proxy), in_start_end_userlist, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_cal_call_get_free_busy_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_finish_call_void (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, error, e_gdbus_cal_call_get_free_busy);
+}
+
+gboolean
+e_gdbus_cal_call_get_free_busy_sync (GDBusProxy *proxy, const gchar * const *in_start_end_userlist, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_call_sync_strv__void (proxy, in_start_end_userlist, cancellable, error,
+		e_gdbus_cal_call_get_free_busy,
+		e_gdbus_cal_call_get_free_busy_finish);
+}
+
+void
+e_gdbus_cal_call_create_object (GDBusProxy *proxy, const gchar *in_calobj, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_call_string ("createObject", e_gdbus_cal_call_create_object, E_GDBUS_ASYNC_OP_KEEPER (proxy), in_calobj, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_cal_call_create_object_finish (GDBusProxy *proxy, GAsyncResult *result, gchar **out_uid, GError **error)
+{
+	return e_gdbus_proxy_finish_call_string (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, out_uid, error, e_gdbus_cal_call_create_object);
+}
+
+gboolean
+e_gdbus_cal_call_create_object_sync (GDBusProxy *proxy, const gchar *in_calobj, gchar **out_uid, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_call_sync_string__string (proxy, in_calobj, out_uid, cancellable, error,
+		e_gdbus_cal_call_create_object,
+		e_gdbus_cal_call_create_object_finish);
+}
+
+/* free returned pointer with g_strfreev() */
+gchar **
+e_gdbus_cal_encode_modify_object (const gchar *in_calobj, guint in_mod)
+{
+	gchar **strv;
+
+	g_return_val_if_fail (in_calobj != NULL, NULL);
+
+	strv = g_new0 (gchar *, 3);
+	strv[0] = e_util_utf8_make_valid (in_calobj);
+	strv[1] = g_strdup_printf ("%u", (guint32) in_mod);
+	strv[2] = NULL;
+
+	return strv;
+}
+
+/* free out_calobj with g_free() */
+gboolean
+e_gdbus_cal_decode_modify_object (const gchar * const *in_strv, gchar **out_calobj, guint *out_mod)
+{
+	g_return_val_if_fail (in_strv != NULL, FALSE);
+	g_return_val_if_fail (in_strv[0] != NULL, FALSE);
+	g_return_val_if_fail (in_strv[1] != NULL, FALSE);
+	g_return_val_if_fail (in_strv[2] == NULL, FALSE);
+	g_return_val_if_fail (out_calobj != NULL, FALSE);
+	g_return_val_if_fail (out_mod != NULL, FALSE);
+
+	*out_calobj = g_strdup (in_strv[0]);
+	*out_mod = atoi (in_strv[1]);
+
+	return TRUE;
+}
+
+void
+e_gdbus_cal_call_modify_object (GDBusProxy *proxy, const gchar * const *in_calobj_mod, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_call_strv ("modifyObject", e_gdbus_cal_call_modify_object, E_GDBUS_ASYNC_OP_KEEPER (proxy), in_calobj_mod, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_cal_call_modify_object_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_finish_call_void (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, error, e_gdbus_cal_call_modify_object);
+}
+
+gboolean
+e_gdbus_cal_call_modify_object_sync (GDBusProxy *proxy, const gchar * const *in_calobj_mod, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_call_sync_strv__void (proxy, in_calobj_mod, cancellable, error,
+		e_gdbus_cal_call_modify_object,
+		e_gdbus_cal_call_modify_object_finish);
+}
+
+/* free returned pointer with g_strfreev() */
+gchar **
+e_gdbus_cal_encode_remove_object (const gchar *in_uid, const gchar *in_rid, guint in_mod)
+{
+	gchar **strv;
+
+	g_return_val_if_fail (in_uid != NULL, NULL);
+
+	strv = g_new0 (gchar *, 4);
+	strv[0] = e_util_utf8_make_valid (in_uid);
+	strv[1] = e_util_utf8_make_valid (in_rid ? in_rid : "");
+	strv[2] = g_strdup_printf ("%u", (guint32) in_mod);
+	strv[3] = NULL;
+
+	return strv;
+}
+
+/* free out_uid and out_rid with g_free() */
+gboolean
+e_gdbus_cal_decode_remove_object (const gchar * const *in_strv, gchar **out_uid, gchar **out_rid, guint *out_mod)
+{
+	g_return_val_if_fail (in_strv != NULL, FALSE);
+	g_return_val_if_fail (in_strv[0] != NULL, FALSE);
+	g_return_val_if_fail (in_strv[1] != NULL, FALSE);
+	g_return_val_if_fail (in_strv[2] != NULL, FALSE);
+	g_return_val_if_fail (in_strv[3] == NULL, FALSE);
+	g_return_val_if_fail (out_uid != NULL, FALSE);
+	g_return_val_if_fail (out_rid != NULL, FALSE);
+	g_return_val_if_fail (out_mod != NULL, FALSE);
+
+	*out_uid = g_strdup (in_strv[0]);
+	*out_rid = g_strdup (in_strv[1]);
+	*out_mod = atoi (in_strv[2]);
+
+	return TRUE;
+}
+
+void
+e_gdbus_cal_call_remove_object (GDBusProxy *proxy, const gchar * const *in_uid_rid_mod, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_call_strv ("removeObject", e_gdbus_cal_call_remove_object, E_GDBUS_ASYNC_OP_KEEPER (proxy), in_uid_rid_mod, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_cal_call_remove_object_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_finish_call_void (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, error, e_gdbus_cal_call_remove_object);
+}
+
+gboolean
+e_gdbus_cal_call_remove_object_sync (GDBusProxy *proxy, const gchar * const *in_uid_rid_mod, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_call_sync_strv__void (proxy, in_uid_rid_mod, cancellable, error,
+		e_gdbus_cal_call_remove_object,
+		e_gdbus_cal_call_remove_object_finish);
+}
+
+void
+e_gdbus_cal_call_receive_objects (GDBusProxy *proxy, const gchar *in_calobj, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_call_string ("receiveObjects", e_gdbus_cal_call_receive_objects, E_GDBUS_ASYNC_OP_KEEPER (proxy), in_calobj, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_cal_call_receive_objects_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_finish_call_void (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, error, e_gdbus_cal_call_receive_objects);
+}
+
+gboolean
+e_gdbus_cal_call_receive_objects_sync (GDBusProxy *proxy, const gchar *in_calobj, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_call_sync_string__void (proxy, in_calobj, cancellable, error,
+		e_gdbus_cal_call_receive_objects,
+		e_gdbus_cal_call_receive_objects_finish);
+}
+
+/* free returned pointer with g_strfreev() */
+gchar **
+e_gdbus_cal_encode_send_objects (const gchar *in_calobj, const GSList *in_users)
+{
+	gint ii;
+	gchar **strv;
+
+	g_return_val_if_fail (in_calobj != NULL, NULL);
+
+	strv = g_new0 (gchar *, g_slist_length ((GSList *) in_users) + 2);
+	strv[0] = e_util_utf8_make_valid (in_calobj);
+	for (ii = 0; in_users; ii++, in_users = in_users->next) {
+		strv[ii + 1] = e_util_utf8_make_valid (in_users->data);
+	}
+	strv[ii + 1] = NULL;
+
+	return strv;
+}
+
+/* free out_calobj with g_free() and out_users with g_strfreev() */
+gboolean
+e_gdbus_cal_decode_send_objects (const gchar * const *in_strv, gchar **out_calobj, GSList **out_users)
+{
+	gint ii;
+
+	g_return_val_if_fail (in_strv != NULL, FALSE);
+	g_return_val_if_fail (in_strv[0] != NULL, FALSE);
+	g_return_val_if_fail (out_calobj != NULL, FALSE);
+	g_return_val_if_fail (out_users != NULL, FALSE);
+
+	*out_users = NULL;
+
+	for (ii = 0; in_strv[ii + 1]; ii++) {
+		*out_users = g_slist_prepend (*out_users, g_strdup (in_strv[ii + 1]));
+	}
+
+	*out_calobj = g_strdup (in_strv[0]);
+	*out_users = g_slist_reverse (*out_users);
+
+	return TRUE;
+}
+
+void
+e_gdbus_cal_call_send_objects (GDBusProxy *proxy, const gchar *in_calobj, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_call_string ("sendObjects", e_gdbus_cal_call_send_objects, E_GDBUS_ASYNC_OP_KEEPER (proxy), in_calobj, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_cal_call_send_objects_finish (GDBusProxy *proxy, GAsyncResult *result, gchar ***out_calobj_users, GError **error)
+{
+	return e_gdbus_proxy_finish_call_strv (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, out_calobj_users, error, e_gdbus_cal_call_send_objects);
+}
+
+gboolean
+e_gdbus_cal_call_send_objects_sync (GDBusProxy *proxy, const gchar *in_calobj, gchar ***out_calobj_users, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_call_sync_string__strv (proxy, in_calobj, out_calobj_users, cancellable, error,
+		e_gdbus_cal_call_send_objects,
+		e_gdbus_cal_call_send_objects_finish);
+}
+
+/* free returned pointer with g_strfreev() */
+gchar **
+e_gdbus_cal_encode_get_attachment_uris (const gchar *in_uid, const gchar *in_rid)
+{
+	return encode_string_string (in_uid, in_rid);
+}
+
+/* free out_uid and out_rid with g_free() */
+gboolean
+e_gdbus_cal_decode_get_attachment_uris (const gchar * const *in_strv, gchar **out_uid, gchar **out_rid)
+{
+	return decode_string_string (in_strv, out_uid, out_rid);
+}
+
+void
+e_gdbus_cal_call_get_attachment_uris (GDBusProxy *proxy, const gchar * const *in_uid_rid, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_call_strv ("getAttachmentUris", e_gdbus_cal_call_get_attachment_uris, E_GDBUS_ASYNC_OP_KEEPER (proxy), in_uid_rid, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_cal_call_get_attachment_uris_finish (GDBusProxy *proxy, GAsyncResult *result, gchar ***out_attachments, GError **error)
+{
+	return e_gdbus_proxy_finish_call_strv (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, out_attachments, error, e_gdbus_cal_call_get_attachment_uris);
+}
+
+gboolean
+e_gdbus_cal_call_get_attachment_uris_sync (GDBusProxy *proxy, const gchar * const *in_uid_rid, gchar ***out_attachments, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_call_sync_strv__strv (proxy, in_uid_rid, out_attachments, cancellable, error,
+		e_gdbus_cal_call_get_attachment_uris,
+		e_gdbus_cal_call_get_attachment_uris_finish);
+}
+
+/* free returned pointer with g_strfreev() */
+gchar **
+e_gdbus_cal_encode_discard_alarm (const gchar *in_uid, const gchar *in_rid, const gchar *in_auid)
+{
+	gchar **strv;
+
+	strv = g_new0 (gchar *, 4);
+	strv[0] = e_util_utf8_make_valid (in_uid ? in_uid : "");
+	strv[1] = e_util_utf8_make_valid (in_rid ? in_rid : "");
+	strv[2] = e_util_utf8_make_valid (in_auid ? in_auid : "");
+	strv[3] = NULL;
+
+	return strv;
+}
+
+/* free out_uid, out_rid and out_auid with g_free() */
+gboolean
+e_gdbus_cal_decode_discard_alarm (const gchar * const *in_strv, gchar **out_uid, gchar **out_rid, gchar **out_auid)
+{
+	g_return_val_if_fail (in_strv != NULL, FALSE);
+	g_return_val_if_fail (in_strv[0] != NULL, FALSE);
+	g_return_val_if_fail (in_strv[1] != NULL, FALSE);
+	g_return_val_if_fail (in_strv[2] != NULL, FALSE);
+	g_return_val_if_fail (in_strv[3] == NULL, FALSE);
+	g_return_val_if_fail (out_uid != NULL, FALSE);
+	g_return_val_if_fail (out_rid != NULL, FALSE);
+	g_return_val_if_fail (out_auid != NULL, FALSE);
+
+	*out_uid = g_strdup (in_strv[0]);
+	*out_rid = g_strdup (in_strv[1]);
+	*out_auid = g_strdup (in_strv[2]);
+
+	return TRUE;
+}
+
+void
+e_gdbus_cal_call_discard_alarm (GDBusProxy *proxy, const gchar * const *in_uid_rid_auid, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_call_strv ("discardAlarm", e_gdbus_cal_call_discard_alarm, E_GDBUS_ASYNC_OP_KEEPER (proxy), in_uid_rid_auid, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_cal_call_discard_alarm_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_finish_call_void (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, error, e_gdbus_cal_call_discard_alarm);
+}
+
+gboolean
+e_gdbus_cal_call_discard_alarm_sync (GDBusProxy *proxy, const gchar * const *in_uid_rid_auid, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_call_sync_strv__void (proxy, in_uid_rid_auid, cancellable, error,
+		e_gdbus_cal_call_discard_alarm,
+		e_gdbus_cal_call_discard_alarm_finish);
+}
+
+void
+e_gdbus_cal_call_get_view (GDBusProxy *proxy, const gchar *in_sexp, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_call_string ("getView", e_gdbus_cal_call_get_view, E_GDBUS_ASYNC_OP_KEEPER (proxy), in_sexp, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_cal_call_get_view_finish (GDBusProxy *proxy, GAsyncResult *result, gchar **out_view_path, GError **error)
+{
+	return e_gdbus_proxy_finish_call_string (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, out_view_path, error, e_gdbus_cal_call_get_view);
+}
+
+gboolean
+e_gdbus_cal_call_get_view_sync (GDBusProxy *proxy, const gchar *in_sexp, gchar **out_view_path, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_call_sync_string__string (proxy, in_sexp, out_view_path, cancellable, error,
+		e_gdbus_cal_call_get_view,
+		e_gdbus_cal_call_get_view_finish);
+}
+
+void
+e_gdbus_cal_call_get_timezone (GDBusProxy *proxy, const gchar *in_tzid, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_call_string ("getTimezone", e_gdbus_cal_call_get_timezone, E_GDBUS_ASYNC_OP_KEEPER (proxy), in_tzid, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_cal_call_get_timezone_finish (GDBusProxy *proxy, GAsyncResult *result, gchar **out_tzobject, GError **error)
+{
+	return e_gdbus_proxy_finish_call_string (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, out_tzobject, error, e_gdbus_cal_call_get_timezone);
+}
+
+gboolean
+e_gdbus_cal_call_get_timezone_sync (GDBusProxy *proxy, const gchar *in_tzid, gchar **out_tzobject, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_call_sync_string__string (proxy, in_tzid, out_tzobject, cancellable, error,
+		e_gdbus_cal_call_get_timezone,
+		e_gdbus_cal_call_get_timezone_finish);
+}
+
+void
+e_gdbus_cal_call_add_timezone (GDBusProxy *proxy, const gchar *in_tzobject, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_call_string ("addTimezone", e_gdbus_cal_call_add_timezone, E_GDBUS_ASYNC_OP_KEEPER (proxy), in_tzobject, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_cal_call_add_timezone_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_finish_call_void (E_GDBUS_ASYNC_OP_KEEPER (proxy), result, error, e_gdbus_cal_call_add_timezone);
+}
+
+gboolean
+e_gdbus_cal_call_add_timezone_sync (GDBusProxy *proxy, const gchar *in_tzobject, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_call_sync_string__void (proxy, in_tzobject, cancellable, error,
+		e_gdbus_cal_call_add_timezone,
+		e_gdbus_cal_call_add_timezone_finish);
+}
+
+void
+e_gdbus_cal_call_authenticate_user (GDBusProxy *proxy, const gchar * const *in_credentials, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_method_call_strv ("authenticateUser", proxy, in_credentials, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_cal_call_authenticate_user_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_method_call_finish_void (proxy, result, error);
+}
+
+gboolean
+e_gdbus_cal_call_authenticate_user_sync (GDBusProxy *proxy, const gchar * const *in_credentials, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_method_call_sync_strv__void ("authenticateUser", proxy, in_credentials, cancellable, error);
+}
+
+void
+e_gdbus_cal_call_cancel_operation (GDBusProxy *proxy, guint in_opid, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_method_call_uint ("cancelOperation", proxy, in_opid, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_cal_call_cancel_operation_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_method_call_finish_void (proxy, result, error);
+}
+
+gboolean
+e_gdbus_cal_call_cancel_operation_sync (GDBusProxy *proxy, guint in_opid, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_method_call_sync_uint__void ("cancelOperation", proxy, in_opid, cancellable, error);
+}
+
+void
+e_gdbus_cal_call_cancel_all (GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_method_call_void ("cancelAll", proxy, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_cal_call_cancel_all_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_method_call_finish_void (proxy, result, error);
+}
+
+gboolean
+e_gdbus_cal_call_cancel_all_sync (GDBusProxy *proxy, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_method_call_sync_void__void ("cancelAll", proxy, cancellable, error);
+}
+
+void
+e_gdbus_cal_call_close (GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	e_gdbus_proxy_method_call_void ("close", proxy, cancellable, callback, user_data);
+}
+	
+gboolean
+e_gdbus_cal_call_close_finish (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return e_gdbus_proxy_method_call_finish_void (proxy, result, error);
+}
+
+gboolean
+e_gdbus_cal_call_close_sync (GDBusProxy *proxy, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_proxy_method_call_sync_void__void ("close", proxy, cancellable, error);
+}
+
+#define DECLARE_EMIT_DONE_SIGNAL_0(_mname, _sig_id)									\
+void															\
+e_gdbus_cal_emit_ ## _mname ## _done (EGdbusCal *object, guint arg_opid, const GError *arg_error)			\
+{															\
+	g_signal_emit (object, signals[_sig_id], 0, arg_opid, arg_error);						\
+}
+
+#define DECLARE_EMIT_DONE_SIGNAL_1(_mname, _sig_id, _par_type)								\
+void															\
+e_gdbus_cal_emit_ ## _mname ## _done (EGdbusCal *object, guint arg_opid, const GError *arg_error, _par_type out_par)	\
+{															\
+	g_signal_emit (object, signals[_sig_id], 0, arg_opid, arg_error, out_par);					\
+}
+
+DECLARE_EMIT_DONE_SIGNAL_0 (open,			__OPEN_DONE_SIGNAL)
+DECLARE_EMIT_DONE_SIGNAL_0 (remove,			__REMOVE_DONE_SIGNAL)
+DECLARE_EMIT_DONE_SIGNAL_0 (refresh,			__REFRESH_DONE_SIGNAL)
+DECLARE_EMIT_DONE_SIGNAL_1 (get_backend_property,	__GET_BACKEND_PROPERTY_DONE_SIGNAL, const gchar *)
+DECLARE_EMIT_DONE_SIGNAL_0 (set_backend_property,	__SET_BACKEND_PROPERTY_DONE_SIGNAL)
+DECLARE_EMIT_DONE_SIGNAL_1 (get_object,			__GET_OBJECT_DONE_SIGNAL, const gchar *)
+DECLARE_EMIT_DONE_SIGNAL_1 (get_object_list,		__GET_OBJECT_LIST_DONE_SIGNAL, const gchar * const *)
+DECLARE_EMIT_DONE_SIGNAL_0 (get_free_busy,		__GET_FREE_BUSY_DONE_SIGNAL)
+DECLARE_EMIT_DONE_SIGNAL_1 (create_object,		__CREATE_OBJECT_DONE_SIGNAL, const gchar *)
+DECLARE_EMIT_DONE_SIGNAL_0 (modify_object,		__MODIFY_OBJECT_DONE_SIGNAL)
+DECLARE_EMIT_DONE_SIGNAL_0 (remove_object,		__REMOVE_OBJECT_DONE_SIGNAL)
+DECLARE_EMIT_DONE_SIGNAL_0 (receive_objects,		__RECEIVE_OBJECTS_DONE_SIGNAL)
+DECLARE_EMIT_DONE_SIGNAL_1 (send_objects,		__SEND_OBJECTS_DONE_SIGNAL, const gchar * const *)
+DECLARE_EMIT_DONE_SIGNAL_1 (get_attachment_uris,	__GET_ATTACHMENT_URIS_DONE_SIGNAL, const gchar * const *)
+DECLARE_EMIT_DONE_SIGNAL_0 (discard_alarm,		__DISCARD_ALARM_DONE_SIGNAL)
+DECLARE_EMIT_DONE_SIGNAL_1 (get_view,			__GET_VIEW_DONE_SIGNAL, const gchar *)
+DECLARE_EMIT_DONE_SIGNAL_1 (get_timezone,		__GET_TIMEZONE_DONE_SIGNAL, const gchar *)
+DECLARE_EMIT_DONE_SIGNAL_0 (add_timezone,		__ADD_TIMEZONE_DONE_SIGNAL)
+
+void
+e_gdbus_cal_emit_backend_error (EGdbusCal *object, const gchar *arg_message)
+{
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (arg_message != NULL);
+
+	g_signal_emit (object, signals[__BACKEND_ERROR_SIGNAL], 0, arg_message);
+}
+
+void
+e_gdbus_cal_emit_readonly (EGdbusCal *object, gboolean arg_is_readonly)
+{
+	g_signal_emit (object, signals[__READONLY_SIGNAL], 0, arg_is_readonly);
+}
+
+void
+e_gdbus_cal_emit_online (EGdbusCal *object, gboolean arg_is_online)
+{
+	g_signal_emit (object, signals[__ONLINE_SIGNAL], 0, arg_is_online);
+}
+
+void
+e_gdbus_cal_emit_auth_required (EGdbusCal *object, const gchar * const *arg_credentials)
+{
+	g_signal_emit (object, signals[__AUTH_REQUIRED_SIGNAL], 0, arg_credentials);
+}
+
+void
+e_gdbus_cal_emit_opened (EGdbusCal *object, const gchar * const *arg_error)
+{
+	g_signal_emit (object, signals[__OPENED_SIGNAL], 0, arg_error);
+}
+
+void
+e_gdbus_cal_emit_free_busy_data (EGdbusCal *object, const gchar * const *arg_free_busy)
+{
+	g_signal_emit (object, signals[__FREE_BUSY_DATA_SIGNAL], 0, arg_free_busy);
+}
+
+E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (cal, backend_error, message, "s")
+E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (cal, readonly, is_readonly, "b")
+E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (cal, online, is_online, "b")
+E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (cal, auth_required, credentials, "as")
+E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (cal, opened, error, "as")
+E_DECLARE_GDBUS_NOTIFY_SIGNAL_1 (cal, free_busy_data, free_busy_data, "as")
+
+E_DECLARE_GDBUS_ASYNC_METHOD_1			(cal, open, only_if_exists, "b")
+E_DECLARE_GDBUS_ASYNC_METHOD_0			(cal, remove)
+E_DECLARE_GDBUS_ASYNC_METHOD_0			(cal, refresh)
+E_DECLARE_GDBUS_ASYNC_METHOD_1_WITH_RETURN	(cal, getBackendProperty, propname, "s", propvalue, "s")
+E_DECLARE_GDBUS_ASYNC_METHOD_1			(cal, setBackendProperty, propnamevalue, "as")
+E_DECLARE_GDBUS_ASYNC_METHOD_1_WITH_RETURN	(cal, getObject, uid_rid, "as", object, "s")
+E_DECLARE_GDBUS_ASYNC_METHOD_1_WITH_RETURN	(cal, getObjectList, sexp, "s", objects, "as")
+E_DECLARE_GDBUS_ASYNC_METHOD_1_WITH_RETURN	(cal, getFreeBusy, start_stop_users, "as", freebusy, "as")
+E_DECLARE_GDBUS_ASYNC_METHOD_1_WITH_RETURN	(cal, createObject, object, "s", uid, "s")
+E_DECLARE_GDBUS_ASYNC_METHOD_1			(cal, modifyObject, object_mod, "as")
+E_DECLARE_GDBUS_ASYNC_METHOD_1			(cal, removeObject, uid_rid_mod, "as")
+E_DECLARE_GDBUS_ASYNC_METHOD_1			(cal, receiveObjects, object, "s")
+E_DECLARE_GDBUS_ASYNC_METHOD_1_WITH_RETURN	(cal, sendObjects, object, "s", object_users, "as")
+E_DECLARE_GDBUS_ASYNC_METHOD_1_WITH_RETURN	(cal, getAttachmentUris, uid_rid, "as", attachments, "as")
+E_DECLARE_GDBUS_ASYNC_METHOD_1			(cal, discardAlarm, uid_rid_auid, "as")
+E_DECLARE_GDBUS_ASYNC_METHOD_1_WITH_RETURN	(cal, getView, sexp, "s", view_path, "s")
+E_DECLARE_GDBUS_ASYNC_METHOD_1_WITH_RETURN	(cal, getTimezone, tzid, "s", tzobject, "s")
+E_DECLARE_GDBUS_ASYNC_METHOD_1			(cal, addTimezone, tzobject, "s")
+
+E_DECLARE_GDBUS_SYNC_METHOD_1			(cal, authenticateUser, credentials, "as")
+E_DECLARE_GDBUS_SYNC_METHOD_1			(cal, cancelOperation, opid, "u")
+E_DECLARE_GDBUS_SYNC_METHOD_0			(cal, cancelAll)
+E_DECLARE_GDBUS_SYNC_METHOD_0			(cal, close)
+
+static const GDBusMethodInfo * const e_gdbus_cal_method_info_pointers[] =
+{
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, open),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, remove),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, refresh),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, getBackendProperty),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, setBackendProperty),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, getObject),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, getObjectList),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, getFreeBusy),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, createObject),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, modifyObject),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, removeObject),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, receiveObjects),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, sendObjects),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, getAttachmentUris),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, discardAlarm),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, getView),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, getTimezone),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, addTimezone),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, authenticateUser),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, cancelOperation),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, cancelAll),
+	&E_DECLARED_GDBUS_METHOD_INFO_NAME (cal, close),
+	NULL
+};
+
+static const GDBusSignalInfo * const e_gdbus_cal_signal_info_pointers[] =
+{
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, backend_error),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, readonly),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, online),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, auth_required),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, opened),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, free_busy_data),
+
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, open_done),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, remove_done),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, refresh_done),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, getBackendProperty_done),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, setBackendProperty_done),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, getObject_done),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, getObjectList_done),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, getFreeBusy_done),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, createObject_done),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, modifyObject_done),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, removeObject_done),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, receiveObjects_done),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, sendObjects_done),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, getAttachmentUris_done),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, discardAlarm_done),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, getView_done),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, getTimezone_done),
+	&E_DECLARED_GDBUS_SIGNAL_INFO_NAME (cal, addTimezone_done),
+	NULL
+};
+
+static const GDBusInterfaceInfo _e_gdbus_cal_interface_info =
+{
+	-1,
+	(gchar *) GDBUS_CAL_INTERFACE_NAME,
+	(GDBusMethodInfo **) &e_gdbus_cal_method_info_pointers,
+	(GDBusSignalInfo **) &e_gdbus_cal_signal_info_pointers,
+	(GDBusPropertyInfo **) NULL
+};
+
+static void
+handle_method_call (GDBusConnection       *connection,
+                    const gchar           *sender,
+                    const gchar           *object_path,
+                    const gchar           *interface_name,
+                    const gchar           *method_name,
+                    GVariant              *parameters,
+                    GDBusMethodInvocation *invocation,
+                    gpointer               user_data)
+{
+	guint method_id, method_type;
+
+	method_id = lookup_method_id_from_method_name (method_name);
+	method_type = lookup_method_type_from_method_name (method_name);
+
+	g_return_if_fail (method_id != 0);
+	g_return_if_fail (method_type != 0);
+
+	e_gdbus_stub_handle_method_call (user_data, invocation, parameters, method_name, signals[method_id], method_type);
+}
+
+static GVariant *
+get_property (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *property_name, GError **error, gpointer user_data)
+{
+	g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "This implementation does not support property `%s'", property_name);
+	return NULL;
+}
+
+static gboolean
+set_property (GDBusConnection *connection, const gchar *sender, const gchar *object_path, const gchar *interface_name, const gchar *property_name, GVariant *value, GError **error, gpointer user_data)
+{
+	g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "This implementation does not support property `%s'", property_name);
+	return FALSE;
+}
+
+static const GDBusInterfaceVTable e_gdbus_cal_interface_vtable =
+{
+	handle_method_call,
+	get_property,
+	set_property
+};
+
+static gboolean
+emit_notifications_in_idle (gpointer user_data)
+{
+	GObject *object = G_OBJECT (user_data);
+	GDBusConnection *connection;
+	const gchar *path;
+	GHashTable *notification_queue;
+	GHashTableIter iter;
+	const gchar *property_name;
+	GVariant *value;
+	GVariantBuilder *builder;
+	GVariantBuilder *invalidated_builder;
+	GHashTable *pvc;
+	gboolean has_changes;
+
+	notification_queue = g_object_get_data (object, "gdbus-codegen-notification-queue");
+	path = g_object_get_data (object, "gdbus-codegen-path");
+	connection = g_object_get_data (object, "gdbus-codegen-connection");
+	pvc = g_object_get_data (object, "gdbus-codegen-pvc");
+	g_assert (notification_queue != NULL && path != NULL && connection != NULL && pvc != NULL);
+
+	builder = g_variant_builder_new (G_VARIANT_TYPE_ARRAY);
+	invalidated_builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
+	g_hash_table_iter_init (&iter, notification_queue);
+	has_changes = FALSE;
+	while (g_hash_table_iter_next (&iter, (gpointer) &property_name, (gpointer) &value)) {
+		GVariant *cached_value;
+		cached_value = g_hash_table_lookup (pvc, property_name);
+		if (cached_value == NULL || !g_variant_equal (cached_value, value)) {
+			g_hash_table_insert (pvc, (gpointer) property_name, (gpointer) g_variant_ref (value));
+			g_variant_builder_add (builder, "{sv}", property_name, value);
+			has_changes = TRUE;
+		}
+	}
+
+	if (has_changes) {
+		g_dbus_connection_emit_signal (connection,
+					NULL,
+					path,
+					"org.freedesktop.DBus.Properties",
+					"PropertiesChanged",
+					g_variant_new ("(sa{sv}as)",
+							GDBUS_CAL_INTERFACE_NAME,
+							builder,
+							invalidated_builder),
+					NULL);
+	} else {
+		g_variant_builder_unref (builder);
+		g_variant_builder_unref (invalidated_builder);
+	}
+
+	g_hash_table_remove_all (notification_queue);
+	g_object_set_data (object, "gdbus-codegen-notification-idle-id", GUINT_TO_POINTER (0));
+	return FALSE;
+}
+
+/**
+ * e_gdbus_cal_drain_notify:
+ * @object: A #EGdbusCal that is exported.
+ *
+ * If @object has queued notifications, empty the queue forcing
+ * the <literal>PropertiesChanged</literal> signal to be emitted.
+ * See <xref linkend="EGdbusCal.description"/> for more background information.
+ */
+void
+e_gdbus_cal_drain_notify (EGdbusCal *object)
+{
+	gint idle_id;
+	idle_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (object), "gdbus-codegen-notification-idle-id"));
+	if (idle_id > 0) {
+		emit_notifications_in_idle (object);
+		g_source_remove (idle_id);
+	}
+}
+
+static void
+on_object_unregistered (GObject *object)
+{
+	gint idle_id;
+	idle_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (object), "gdbus-codegen-notification-idle-id"));
+	if (idle_id > 0) {
+		g_source_remove (idle_id);
+	}
+	g_object_set_data (G_OBJECT (object), "gdbus-codegen-path", NULL);
+	g_object_set_data (G_OBJECT (object), "gdbus-codegen-connection", NULL);
+}
+
+/**
+ * e_gdbus_cal_register_object:
+ * @object: An instance of a #GObject<!-- -->-derived type implementing the #EGdbusCal interface.
+ * @connection: A #GDBusConnection.
+ * @object_path: The object to register the object at.
+ * @error: Return location for error or %NULL.
+ *
+ * Registers @object at @object_path on @connection.
+ *
+ * See <xref linkend="EGdbusCal.description"/>
+ * for how properties, methods and signals are handled.
+ *
+ * Returns: 0 if @error is set, otherwise a registration id (never 0) that can be used with g_dbus_connection_unregister_object().
+ */
+guint
+e_gdbus_cal_register_object (EGdbusCal *object, GDBusConnection *connection, const gchar *object_path, GError **error)
+{
+	GHashTable *pvc;
+
+	pvc = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) g_variant_unref);
+
+	g_object_set_data_full (G_OBJECT (object), "gdbus-codegen-path", (gpointer) g_strdup (object_path), g_free);
+	g_object_set_data (G_OBJECT (object), "gdbus-codegen-connection", (gpointer) connection);
+	g_object_set_data_full (G_OBJECT (object), "gdbus-codegen-pvc", (gpointer) pvc, (GDestroyNotify) g_hash_table_unref);
+
+	return g_dbus_connection_register_object (connection,
+			object_path,
+			(GDBusInterfaceInfo *) &_e_gdbus_cal_interface_info,
+			&e_gdbus_cal_interface_vtable,
+			object,
+			(GDestroyNotify) on_object_unregistered,
+			error);
+}
+
+/**
+ * e_gdbus_cal_interface_info:
+ *
+ * Gets interface description for the <literal>org.gnome.evolution.dataserver.Calendar</literal> D-Bus interface.
+ *
+ * Returns: A #GDBusInterfaceInfo. Do not free, the object is statically allocated.
+ */
+const GDBusInterfaceInfo *
+e_gdbus_cal_interface_info (void)
+{
+	return &_e_gdbus_cal_interface_info;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void proxy_iface_init (EGdbusCalIface *iface);
+static void async_op_keeper_iface_init (EGdbusAsyncOpKeeperInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (EGdbusCalProxy, e_gdbus_cal_proxy, G_TYPE_DBUS_PROXY,
+                         G_IMPLEMENT_INTERFACE (E_TYPE_GDBUS_CAL, proxy_iface_init)
+			 G_IMPLEMENT_INTERFACE (E_TYPE_GDBUS_ASYNC_OP_KEEPER, async_op_keeper_iface_init));
+
+static void
+e_gdbus_cal_proxy_init (EGdbusCalProxy *proxy)
+{
+	g_dbus_proxy_set_interface_info (G_DBUS_PROXY (proxy), (GDBusInterfaceInfo *) &_e_gdbus_cal_interface_info);
+
+	proxy->priv = G_TYPE_INSTANCE_GET_PRIVATE (proxy, E_TYPE_GDBUS_CAL_PROXY, EGdbusCalProxyPrivate);
+	proxy->priv->pending_ops = e_gdbus_async_op_keeper_create_pending_ops (E_GDBUS_ASYNC_OP_KEEPER (proxy));
+
+	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_VOID   (open);
+	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_VOID   (remove);
+	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_VOID   (refresh);
+	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_STRING (get_backend_property);
+	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_VOID   (set_backend_property);
+	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_STRING (get_object);
+	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_STRV   (get_object_list);
+	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_STRV   (get_free_busy);
+	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_STRING (create_object);
+	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_VOID   (modify_object);
+	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_VOID   (remove_object);
+	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_VOID   (receive_objects);
+	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_STRV   (send_objects);
+	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_STRV   (get_attachment_uris);
+	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_VOID   (discard_alarm);
+	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_STRING (get_view);
+	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_STRING (get_timezone);
+	E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_VOID   (add_timezone);
+}
+
+static void
+g_signal (GDBusProxy *proxy, const gchar *sender_name, const gchar *signal_name, GVariant *parameters)
+{
+	guint signal_id, signal_type;
+
+	signal_id = lookup_signal_id_from_signal_name (signal_name);
+	signal_type = lookup_signal_type_from_signal_name (signal_name);
+
+	g_return_if_fail (signal_id != 0);
+	g_return_if_fail (signal_type != 0);
+
+	e_gdbus_proxy_emit_signal (proxy, parameters, signals[signal_id], signal_type);
+}
+
+static void
+gdbus_cal_proxy_finalize (GObject *object)
+{
+	EGdbusCalProxy *proxy = E_GDBUS_CAL_PROXY (object);
+
+	g_return_if_fail (proxy != NULL);
+	g_return_if_fail (proxy->priv != NULL);
+
+	if (g_hash_table_size (proxy->priv->pending_ops))
+		g_debug ("%s: Kept %d items in pending_ops", G_STRFUNC, g_hash_table_size (proxy->priv->pending_ops));
+
+	g_hash_table_destroy (proxy->priv->pending_ops);
+
+	G_OBJECT_CLASS (e_gdbus_cal_proxy_parent_class)->finalize (object);
+}
+
+static void
+e_gdbus_cal_proxy_class_init (EGdbusCalProxyClass *klass)
+{
+	GObjectClass *object_class;
+	GDBusProxyClass *proxy_class;
+
+	g_type_class_add_private (klass, sizeof (EGdbusCalProxyPrivate));
+
+	object_class = G_OBJECT_CLASS (klass);
+	object_class->finalize = gdbus_cal_proxy_finalize;
+
+	proxy_class = G_DBUS_PROXY_CLASS (klass);
+	proxy_class->g_signal = g_signal;
+}
+
+static void
+proxy_iface_init (EGdbusCalIface *iface)
+{
+}
+
+static GHashTable *
+gdbus_cal_get_pending_ops (EGdbusAsyncOpKeeper *object)
+{
+	EGdbusCalProxy *proxy;
+
+	g_return_val_if_fail (object != NULL, NULL);
+	g_return_val_if_fail (E_IS_GDBUS_CAL_PROXY (object), NULL);
+
+	proxy = E_GDBUS_CAL_PROXY (object);
+	g_return_val_if_fail (proxy != NULL, NULL);
+	g_return_val_if_fail (proxy->priv != NULL, NULL);
+
+	return proxy->priv->pending_ops;
+}
+
+static gboolean
+gdbus_cal_call_cancel_operation_sync (EGdbusAsyncOpKeeper *object, guint in_opid, GCancellable *cancellable, GError **error)
+{
+	return e_gdbus_cal_call_cancel_operation_sync (G_DBUS_PROXY (object), in_opid, cancellable, error);
+}
+
+static void
+async_op_keeper_iface_init (EGdbusAsyncOpKeeperInterface *iface)
+{
+	g_return_if_fail (iface != NULL);
+
+	iface->get_pending_ops = gdbus_cal_get_pending_ops;
+	iface->cancel_op_sync = gdbus_cal_call_cancel_operation_sync;
+}
+
+/**
+ * e_gdbus_cal_proxy_new:
+ * @connection: A #GDBusConnection.
+ * @flags: Flags used when constructing the proxy.
+ * @name: A bus name (well-known or unique) or %NULL if @connection is not a message bus connection.
+ * @object_path: An object path.
+ * @cancellable: A #GCancellable or %NULL.
+ * @callback: Callback function to invoke when the proxy is ready.
+ * @user_data: User data to pass to @callback.
+ *
+ * Like g_dbus_proxy_new() but returns a #EGdbusCalProxy.
+ *
+ * This is a failable asynchronous constructor - when the proxy is ready, callback will be invoked and you can use e_gdbus_cal_proxy_new_finish() to get the result.
+ */
+void
+e_gdbus_cal_proxy_new (GDBusConnection *connection, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	g_async_initable_new_async (E_TYPE_GDBUS_CAL_PROXY,
+				G_PRIORITY_DEFAULT,
+				cancellable,
+				callback,
+				user_data,
+				"g-flags", flags,
+				"g-name", name,
+				"g-connection", connection,
+				"g-object-path", object_path,
+				"g-interface-name", GDBUS_CAL_INTERFACE_NAME,
+				NULL);
+}
+
+/**
+ * e_gdbus_cal_proxy_new_finish:
+ * @result: A #GAsyncResult obtained from the #GAsyncReadyCallback function passed to e_gdbus_cal_proxy_new().
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes creating a #EGdbusCalProxy.
+ *
+ * Returns: A #EGdbusCalProxy or %NULL if @error is set. Free with g_object_unref().
+ */
+EGdbusCal *
+e_gdbus_cal_proxy_new_finish (GAsyncResult  *result, GError **error)
+{
+	GObject *object;
+	GObject *source_object;
+	source_object = g_async_result_get_source_object (result);
+	g_assert (source_object != NULL);
+	object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), result, error);
+	g_object_unref (source_object);
+	if (object != NULL)
+		return E_GDBUS_CAL (object);
+	else
+		return NULL;
+}
+
+/**
+ * e_gdbus_cal_proxy_new_sync:
+ * @connection: A #GDBusConnection.
+ * @flags: Flags used when constructing the proxy.
+ * @name: A bus name (well-known or unique) or %NULL if @connection is not a message bus connection.
+ * @object_path: An object path.
+ * @cancellable: A #GCancellable or %NULL.
+ * @error: Return location for error or %NULL.
+ *
+ * Like g_dbus_proxy_new_sync() but returns a #EGdbusCalProxy.
+ *
+ * This is a synchronous failable constructor. See e_gdbus_cal_proxy_new() and e_gdbus_cal_proxy_new_finish() for the asynchronous version.
+ *
+ * Returns: A #EGdbusCalProxy or %NULL if error is set. Free with g_object_unref().
+ */
+EGdbusCal *
+e_gdbus_cal_proxy_new_sync (GDBusConnection *connection, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GError **error)
+{
+	GInitable *initable;
+	initable = g_initable_new (E_TYPE_GDBUS_CAL_PROXY,
+				cancellable,
+				error,
+				"g-flags", flags,
+				"g-name", name,
+				"g-connection", connection,
+				"g-object-path", object_path,
+				"g-interface-name", GDBUS_CAL_INTERFACE_NAME,
+				NULL);
+	if (initable != NULL)
+		return E_GDBUS_CAL (initable);
+	else
+		return NULL;
+}
+
+/**
+ * e_gdbus_cal_proxy_new_for_bus:
+ * @bus_type: A #GBusType.
+ * @flags: Flags used when constructing the proxy.
+ * @name: A bus name (well-known or unique).
+ * @object_path: An object path.
+ * @cancellable: A #GCancellable or %NULL.
+ * @callback: Callback function to invoke when the proxy is ready.
+ * @user_data: User data to pass to @callback.
+ *
+ * Like g_dbus_proxy_new_for_bus() but returns a #EGdbusCalProxy.
+ *
+ * This is a failable asynchronous constructor - when the proxy is ready, callback will be invoked and you can use e_gdbus_cal_proxy_new_for_bus_finish() to get the result.
+ */
+void
+e_gdbus_cal_proxy_new_for_bus (GBusType bus_type, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	g_async_initable_new_async (E_TYPE_GDBUS_CAL_PROXY,
+				G_PRIORITY_DEFAULT,
+				cancellable,
+				callback,
+				user_data,
+				"g-flags", flags,
+				"g-name", name,
+				"g-bus-type", bus_type,
+				"g-object-path", object_path,
+				"g-interface-name", GDBUS_CAL_INTERFACE_NAME,
+				NULL);
+}
+
+/**
+ * e_gdbus_cal_proxy_new_for_bus_finish:
+ * @result: A #GAsyncResult obtained from the #GAsyncReadyCallback function passed to e_gdbus_cal_proxy_new_for_bus().
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes creating a #EGdbusCalProxy.
+ *
+ * Returns: A #EGdbusCalProxy or %NULL if @error is set. Free with g_object_unref().
+ */
+EGdbusCal *
+e_gdbus_cal_proxy_new_for_bus_finish (GAsyncResult *result, GError **error)
+{
+	GObject *object;
+	GObject *source_object;
+	source_object = g_async_result_get_source_object (result);
+	g_assert (source_object != NULL);
+	object = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), result, error);
+	g_object_unref (source_object);
+	if (object != NULL)
+		return E_GDBUS_CAL (object);
+	else
+		return NULL;
+}
+
+/**
+ * e_gdbus_cal_proxy_new_for_bus_sync:
+ * @bus_type: A #GBusType.
+ * @flags: Flags used when constructing the proxy.
+ * @name: A bus name (well-known or unique).
+ * @object_path: An object path.
+ * @cancellable: A #GCancellable or %NULL.
+ * @error: Return location for error or %NULL.
+ *
+ * Like g_dbus_proxy_new_for_bus_sync() but returns a #EGdbusCalProxy.
+ *
+ * This is a synchronous failable constructor. See e_gdbus_cal_proxy_new_for_bus() and e_gdbus_cal_proxy_new_for_bus_finish() for the asynchronous version.
+ *
+ * Returns: A #EGdbusCalProxy or %NULL if error is set. Free with g_object_unref().
+ */
+EGdbusCal *
+e_gdbus_cal_proxy_new_for_bus_sync (GBusType bus_type, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GError **error)
+{
+	GInitable *initable;
+	initable = g_initable_new (E_TYPE_GDBUS_CAL_PROXY,
+				cancellable,
+				error,
+				"g-flags", flags,
+				"g-name", name,
+				"g-bus-type", bus_type,
+				"g-object-path", object_path,
+				"g-interface-name", GDBUS_CAL_INTERFACE_NAME,
+				NULL);
+	if (initable != NULL)
+		return E_GDBUS_CAL (initable);
+	else
+		return NULL;
+}
+
+/* ---------------------------------------------------------------------- */
+
+struct _EGdbusCalStubPrivate
+{
+	gint foo;
+};
+
+static void stub_iface_init (EGdbusCalIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (EGdbusCalStub, e_gdbus_cal_stub, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (E_TYPE_GDBUS_CAL, stub_iface_init));
+
+static void
+e_gdbus_cal_stub_init (EGdbusCalStub *stub)
+{
+	stub->priv = G_TYPE_INSTANCE_GET_PRIVATE (stub, E_TYPE_GDBUS_CAL_STUB, EGdbusCalStubPrivate);
+}
+
+static void
+e_gdbus_cal_stub_class_init (EGdbusCalStubClass *klass)
+{
+	g_type_class_add_private (klass, sizeof (EGdbusCalStubPrivate));
+}
+
+static void
+stub_iface_init (EGdbusCalIface *iface)
+{
+}
+
+/**
+ * e_gdbus_cal_stub_new:
+ *
+ * Creates a new stub object that can be exported via e_gdbus_cal_register_object().
+ *
+ * Returns: A #EGdbusCalStub instance. Free with g_object_unref().
+ */
+EGdbusCal *
+e_gdbus_cal_stub_new (void)
+{
+	return E_GDBUS_CAL (g_object_new (E_TYPE_GDBUS_CAL_STUB, NULL));
+}
+
+/* Returns GDBus connection associated with the stub object */
+GDBusConnection *
+e_gdbus_cal_stub_get_connection (EGdbusCal *stub)
+{
+	g_return_val_if_fail (stub != NULL, NULL);
+	g_return_val_if_fail (E_IS_GDBUS_CAL_STUB (stub), NULL);
+
+	return g_object_get_data (G_OBJECT (stub), "gdbus-codegen-connection");
+}
diff --git a/calendar/libegdbus/e-gdbus-cal.h b/calendar/libegdbus/e-gdbus-cal.h
new file mode 100644
index 0000000..21e2c7d
--- /dev/null
+++ b/calendar/libegdbus/e-gdbus-cal.h
@@ -0,0 +1,333 @@
+/*
+ * e-gdbus-cal.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 2011 Red Hat, Inc. (www.redhat.com)
+ *
+ */
+
+#ifndef E_GDBUS_CAL_H
+#define E_GDBUS_CAL_H
+
+#include <gio/gio.h>
+
+#include <libedataserver/e-gdbus-templates.h>
+
+G_BEGIN_DECLS
+
+#define E_TYPE_GDBUS_CAL	(e_gdbus_cal_get_type ())
+#define E_GDBUS_CAL(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_GDBUS_CAL, EGdbusCal))
+#define E_IS_GDBUS_CAL(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_GDBUS_CAL))
+#define E_GDBUS_CAL_GET_IFACE(o)(G_TYPE_INSTANCE_GET_INTERFACE((o), E_TYPE_GDBUS_CAL, EGdbusCalIface))
+
+typedef struct _EGdbusCal EGdbusCal; /* Dummy typedef */
+typedef struct _EGdbusCalIface EGdbusCalIface;
+
+GType e_gdbus_cal_get_type (void) G_GNUC_CONST;
+
+/* ---------------------------------------------------------------------- */
+
+typedef struct _EGdbusCalProxy EGdbusCalProxy;
+typedef struct _EGdbusCalProxyClass EGdbusCalProxyClass;
+typedef struct _EGdbusCalProxyPrivate EGdbusCalProxyPrivate;
+
+struct _EGdbusCalProxy
+{
+	GDBusProxy parent_instance;
+	EGdbusCalProxyPrivate *priv;
+};
+
+struct _EGdbusCalProxyClass
+{
+	GDBusProxyClass parent_class;
+};
+
+#define E_TYPE_GDBUS_CAL_PROXY	(e_gdbus_cal_proxy_get_type ())
+#define E_GDBUS_CAL_PROXY(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_GDBUS_CAL_PROXY, EGdbusCalProxy))
+#define E_IS_GDBUS_CAL_PROXY(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_GDBUS_CAL_PROXY))
+GType e_gdbus_cal_proxy_get_type (void) G_GNUC_CONST;
+
+void		e_gdbus_cal_proxy_new		(GDBusConnection *connection, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+EGdbusCal *	e_gdbus_cal_proxy_new_finish	(GAsyncResult  *result, GError **error);
+EGdbusCal *	e_gdbus_cal_proxy_new_sync	(GDBusConnection *connection, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_cal_proxy_new_for_bus		(GBusType bus_type, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+EGdbusCal *	e_gdbus_cal_proxy_new_for_bus_finish	(GAsyncResult *result, GError **error);
+EGdbusCal *	e_gdbus_cal_proxy_new_for_bus_sync	(GBusType bus_type, GDBusProxyFlags flags, const gchar *name, const gchar *object_path, GCancellable *cancellable, GError **error);
+
+/* ---------------------------------------------------------------------- */
+
+typedef struct _EGdbusCalStub EGdbusCalStub;
+typedef struct _EGdbusCalStubClass EGdbusCalStubClass;
+typedef struct _EGdbusCalStubPrivate EGdbusCalStubPrivate;
+
+struct _EGdbusCalStub
+{
+	GObject parent_instance;
+	EGdbusCalStubPrivate *priv;
+};
+
+struct _EGdbusCalStubClass
+{
+	GObjectClass parent_class;
+};
+
+#define E_TYPE_GDBUS_CAL_STUB	(e_gdbus_cal_stub_get_type ())
+#define E_GDBUS_CAL_STUB(o)	(G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_GDBUS_CAL_STUB, EGdbusCalStub))
+#define E_IS_GDBUS_CAL_STUB(o)	(G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_GDBUS_CAL_STUB))
+GType e_gdbus_cal_stub_get_type (void) G_GNUC_CONST;
+
+EGdbusCal *e_gdbus_cal_stub_new (void);
+GDBusConnection *e_gdbus_cal_stub_get_connection (EGdbusCal *stub);
+
+guint e_gdbus_cal_register_object (EGdbusCal *object, GDBusConnection *connection, const gchar *object_path, GError **error);
+void e_gdbus_cal_drain_notify (EGdbusCal *object);
+
+const GDBusInterfaceInfo *e_gdbus_cal_interface_info (void) G_GNUC_CONST;
+
+struct _EGdbusCalIface
+{
+	GTypeInterface parent_iface;
+
+	/* Signal handlers for receiving D-Bus signals: */
+	void	(*backend_error)			(EGdbusCal *object, const gchar *arg_message);
+	void	(*readonly)				(EGdbusCal *object, gboolean arg_is_readonly);
+	void	(*online)				(EGdbusCal *object, gboolean arg_is_online);
+	void	(*auth_required)			(EGdbusCal *object, const gchar * const *arg_credentials);
+	void	(*opened)				(EGdbusCal *object, const gchar * const *arg_error);
+	void	(*free_busy_data)			(EGdbusCal *object, const gchar * const *arg_free_busy);
+
+	/* Signal handlers for handling D-Bus method calls: */
+	gboolean (*handle_open)				(EGdbusCal *object, GDBusMethodInvocation *invocation, gboolean in_only_if_exists);
+	void	 (*open_done)				(EGdbusCal *object, guint arg_opid, const GError *arg_error);
+
+	gboolean (*handle_remove)			(EGdbusCal *object, GDBusMethodInvocation *invocation);
+	void	 (*remove_done)				(EGdbusCal *object, guint arg_opid, const GError *arg_error);
+
+	gboolean (*handle_refresh)			(EGdbusCal *object, GDBusMethodInvocation *invocation);
+	void	 (*refresh_done)			(EGdbusCal *object, guint arg_opid, const GError *arg_error);
+
+	gboolean (*handle_get_backend_property)		(EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar *in_prop_name);
+	void	 (*get_backend_property_done)		(EGdbusCal *object, guint arg_opid, const GError *arg_error, gchar **out_prop_value);
+
+	gboolean (*handle_set_backend_property)		(EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar * const *in_prop_name_value);
+	void	 (*set_backend_property_done)		(EGdbusCal *object, guint arg_opid, const GError *arg_error);
+
+	gboolean (*handle_get_object)			(EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar * const *in_uid_rid);
+	void	 (*get_object_done)			(EGdbusCal *object, guint arg_opid, const GError *arg_error, gchar **out_object);
+
+	gboolean (*handle_get_object_list)		(EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar *in_sexp);
+	void	 (*get_object_list_done)		(EGdbusCal *object, guint arg_opid, const GError *arg_error, gchar ***out_objects);
+
+	gboolean (*handle_get_free_busy)		(EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar * const *in_start_end_userlist);
+	void	 (*get_free_busy_done)			(EGdbusCal *object, guint arg_opid, const GError *arg_error);
+
+	gboolean (*handle_create_object)		(EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar *in_calobj);
+	void	 (*create_object_done)			(EGdbusCal *object, guint arg_opid, const GError *arg_error, gchar **out_uid);
+
+	gboolean (*handle_modify_object)		(EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar * const *in_calobj_mod);
+	void	 (*modify_object_done)			(EGdbusCal *object, guint arg_opid, const GError *arg_error);
+
+	gboolean (*handle_remove_object)		(EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar * const *in_uid_rid_mod);
+	void	 (*remove_object_done)			(EGdbusCal *object, guint arg_opid, const GError *arg_error);
+
+	gboolean (*handle_receive_objects)		(EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar *in_calobj);
+	void	 (*receive_objects_done)		(EGdbusCal *object, guint arg_opid, const GError *arg_error);
+
+	gboolean (*handle_send_objects)			(EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar *in_calobj);
+	void	 (*send_objects_done)			(EGdbusCal *object, guint arg_opid, const GError *arg_error, gchar ***out_calobj_users);
+
+	gboolean (*handle_get_attachment_uris)		(EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar * const *in_uid_rid);
+	void	 (*get_attachment_uris_done)		(EGdbusCal *object, guint arg_opid, const GError *arg_error, gchar ***out_attachments);
+
+	gboolean (*handle_discard_alarm)		(EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar * const *in_uid_rid_auid);
+	void	 (*discard_alarm_done)			(EGdbusCal *object, guint arg_opid, const GError *arg_error);
+
+	gboolean (*handle_get_view)			(EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar *in_sexp);
+	void	 (*get_view_done)			(EGdbusCal *object, guint arg_opid, const GError *arg_error, gchar **out_view_path);
+
+	gboolean (*handle_get_timezone)			(EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar *in_tzid);
+	void	 (*get_timezone_done)			(EGdbusCal *object, guint arg_opid, const GError *arg_error, gchar **out_tzobject);
+
+	gboolean (*handle_add_timezone)			(EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar *in_tzobject);
+	void	 (*add_timezone_done)			(EGdbusCal *object, guint arg_opid, const GError *arg_error);
+
+	gboolean (*handle_authenticate_user)		(EGdbusCal *object, GDBusMethodInvocation *invocation, const gchar * const *in_credentials);
+	gboolean (*handle_cancel_operation)		(EGdbusCal *object, GDBusMethodInvocation *invocation, guint in_opid);
+	gboolean (*handle_cancel_all)			(EGdbusCal *object, GDBusMethodInvocation *invocation);
+	gboolean (*handle_close)			(EGdbusCal *object, GDBusMethodInvocation *invocation);
+};
+
+/* D-Bus Methods */
+void		e_gdbus_cal_call_open				(GDBusProxy *proxy, gboolean in_only_if_exists, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_cal_call_open_finish			(GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_cal_call_open_sync			(GDBusProxy *proxy, gboolean in_only_if_exists, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_cal_call_remove				(GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_cal_call_remove_finish			(GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_cal_call_remove_sync			(GDBusProxy *proxy, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_cal_call_refresh			(GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_cal_call_refresh_finish			(GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_cal_call_refresh_sync			(GDBusProxy *proxy, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_cal_call_get_backend_property		(GDBusProxy *proxy, const gchar *in_prop_name, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_cal_call_get_backend_property_finish	(GDBusProxy *proxy, GAsyncResult *result, gchar **out_prop_value, GError **error);
+gboolean	e_gdbus_cal_call_get_backend_property_sync	(GDBusProxy *proxy, const gchar *in_prop_name, gchar **out_prop_value, GCancellable *cancellable, GError **error);
+
+gchar **	e_gdbus_cal_encode_set_backend_property		(const gchar *in_prop_name, const gchar *in_prop_value);
+gboolean	e_gdbus_cal_decode_set_backend_property		(const gchar * const *in_strv, gchar **out_prop_name, gchar **out_prop_value);
+void		e_gdbus_cal_call_set_backend_property		(GDBusProxy *proxy, const gchar * const *in_prop_name_value, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_cal_call_set_backend_property_finish	(GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_cal_call_set_backend_property_sync	(GDBusProxy *proxy, const gchar * const *in_prop_name_value, GCancellable *cancellable, GError **error);
+
+gchar **	e_gdbus_cal_encode_get_object			(const gchar *in_uid, const gchar *in_rid);
+gboolean	e_gdbus_cal_decode_get_object			(const gchar * const *in_strv, gchar **out_uid, gchar **out_rid);
+void		e_gdbus_cal_call_get_object			(GDBusProxy *proxy, const gchar * const *in_uid_rid, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_cal_call_get_object_finish		(GDBusProxy *proxy, GAsyncResult *result, gchar **out_object, GError **error);
+gboolean	e_gdbus_cal_call_get_object_sync		(GDBusProxy *proxy, const gchar * const *in_uid_rid, gchar **out_object, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_cal_call_get_object_list		(GDBusProxy *proxy, const gchar *in_sexp, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_cal_call_get_object_list_finish		(GDBusProxy *proxy, GAsyncResult *result, gchar ***out_objects, GError **error);
+gboolean	e_gdbus_cal_call_get_object_list_sync		(GDBusProxy *proxy, const gchar *in_sexp, gchar ***out_objects, GCancellable *cancellable, GError **error);
+
+gchar **	e_gdbus_cal_encode_get_free_busy		(guint in_start, guint in_end, const GSList *in_users);
+gboolean	e_gdbus_cal_decode_get_free_busy		(const gchar * const *in_strv, guint *out_start, guint *out_end, GSList **out_users);
+void		e_gdbus_cal_call_get_free_busy			(GDBusProxy *proxy, const gchar * const *in_start_end_userlist, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_cal_call_get_free_busy_finish		(GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_cal_call_get_free_busy_sync		(GDBusProxy *proxy, const gchar * const *in_start_end_userlist, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_cal_call_create_object			(GDBusProxy *proxy, const gchar *in_calobj, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_cal_call_create_object_finish		(GDBusProxy *proxy, GAsyncResult *result, gchar **out_uid, GError **error);
+gboolean	e_gdbus_cal_call_create_object_sync		(GDBusProxy *proxy, const gchar *in_calobj, gchar **out_uid, GCancellable *cancellable, GError **error);
+
+gchar **	e_gdbus_cal_encode_modify_object		(const gchar *in_calobj, guint in_mod);
+gboolean	e_gdbus_cal_decode_modify_object		(const gchar * const *in_strv, gchar **out_calobj, guint *out_mod);
+void		e_gdbus_cal_call_modify_object			(GDBusProxy *proxy, const gchar * const *in_calobj_mod, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_cal_call_modify_object_finish		(GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_cal_call_modify_object_sync		(GDBusProxy *proxy, const gchar * const *in_calobj_mod, GCancellable *cancellable, GError **error);
+
+gchar **	e_gdbus_cal_encode_remove_object		(const gchar *in_uid, const gchar *in_rid, guint in_mod);
+gboolean	e_gdbus_cal_decode_remove_object		(const gchar * const *in_strv, gchar **out_uid, gchar **out_rid, guint *out_mod);
+void		e_gdbus_cal_call_remove_object			(GDBusProxy *proxy, const gchar * const *in_uid_rid_mod, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_cal_call_remove_object_finish		(GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_cal_call_remove_object_sync		(GDBusProxy *proxy, const gchar * const *in_uid_rid_mod, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_cal_call_receive_objects		(GDBusProxy *proxy, const gchar *in_calobj, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_cal_call_receive_objects_finish		(GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_cal_call_receive_objects_sync		(GDBusProxy *proxy, const gchar *in_calobj, GCancellable *cancellable, GError **error);
+
+gchar **	e_gdbus_cal_encode_send_objects			(const gchar *in_calobj, const GSList *in_users);
+gboolean	e_gdbus_cal_decode_send_objects			(const gchar * const *in_strv, gchar **out_calobj, GSList **out_users);
+void		e_gdbus_cal_call_send_objects			(GDBusProxy *proxy, const gchar *in_calobj, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_cal_call_send_objects_finish		(GDBusProxy *proxy, GAsyncResult *result, gchar ***out_calobj_users, GError **error);
+gboolean	e_gdbus_cal_call_send_objects_sync		(GDBusProxy *proxy, const gchar *in_calobj, gchar ***out_calobj_users, GCancellable *cancellable, GError **error);
+
+gchar **	e_gdbus_cal_encode_get_attachment_uris		(const gchar *in_uid, const gchar *in_rid);
+gboolean	e_gdbus_cal_decode_get_attachment_uris		(const gchar * const *in_strv, gchar **out_uid, gchar **out_rid);
+void		e_gdbus_cal_call_get_attachment_uris		(GDBusProxy *proxy, const gchar * const *in_uid_rid, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_cal_call_get_attachment_uris_finish	(GDBusProxy *proxy, GAsyncResult *result, gchar ***out_attachments, GError **error);
+gboolean	e_gdbus_cal_call_get_attachment_uris_sync	(GDBusProxy *proxy, const gchar * const *in_uid_rid, gchar ***out_attachments, GCancellable *cancellable, GError **error);
+
+gchar **	e_gdbus_cal_encode_discard_alarm		(const gchar *in_uid, const gchar *in_rid, const gchar *in_auid);
+gboolean	e_gdbus_cal_decode_discard_alarm		(const gchar * const *in_strv, gchar **out_uid, gchar **out_rid, gchar **out_auid);
+void		e_gdbus_cal_call_discard_alarm			(GDBusProxy *proxy, const gchar * const *in_uid_rid_auid, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_cal_call_discard_alarm_finish		(GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_cal_call_discard_alarm_sync		(GDBusProxy *proxy, const gchar * const *in_uid_rid_auid, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_cal_call_get_view			(GDBusProxy *proxy, const gchar *in_sexp, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_cal_call_get_view_finish		(GDBusProxy *proxy, GAsyncResult *result, gchar **out_view_path, GError **error);
+gboolean	e_gdbus_cal_call_get_view_sync			(GDBusProxy *proxy, const gchar *in_sexp, gchar **out_view_path, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_cal_call_get_timezone			(GDBusProxy *proxy, const gchar *in_tzid, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_cal_call_get_timezone_finish		(GDBusProxy *proxy, GAsyncResult *result, gchar **out_tzobject, GError **error);
+gboolean	e_gdbus_cal_call_get_timezone_sync		(GDBusProxy *proxy, const gchar *in_tzid, gchar **out_tzobject, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_cal_call_add_timezone			(GDBusProxy *proxy, const gchar *in_tzobject, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_cal_call_add_timezone_finish		(GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_cal_call_add_timezone_sync		(GDBusProxy *proxy, const gchar *in_tzobject, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_cal_call_authenticate_user		(GDBusProxy *proxy, const gchar * const *in_credentials, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_cal_call_authenticate_user_finish	(GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_cal_call_authenticate_user_sync		(GDBusProxy *proxy, const gchar * const *in_credentials, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_cal_call_cancel_operation		(GDBusProxy *proxy, guint in_opid, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_cal_call_cancel_operation_finish	(GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_cal_call_cancel_operation_sync		(GDBusProxy *proxy, guint in_opid, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_cal_call_cancel_all			(GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_cal_call_cancel_all_finish		(GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_cal_call_cancel_all_sync		(GDBusProxy *proxy, GCancellable *cancellable, GError **error);
+
+void		e_gdbus_cal_call_close				(GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_gdbus_cal_call_close_finish			(GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean	e_gdbus_cal_call_close_sync			(GDBusProxy *proxy, GCancellable *cancellable, GError **error);
+
+/* D-Bus Methods Completion Helpers */
+#define e_gdbus_cal_complete_open			e_gdbus_complete_async_method
+#define e_gdbus_cal_complete_remove			e_gdbus_complete_async_method
+#define e_gdbus_cal_complete_refresh			e_gdbus_complete_async_method
+#define e_gdbus_cal_complete_get_backend_property	e_gdbus_complete_async_method
+#define e_gdbus_cal_complete_set_backend_property	e_gdbus_complete_async_method
+#define e_gdbus_cal_complete_get_object			e_gdbus_complete_async_method
+#define e_gdbus_cal_complete_get_object_list		e_gdbus_complete_async_method
+#define e_gdbus_cal_complete_get_free_busy		e_gdbus_complete_async_method
+#define e_gdbus_cal_complete_create_object		e_gdbus_complete_async_method
+#define e_gdbus_cal_complete_modify_object		e_gdbus_complete_async_method
+#define e_gdbus_cal_complete_remove_object		e_gdbus_complete_async_method
+#define e_gdbus_cal_complete_receive_objects		e_gdbus_complete_async_method
+#define e_gdbus_cal_complete_send_objects		e_gdbus_complete_async_method
+#define e_gdbus_cal_complete_get_attachment_uris	e_gdbus_complete_async_method
+#define e_gdbus_cal_complete_discard_alarm		e_gdbus_complete_async_method
+#define e_gdbus_cal_complete_get_view			e_gdbus_complete_async_method
+#define e_gdbus_cal_complete_get_timezone		e_gdbus_complete_async_method
+#define e_gdbus_cal_complete_add_timezone		e_gdbus_complete_async_method
+#define e_gdbus_cal_complete_authenticate_user		e_gdbus_complete_sync_method_void
+#define e_gdbus_cal_complete_cancel_operation		e_gdbus_complete_sync_method_void
+#define e_gdbus_cal_complete_cancel_all			e_gdbus_complete_sync_method_void
+#define e_gdbus_cal_complete_close			e_gdbus_complete_sync_method_void
+
+void e_gdbus_cal_emit_open_done				(EGdbusCal *object, guint arg_opid, const GError *arg_error);
+void e_gdbus_cal_emit_remove_done			(EGdbusCal *object, guint arg_opid, const GError *arg_error);
+void e_gdbus_cal_emit_refresh_done			(EGdbusCal *object, guint arg_opid, const GError *arg_error);
+void e_gdbus_cal_emit_get_backend_property_done		(EGdbusCal *object, guint arg_opid, const GError *arg_error, const gchar *out_prop_value);
+void e_gdbus_cal_emit_set_backend_property_done		(EGdbusCal *object, guint arg_opid, const GError *arg_error);
+void e_gdbus_cal_emit_get_object_done			(EGdbusCal *object, guint arg_opid, const GError *arg_error, const gchar *out_object);
+void e_gdbus_cal_emit_get_object_list_done		(EGdbusCal *object, guint arg_opid, const GError *arg_error, const gchar * const *out_objects);
+void e_gdbus_cal_emit_get_free_busy_done		(EGdbusCal *object, guint arg_opid, const GError *arg_error);
+void e_gdbus_cal_emit_get_free_busy_data		(EGdbusCal *object, guint arg_opid, const GError *arg_error, const gchar * const *out_freebusy);
+void e_gdbus_cal_emit_create_object_done		(EGdbusCal *object, guint arg_opid, const GError *arg_error, const gchar *out_uid);
+void e_gdbus_cal_emit_modify_object_done		(EGdbusCal *object, guint arg_opid, const GError *arg_error);
+void e_gdbus_cal_emit_remove_object_done		(EGdbusCal *object, guint arg_opid, const GError *arg_error);
+void e_gdbus_cal_emit_receive_objects_done		(EGdbusCal *object, guint arg_opid, const GError *arg_error);
+void e_gdbus_cal_emit_send_objects_done			(EGdbusCal *object, guint arg_opid, const GError *arg_error, const gchar * const *out_calobj_users);
+void e_gdbus_cal_emit_get_attachment_uris_done		(EGdbusCal *object, guint arg_opid, const GError *arg_error, const gchar * const *out_attachments);
+void e_gdbus_cal_emit_discard_alarm_done		(EGdbusCal *object, guint arg_opid, const GError *arg_error);
+void e_gdbus_cal_emit_get_view_done			(EGdbusCal *object, guint arg_opid, const GError *arg_error, const gchar *out_view_path);
+void e_gdbus_cal_emit_get_timezone_done			(EGdbusCal *object, guint arg_opid, const GError *arg_error, const gchar *out_object);
+void e_gdbus_cal_emit_add_timezone_done			(EGdbusCal *object, guint arg_opid, const GError *arg_error);
+
+/* D-Bus Signal Emission Helpers */
+void e_gdbus_cal_emit_backend_error	(EGdbusCal *object, const gchar *arg_message);
+void e_gdbus_cal_emit_readonly		(EGdbusCal *object, gboolean arg_is_readonly);
+void e_gdbus_cal_emit_online		(EGdbusCal *object, gint arg_is_online);
+void e_gdbus_cal_emit_auth_required	(EGdbusCal *object, const gchar * const *arg_credentials);
+void e_gdbus_cal_emit_opened		(EGdbusCal *object, const gchar * const *arg_error);
+void e_gdbus_cal_emit_free_busy_data	(EGdbusCal *object, const gchar * const *arg_free_busy);
+
+G_END_DECLS
+
+#endif /* E_GDBUS_CAL_H */
diff --git a/configure.ac b/configure.ac
index 5742537..5c85b29 100644
--- a/configure.ac
+++ b/configure.ac
@@ -55,8 +55,8 @@ EDS_MICRO_VERSION=eds_micro_version
 dnl ******************************
 dnl D-Bus versioning
 dnl ******************************
-ADDRESS_BOOK_DBUS_SERVICE_NAME="org.gnome.evolution.dataserver.AddressBook0"
-CALENDAR_DBUS_SERVICE_NAME="org.gnome.evolution.dataserver.Calendar0"
+ADDRESS_BOOK_DBUS_SERVICE_NAME="org.gnome.evolution.dataserver.AddressBook1"
+CALENDAR_DBUS_SERVICE_NAME="org.gnome.evolution.dataserver.Calendar1"
 
 AC_DEFINE_UNQUOTED(
        ADDRESS_BOOK_DBUS_SERVICE_NAME,
@@ -82,19 +82,19 @@ LIBEDATASERVERUI_CURRENT=0
 LIBEDATASERVERUI_REVISION=0
 LIBEDATASERVERUI_AGE=0
 
-LIBECAL_CURRENT=10
+LIBECAL_CURRENT=11
 LIBECAL_REVISION=2
 LIBECAL_AGE=2
 
-LIBEDATACAL_CURRENT=11
+LIBEDATACAL_CURRENT=12
 LIBEDATACAL_REVISION=0
 LIBEDATACAL_AGE=0
 
-LIBEDATABOOK_CURRENT=9
+LIBEDATABOOK_CURRENT=10
 LIBEDATABOOK_REVISION=0
 LIBEDATABOOK_AGE=0
 
-LIBEBOOK_CURRENT=13
+LIBEBOOK_CURRENT=14
 LIBEBOOK_REVISION=1
 LIBEBOOK_AGE=3
 
@@ -1505,8 +1505,10 @@ libedataserverui/Makefile
 libedataserverui/libedataserverui.pc
 tests/Makefile
 tests/libebook/Makefile
+tests/libebook/client/Makefile
 tests/libebook/vcard/Makefile
 tests/libecal/Makefile
+tests/libecal/client/Makefile
 tests/libedata-cal/Makefile
 tests/libedataserver/Makefile
 tests/libedataserverui/Makefile
diff --git a/libedataserver/Makefile.am b/libedataserver/Makefile.am
index 4cc32fb..4253781 100644
--- a/libedataserver/Makefile.am
+++ b/libedataserver/Makefile.am
@@ -1,3 +1,7 @@
+# The marshallers
+MARSHAL_GENERATED = e-gdbus-marshallers.c e-gdbus-marshallers.h
+ EVO_MARSHAL_RULE@
+
 lib_LTLIBRARIES = libedataserver-1.2.la
 
 libedataserver_1_2_la_CPPFLAGS = \
@@ -14,14 +18,21 @@ libedataserver_1_2_la_CPPFLAGS = \
 	$(SOUP_CFLAGS)
 
 libedataserver_1_2_la_SOURCES =		\
+	$(MARSHAL_GENERATED)		\
 	e-account-list.c		\
 	e-account.c			\
 	e-categories.c			\
+	e-client.c			\
+	e-client-private.h		\
+	e-credentials.c			\
 	e-flag.c			\
+	e-gdbus-templates.h		\
+	e-gdbus-templates.c		\
 	e-iterator.c			\
 	e-list.c			\
 	e-list-iterator.c		\
 	e-memory.c			\
+	e-operation-pool.c		\
 	e-proxy.c			\
 	e-sexp.c			\
 	e-source-group.c		\
@@ -52,11 +63,14 @@ libedataserverinclude_HEADERS =		\
 	e-account-list.h		\
 	e-account.h			\
 	e-categories.h			\
+	e-client.h			\
+	e-credentials.h			\
 	e-flag.h			\
 	e-iterator.h			\
 	e-list.h			\
 	e-list-iterator.h		\
 	e-memory.h			\
+	e-operation-pool.h		\
 	e-proxy.h			\
 	e-sexp.h			\
 	e-source-group.h		\
@@ -81,7 +95,8 @@ EXTRA_DIST = 						\
 	$(pkgconfig_DATA:-$(API_VERSION).pc=.pc.in)	\
 	eds-version.h.in
 
-CLEANFILES =
+BUILT_SOURCES = $(MARSHAL_GENERATED)
+CLEANFILES = $(BUILT_SOURCES)
 DISTCLEANFILES = eds-version.h $(pkgconfig_DATA)
 
 -include $(INTROSPECTION_MAKEFILE)
diff --git a/libedataserver/e-client-private.h b/libedataserver/e-client-private.h
new file mode 100644
index 0000000..71091bf
--- /dev/null
+++ b/libedataserver/e-client-private.h
@@ -0,0 +1,122 @@
+/*
+ * e-client-private.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 2011 Red Hat, Inc. (www.redhat.com)
+ *
+ */
+
+#ifndef E_CLIENT_PRIVATE_H
+#define E_CLIENT_PRIVATE_H
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#include "libedataserver/e-credentials.h"
+#include "libedataserver/e-source.h"
+#include "libedataserver/e-source-list.h"
+#include "libedataserver/e-client.h"
+
+G_BEGIN_DECLS
+
+void		e_client_set_capabilities	(EClient *client, const gchar *capabilities);
+void		e_client_set_readonly		(EClient *client, gboolean readonly);
+void		e_client_set_online		(EClient *client, gboolean is_online);
+guint32		e_client_register_op		(EClient *client, GCancellable *cancellable);
+void		e_client_unregister_op		(EClient *client, guint32 opid);
+void		e_client_process_authentication	(EClient *client, const ECredentials *credentials);
+
+gboolean	e_client_emit_authenticate	(EClient *client, ECredentials *credentials);
+void		e_client_emit_opened		(EClient *client, const GError *error);
+void		e_client_emit_backend_error	(EClient *client, const gchar *error_msg);
+void		e_client_emit_backend_died	(EClient *client);
+
+ESource *	e_client_util_get_system_source	(ESourceList *source_list);
+gboolean	e_client_util_set_default	(ESourceList *source_list, ESource *source);
+ESource *	e_client_util_get_source_for_uri(ESourceList *source_list, const gchar *uri);
+
+/* protected functions simplifying sync/async calls */
+GDBusProxy *	e_client_get_dbus_proxy		(EClient *client);
+void		e_client_unwrap_dbus_error	(EClient *client, GError *dbus_error, GError **out_error);
+
+void		e_client_proxy_return_async_error	(EClient *client, const GError *error, GAsyncReadyCallback callback, gpointer user_data, gpointer source_tag);
+
+#define e_client_return_async_if_fail(_expr, _client, _callback, _user_data, _source_tag)	\
+	G_STMT_START {										\
+		if (!G_LIKELY (_expr)) {							\
+			GError *error;								\
+												\
+			error = g_error_new (							\
+				E_CLIENT_ERROR, E_CLIENT_ERROR_INVALID_ARG,			\
+				"file %s:%d: %s: assertion `%s' failed",			\
+				__FILE__, __LINE__, G_STRFUNC, # _expr);			\
+												\
+			g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "%s", error->message);	\
+												\
+			e_client_proxy_return_async_error (					\
+				_client, error, _callback, _user_data, _source_tag);		\
+												\
+			g_error_free (error);							\
+		}										\
+	} G_STMT_END
+
+typedef gboolean (* EClientProxyFinishVoidFunc)		(GDBusProxy *proxy, GAsyncResult *result, GError **error);
+typedef gboolean (* EClientProxyFinishBooleanFunc)	(GDBusProxy *proxy, GAsyncResult *result, gboolean *out_boolean, GError **error);
+typedef gboolean (* EClientProxyFinishStringFunc)	(GDBusProxy *proxy, GAsyncResult *result, gchar **out_string, GError **error);
+typedef gboolean (* EClientProxyFinishStrvFunc)		(GDBusProxy *proxy, GAsyncResult *result, gchar ***out_strv, GError **error);
+typedef gboolean (* EClientProxyFinishUintFunc)		(GDBusProxy *proxy, GAsyncResult *result, guint *out_uint, GError **error);
+
+void		e_client_proxy_call_void	(EClient *client, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data, gpointer source_tag, void (*func) (GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data), EClientProxyFinishVoidFunc finish_void, EClientProxyFinishBooleanFunc finish_boolean, EClientProxyFinishStringFunc finish_string, EClientProxyFinishStrvFunc finish_strv, EClientProxyFinishUintFunc finish_uint);
+void		e_client_proxy_call_boolean	(EClient *client, gboolean in_boolean, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data, gpointer source_tag, void (*func) (GDBusProxy *proxy, gboolean in_boolean, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data), EClientProxyFinishVoidFunc finish_void, EClientProxyFinishBooleanFunc finish_boolean, EClientProxyFinishStringFunc finish_string, EClientProxyFinishStrvFunc finish_strv, EClientProxyFinishUintFunc finish_uint);
+void		e_client_proxy_call_string	(EClient *client, const gchar *in_string, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data, gpointer source_tag, void (*func) (GDBusProxy *proxy, const gchar * in_string, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data), EClientProxyFinishVoidFunc finish_void, EClientProxyFinishBooleanFunc finish_boolean, EClientProxyFinishStringFunc finish_string, EClientProxyFinishStrvFunc finish_strv, EClientProxyFinishUintFunc finish_uint);
+void		e_client_proxy_call_strv	(EClient *client, const gchar * const *in_strv, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data, gpointer source_tag, void (*func) (GDBusProxy *proxy, const gchar * const * in_strv, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data), EClientProxyFinishVoidFunc finish_void, EClientProxyFinishBooleanFunc finish_boolean, EClientProxyFinishStringFunc finish_string, EClientProxyFinishStrvFunc finish_strv, EClientProxyFinishUintFunc finish_uint);
+void		e_client_proxy_call_uint	(EClient *client, guint in_uint, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data, gpointer source_tag, void (*func) (GDBusProxy *proxy, guint in_uint, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data), EClientProxyFinishVoidFunc finish_void, EClientProxyFinishBooleanFunc finish_boolean, EClientProxyFinishStringFunc finish_string, EClientProxyFinishStrvFunc finish_strv, EClientProxyFinishUintFunc finish_uint);
+
+gboolean	e_client_proxy_call_finish_void		(EClient *client, GAsyncResult *result, GError **error, gpointer source_tag);
+gboolean	e_client_proxy_call_finish_boolean	(EClient *client, GAsyncResult *result, gboolean *out_boolean, GError **error, gpointer source_tag);
+gboolean	e_client_proxy_call_finish_string	(EClient *client, GAsyncResult *result, gchar **out_string, GError **error, gpointer source_tag);
+gboolean	e_client_proxy_call_finish_strv		(EClient *client, GAsyncResult *result, gchar ***out_strv, GError **error, gpointer source_tag);
+gboolean	e_client_proxy_call_finish_uint		(EClient *client, GAsyncResult *result, guint *out_uint, GError **error, gpointer source_tag);
+
+gboolean	e_client_proxy_call_sync_void__void		(EClient *client, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, GCancellable *cancellable, GError **error));
+gboolean	e_client_proxy_call_sync_void__boolean		(EClient *client, gboolean *out_boolean, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, gboolean *out_boolean, GCancellable *cancellable, GError **error));
+gboolean	e_client_proxy_call_sync_void__string		(EClient *client, gchar **out_string, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, gchar **out_string, GCancellable *cancellable, GError **error));
+gboolean	e_client_proxy_call_sync_void__strv		(EClient *client, gchar ***out_strv, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, gchar ***out_strv, GCancellable *cancellable, GError **error));
+gboolean	e_client_proxy_call_sync_void__uint		(EClient *client, guint *out_uint, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, guint *out_uint, GCancellable *cancellable, GError **error));
+gboolean	e_client_proxy_call_sync_boolean__void		(EClient *client, gboolean in_boolean, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, gboolean in_boolean, GCancellable *cancellable, GError **error));
+gboolean	e_client_proxy_call_sync_boolean__boolean	(EClient *client, gboolean in_boolean, gboolean *out_boolean, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, gboolean in_boolean, gboolean *out_boolean, GCancellable *cancellable, GError **error));
+gboolean	e_client_proxy_call_sync_boolean__string	(EClient *client, gboolean in_boolean, gchar **out_string, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, gboolean in_boolean, gchar **out_string, GCancellable *cancellable, GError **error));
+gboolean	e_client_proxy_call_sync_boolean__strv		(EClient *client, gboolean in_boolean, gchar ***out_strv, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, gboolean in_boolean, gchar ***out_strv, GCancellable *cancellable, GError **error));
+gboolean	e_client_proxy_call_sync_boolean__uint		(EClient *client, gboolean in_boolean, guint *out_uint, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, gboolean in_boolean, guint *out_uint, GCancellable *cancellable, GError **error));
+gboolean	e_client_proxy_call_sync_string__void		(EClient *client, const gchar *in_string, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, const gchar *in_string, GCancellable *cancellable, GError **error));
+gboolean	e_client_proxy_call_sync_string__boolean	(EClient *client, const gchar *in_string, gboolean *out_boolean, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, const gchar *in_string, gboolean *out_boolean, GCancellable *cancellable, GError **error));
+gboolean	e_client_proxy_call_sync_string__string		(EClient *client, const gchar *in_string, gchar **out_string, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, const gchar *in_string, gchar **out_string, GCancellable *cancellable, GError **error));
+gboolean	e_client_proxy_call_sync_string__strv		(EClient *client, const gchar *in_string, gchar ***out_strv, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, const gchar *in_string, gchar ***out_strv, GCancellable *cancellable, GError **error));
+gboolean	e_client_proxy_call_sync_string__uint		(EClient *client, const gchar *in_string, guint *out_uint, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, const gchar *in_string, guint *out_uint, GCancellable *cancellable, GError **error));
+gboolean	e_client_proxy_call_sync_strv__void		(EClient *client, const gchar * const *in_strv, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, const gchar * const *in_strv, GCancellable *cancellable, GError **error));
+gboolean	e_client_proxy_call_sync_strv__boolean		(EClient *client, const gchar * const *in_strv, gboolean *out_boolean, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, const gchar * const *in_strv, gboolean *out_boolean, GCancellable *cancellable, GError **error));
+gboolean	e_client_proxy_call_sync_strv__string		(EClient *client, const gchar * const *in_strv, gchar **out_string, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, const gchar * const *in_strv, gchar **out_string, GCancellable *cancellable, GError **error));
+gboolean	e_client_proxy_call_sync_strv__strv		(EClient *client, const gchar * const *in_strv, gchar ***out_strv, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, const gchar * const *in_strv, gchar ***out_strv, GCancellable *cancellable, GError **error));
+gboolean	e_client_proxy_call_sync_strv__uint		(EClient *client, const gchar * const *in_strv, guint *out_uint, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, const gchar * const *in_strv, guint *out_uint, GCancellable *cancellable, GError **error));
+gboolean	e_client_proxy_call_sync_uint__void		(EClient *client, guint in_uint, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, guint in_uint, GCancellable *cancellable, GError **error));
+gboolean	e_client_proxy_call_sync_uint__boolean		(EClient *client, guint in_uint, gboolean *out_boolean, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, guint in_uint, gboolean *out_boolean, GCancellable *cancellable, GError **error));
+gboolean	e_client_proxy_call_sync_uint__string		(EClient *client, guint in_uint, gchar **out_string, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, guint in_uint, gchar **out_string, GCancellable *cancellable, GError **error));
+gboolean	e_client_proxy_call_sync_uint__strv		(EClient *client, guint in_uint, gchar ***out_strv, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, guint in_uint, gchar ***out_strv, GCancellable *cancellable, GError **error));
+gboolean	e_client_proxy_call_sync_uint__uint		(EClient *client, guint in_uint, guint *out_uint, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, guint in_uint, guint *out_uint, GCancellable *cancellable, GError **error));
+
+G_END_DECLS
+
+#endif /* E_CLIENT_PRIVATE_H */
diff --git a/libedataserver/e-client.c b/libedataserver/e-client.c
new file mode 100644
index 0000000..6d16d47
--- /dev/null
+++ b/libedataserver/e-client.c
@@ -0,0 +1,2489 @@
+/*
+ * e-client.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 2011 Red Hat, Inc. (www.redhat.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <gio/gio.h>
+
+#include "e-gdbus-marshallers.h"
+#include "e-operation-pool.h"
+
+#include "e-client.h"
+#include "e-client-private.h"
+
+struct _EClientPrivate
+{
+	GStaticRecMutex prop_mutex;
+
+	ESource *source;
+	gchar *uri;
+	gboolean online;
+	gboolean readonly;
+	gboolean opened;
+	gboolean capabilities_retrieved;
+	GSList *capabilities;
+
+	GStaticRecMutex ops_mutex;
+	guint32 last_opid;
+	GHashTable *ops; /* opid to GCancellable */
+};
+
+enum {
+	PROP_0,
+	PROP_SOURCE,
+	PROP_CAPABILITIES,
+	PROP_READONLY,
+	PROP_ONLINE,
+	PROP_OPENED
+};
+
+enum {
+	AUTHENTICATE,
+	OPENED,
+	BACKEND_ERROR,
+	BACKEND_DIED,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+static EOperationPool *ops_pool = NULL;
+
+G_DEFINE_ABSTRACT_TYPE (EClient, e_client, G_TYPE_OBJECT)
+
+/**
+ * Well-known client backend properties, which are common for each #EClient:
+ * @CLIENT_BACKEND_PROPERTY_OPENED: Is set to "TRUE" or "FALSE" depending
+ *   whether the backend is fully opened.
+ * @CLIENT_BACKEND_PROPERTY_OPENING: Is set to "TRUE" or "FALSE" depending
+ *   whether the backend is processing its opening phase.
+ * @CLIENT_BACKEND_PROPERTY_ONLINE: Is set to "TRUE" or "FALSE" depending
+ *   on the backend's loaded state. See also e_client_is_online().
+ * @CLIENT_BACKEND_PROPERTY_READONLY: Is set to "TRUE" or "FALSE" depending
+ *   on the backend's readonly state. See also e_client_is_readonly().
+ * @CLIENT_BACKEND_PROPERTY_CACHE_DIR: Local folder with cached data used
+ *   by the backend.
+ * @CLIENT_BACKEND_PROPERTY_CAPABILITIES: Retrieves comma-separated list
+ *   of	capabilities supported by the backend. Preferred method of retreiving
+ *   and working with capabilities is e_client_get_capabilities() and
+ *   e_client_check_capability().
+ **/
+
+GQuark
+e_client_error_quark (void)
+{
+	static GQuark q = 0;
+
+	if (q == 0)
+		q = g_quark_from_static_string ("e-client-error-quark");
+
+	return q;
+}
+
+const gchar *
+e_client_error_to_string (EClientError code)
+{
+	switch (code) {
+	case E_CLIENT_ERROR_INVALID_ARG:
+		return C_("ClientError", "Invalid argument");
+	case E_CLIENT_ERROR_BUSY:
+		return C_("ClientError", "Backend is busy");
+	case E_CLIENT_ERROR_SOURCE_NOT_LOADED:
+		return C_("ClientError", "Source not loaded");
+	case E_CLIENT_ERROR_SOURCE_ALREADY_LOADED:
+		return C_("ClientError", "Source already loaded");
+	case E_CLIENT_ERROR_AUTHENTICATION_FAILED:
+		return C_("ClientError", "Authentication failed");
+	case E_CLIENT_ERROR_AUTHENTICATION_REQUIRED:
+		return C_("ClientError", "Authentication required");
+	case E_CLIENT_ERROR_REPOSITORY_OFFLINE:
+		return C_("ClientError", "Repository offline");
+	case E_CLIENT_ERROR_PERMISSION_DENIED:
+		return C_("ClientError", "Permission denied");
+	case E_CLIENT_ERROR_CANCELLED:
+		return C_("ClientError", "Cancelled");
+	case E_CLIENT_ERROR_COULD_NOT_CANCEL:
+		return C_("ClientError", "Could not cancel");
+	case E_CLIENT_ERROR_NOT_SUPPORTED:
+		return C_("ClientError", "Not supported");
+	case E_CLIENT_ERROR_DBUS_ERROR:
+		return C_("ClientError", "D-Bus error");
+	case E_CLIENT_ERROR_OTHER_ERROR:
+		return C_("ClientError", "Other error");
+	}
+
+	return C_("ClientError", "Unknown error");
+}
+
+static void client_set_source (EClient *client, ESource *source);
+static void client_operation_thread (gpointer data, gpointer user_data);
+static void client_handle_authentication (EClient *client, const ECredentials *credentials);
+
+static void
+e_client_init (EClient *client)
+{
+	client->priv = G_TYPE_INSTANCE_GET_PRIVATE (client, E_TYPE_CLIENT, EClientPrivate);
+
+	client->priv->readonly = TRUE;
+
+	g_static_rec_mutex_init (&client->priv->prop_mutex);
+
+	g_static_rec_mutex_init (&client->priv->ops_mutex);
+	client->priv->last_opid = 0;
+	client->priv->ops = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
+}
+
+static void
+client_dispose (GObject *object)
+{
+	EClient *client;
+
+	client = E_CLIENT (object);
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (client->priv != NULL);
+
+	e_client_cancel_all (client);
+
+	/* Chain up to parent's dispose() method. */
+	G_OBJECT_CLASS (e_client_parent_class)->dispose (object);
+}
+
+static void
+client_finalize (GObject *object)
+{
+	EClient *client;
+	EClientPrivate *priv;
+
+	client = E_CLIENT (object);
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (client->priv != NULL);
+
+	priv = client->priv;
+
+	g_static_rec_mutex_lock (&priv->prop_mutex);
+
+	if (priv->source) {
+		g_object_unref (priv->source);
+		priv->source = NULL;
+	}
+
+	if (priv->uri) {
+		g_free (priv->uri);
+		priv->uri = NULL;
+	}
+
+	if (priv->capabilities) {
+		g_slist_foreach (priv->capabilities, (GFunc) g_free, NULL);
+		g_slist_free (priv->capabilities);
+		priv->capabilities = NULL;
+	}
+
+	if (priv->ops) {
+		g_hash_table_destroy (priv->ops);
+		priv->ops = NULL;
+	}
+
+	g_static_rec_mutex_unlock (&priv->prop_mutex);
+	g_static_rec_mutex_free (&priv->prop_mutex);
+	g_static_rec_mutex_free (&priv->ops_mutex);
+
+	/* Chain up to parent's finalize() method. */
+	G_OBJECT_CLASS (e_client_parent_class)->finalize (object);
+}
+
+static void
+client_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_SOURCE:
+			client_set_source (E_CLIENT (object), g_value_get_object (value));
+			return;
+
+		case PROP_ONLINE:
+			e_client_set_online (E_CLIENT (object), g_value_get_boolean (value));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+client_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
+{
+	switch (property_id) {
+		case PROP_SOURCE:
+			g_value_set_object (value, e_client_get_source (E_CLIENT (object)));
+			return;
+
+		case PROP_CAPABILITIES:
+			g_value_set_pointer (value, (gpointer) e_client_get_capabilities (E_CLIENT (object)));
+			return;
+
+		case PROP_READONLY:
+			g_value_set_boolean (value, e_client_is_readonly (E_CLIENT (object)));
+			return;
+
+		case PROP_ONLINE:
+			g_value_set_boolean (value, e_client_is_online (E_CLIENT (object)));
+			return;
+
+		case PROP_OPENED:
+			g_value_set_boolean (value, e_client_is_opened (E_CLIENT (object)));
+			return;
+	}
+
+	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+e_client_class_init (EClientClass *klass)
+{
+	GObjectClass *object_class;
+
+	g_type_class_add_private (klass, sizeof (EClientPrivate));
+
+	object_class = G_OBJECT_CLASS (klass);
+	object_class->set_property = client_set_property;
+	object_class->get_property = client_get_property;
+	object_class->dispose = client_dispose;
+	object_class->finalize = client_finalize;
+
+	g_object_class_install_property (
+		object_class,
+		PROP_SOURCE,
+		g_param_spec_object (
+			"source",
+			NULL,
+			NULL,
+			E_TYPE_SOURCE,
+			G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_CAPABILITIES,
+		g_param_spec_pointer (
+			"capabilities",
+			NULL,
+			NULL,
+			G_PARAM_READABLE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_READONLY,
+		g_param_spec_boolean (
+			"readonly",
+			NULL,
+			NULL,
+			FALSE,
+			G_PARAM_READABLE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_ONLINE,
+		g_param_spec_boolean (
+			"online",
+			NULL,
+			NULL,
+			FALSE,
+			G_PARAM_READWRITE));
+
+	g_object_class_install_property (
+		object_class,
+		PROP_OPENED,
+		g_param_spec_boolean (
+			"opened",
+			NULL,
+			NULL,
+			FALSE,
+			G_PARAM_READABLE));
+
+	signals[AUTHENTICATE] = g_signal_new (
+		"authenticate",
+		G_OBJECT_CLASS_TYPE (klass),
+		G_SIGNAL_RUN_LAST,
+		G_STRUCT_OFFSET (EClientClass, authenticate),
+		NULL, NULL,
+		e_gdbus_marshallers_BOOLEAN__POINTER,
+		G_TYPE_BOOLEAN, 1,
+		G_TYPE_POINTER);
+
+	signals[OPENED] = g_signal_new (
+		"opened",
+		G_OBJECT_CLASS_TYPE (klass),
+		G_SIGNAL_RUN_LAST,
+		G_STRUCT_OFFSET (EClientClass, opened),
+		NULL, NULL,
+		g_cclosure_marshal_VOID__BOXED,
+		G_TYPE_NONE, 1,
+		G_TYPE_ERROR);
+
+
+	signals[BACKEND_ERROR] = g_signal_new (
+		"backend-error",
+		G_OBJECT_CLASS_TYPE (klass),
+		G_SIGNAL_RUN_FIRST,
+		G_STRUCT_OFFSET (EClientClass, backend_error),
+		NULL, NULL,
+		g_cclosure_marshal_VOID__STRING,
+		G_TYPE_NONE, 1,
+		G_TYPE_STRING);
+
+	signals[BACKEND_DIED] = g_signal_new (
+		"backend-died",
+		G_OBJECT_CLASS_TYPE (klass),
+		G_SIGNAL_RUN_LAST,
+		G_STRUCT_OFFSET (EClientClass, backend_died),
+		NULL, NULL,
+		g_cclosure_marshal_VOID__VOID,
+		G_TYPE_NONE, 0);
+
+	if (!ops_pool)
+		ops_pool = e_operation_pool_new (2, client_operation_thread, NULL);
+}
+
+typedef enum {
+	E_CLIENT_OP_AUTHENTICATE
+} EClientOp;
+
+typedef struct _EClientOpData {
+	EClient *client;
+	EClientOp op;
+
+	union {
+		ECredentials *credentials;
+	} d;
+} EClientOpData;
+
+static void
+client_operation_thread (gpointer data, gpointer user_data)
+{
+	EClientOpData *op_data = data;
+
+	g_return_if_fail (op_data != NULL);
+
+	switch (op_data->op) {
+	case E_CLIENT_OP_AUTHENTICATE:
+		if (e_client_emit_authenticate (op_data->client, op_data->d.credentials)) {
+			client_handle_authentication (op_data->client, op_data->d.credentials);
+		} else {
+			GError *error;
+
+			error = g_error_new_literal (E_CLIENT_ERROR, E_CLIENT_ERROR_AUTHENTICATION_REQUIRED, e_client_error_to_string (E_CLIENT_ERROR_AUTHENTICATION_REQUIRED));
+			e_client_emit_opened (op_data->client, error);
+			g_error_free (error);
+		}
+		e_credentials_free (op_data->d.credentials);
+		break;
+	}
+
+	g_object_unref (op_data->client);
+	g_free (op_data);
+}
+
+static void
+client_set_source (EClient *client, ESource *source)
+{
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CLIENT (client));
+	g_return_if_fail (client->priv != NULL);
+	g_return_if_fail (source != NULL);
+	g_return_if_fail (E_IS_SOURCE (source));
+
+	g_object_ref (source);
+
+	if (client->priv->source)
+		g_object_unref (client->priv->source);
+
+	client->priv->source = source;
+}
+
+/**
+ * e_client_get_source:
+ * @client: an #EClient
+ *
+ * Get the #ESource that this client has assigned.
+ *
+ * Returns: The source.
+ *
+ * Since: 3.2
+ **/
+ESource *
+e_client_get_source (EClient *client)
+{
+	g_return_val_if_fail (client != NULL, NULL);
+	g_return_val_if_fail (E_IS_CLIENT (client), NULL);
+	g_return_val_if_fail (client->priv != NULL, NULL);
+
+	return client->priv->source;
+}
+
+/**
+ * e_client_get_uri:
+ * @client: an #EClient
+ *
+ * Get the URI that this client has assigned. This string should not be freed.
+ *
+ * Returns: The URI.
+ *
+ * Since: 3.2
+ **/
+const gchar *
+e_client_get_uri (EClient *client)
+{
+	g_return_val_if_fail (client != NULL, NULL);
+	g_return_val_if_fail (E_IS_CLIENT (client), NULL);
+	g_return_val_if_fail (client->priv != NULL, NULL);
+
+	if (!client->priv->uri)
+		client->priv->uri = e_source_get_uri (e_client_get_source (client));
+
+	return client->priv->uri;
+}
+
+static void
+client_ensure_capabilities (EClient *client)
+{
+	EClientClass *klass;
+	gchar *capabilities;
+
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CLIENT (client));
+	g_return_if_fail (client->priv != NULL);
+
+	klass = E_CLIENT_GET_CLASS (client);
+	g_return_if_fail (klass != NULL);
+	g_return_if_fail (klass->retrieve_capabilities != NULL);
+
+	if (client->priv->capabilities_retrieved || client->priv->capabilities)
+		return;
+
+	g_static_rec_mutex_lock (&client->priv->prop_mutex);
+
+	capabilities = klass->retrieve_capabilities (client);
+
+	e_client_set_capabilities (client, capabilities);
+
+	g_free (capabilities);
+
+	client->priv->capabilities_retrieved = TRUE;
+
+	g_static_rec_mutex_unlock (&client->priv->prop_mutex);
+}
+
+/**
+ * e_client_get_capabilities:
+ * @client: an #EClient
+ *
+ * Get list of strings with capabilities advertised by a backend.
+ * This list, together with inner strings, is owned by the @client.
+ * To check for individual capabilities use e_client_check_capability().
+ *
+ * Returns: #GSList of const strings of capabilities
+ *
+ * Since: 3.2
+ **/
+const GSList *
+e_client_get_capabilities (EClient *client)
+{
+	g_return_val_if_fail (client != NULL, NULL);
+	g_return_val_if_fail (E_IS_CLIENT (client), NULL);
+	g_return_val_if_fail (client->priv != NULL, NULL);
+
+	client_ensure_capabilities (client);
+
+	return client->priv->capabilities;
+}
+
+/**
+ * e_client_check_capability:
+ * @client: an #EClient
+ * @capability: a capability
+ *
+ * Check if backend supports particular capability.
+ * To get all capabilities use e_client_get_capabilities().
+ *
+ * Returns: #GSList of const strings of capabilities
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_client_check_capability (EClient *client, const gchar *capability)
+{
+	GSList *iter;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+	g_return_val_if_fail (capability, FALSE);
+
+	g_static_rec_mutex_lock (&client->priv->prop_mutex);
+
+	client_ensure_capabilities (client);
+
+	for (iter = client->priv->capabilities; iter; iter = g_slist_next (iter)) {
+		const gchar *cap = iter->data;
+
+		if (cap && g_ascii_strcasecmp (cap, capability) == 0) {
+			g_static_rec_mutex_unlock (&client->priv->prop_mutex);
+			return TRUE;
+		}
+	}
+
+	g_static_rec_mutex_unlock (&client->priv->prop_mutex);
+
+	return FALSE;
+}
+
+/**
+ * e_client_check_refresh_supported:
+ * @client: A client.
+ *
+ * Checks whether a client supports explicit refreshing (see e_client_refresh()).
+ *
+ * Returns: TRUE if the client supports refreshing, FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_client_check_refresh_supported (EClient *client)
+{
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
+
+	return e_client_check_capability (client, "refresh-supported");
+}
+
+/* capabilities - comma-separated list of capabilities; can be NULL to unset */
+void
+e_client_set_capabilities (EClient *client, const gchar *capabilities)
+{
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CLIENT (client));
+	g_return_if_fail (client->priv != NULL);
+
+	g_static_rec_mutex_lock (&client->priv->prop_mutex);
+
+	if (!capabilities)
+		client->priv->capabilities_retrieved = FALSE;
+
+	g_slist_foreach (client->priv->capabilities, (GFunc) g_free, NULL);
+	g_slist_free (client->priv->capabilities);
+	client->priv->capabilities = e_client_util_parse_comma_strings (capabilities);
+
+	g_static_rec_mutex_unlock (&client->priv->prop_mutex);
+
+	g_object_notify (G_OBJECT (client), "capabilities");
+}
+
+/**
+ * e_client_is_readonly:
+ * @client: an #EClient
+ *
+ * Check if this @client is read-only.
+ *
+ * Returns: %TRUE if this @client is read-only, otherwise %FALSE.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_client_is_readonly (EClient *client)
+{
+	g_return_val_if_fail (client != NULL, TRUE);
+	g_return_val_if_fail (E_IS_CLIENT (client), TRUE);
+	g_return_val_if_fail (client->priv != NULL, TRUE);
+
+	return client->priv->readonly;
+}
+
+void
+e_client_set_readonly (EClient *client, gboolean readonly)
+{
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CLIENT (client));
+	g_return_if_fail (client->priv != NULL);
+
+	g_static_rec_mutex_lock (&client->priv->prop_mutex);
+	if ((readonly ? 1 : 0) == (client->priv->readonly ? 1 : 0)) {
+		g_static_rec_mutex_unlock (&client->priv->prop_mutex);
+		return;
+	}
+
+	client->priv->readonly = readonly;
+
+	g_static_rec_mutex_unlock (&client->priv->prop_mutex);
+
+	g_object_notify (G_OBJECT (client), "readonly");
+}
+
+/**
+ * e_client_is_online:
+ * @client: an #EClient
+ *
+ * Check if this @client is connected.
+ *
+ * Returns: %TRUE if this @client is connected, otherwise %FALSE.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_client_is_online (EClient *client)
+{
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+
+	return client->priv->online;
+}
+
+void
+e_client_set_online (EClient *client, gboolean is_online)
+{
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CLIENT (client));
+	g_return_if_fail (client->priv != NULL);
+
+	/* newly connected/disconnected => make sure capabilities will be correct */
+	e_client_set_capabilities (client, NULL);
+
+	g_static_rec_mutex_lock (&client->priv->prop_mutex);
+	if ((is_online ? 1: 0) == (client->priv->online ? 1 : 0)) {
+		g_static_rec_mutex_unlock (&client->priv->prop_mutex);
+		return;
+	}
+
+	client->priv->online = is_online;
+
+	g_static_rec_mutex_unlock (&client->priv->prop_mutex);
+
+	g_object_notify (G_OBJECT (client), "online");
+}
+
+/**
+ * e_client_is_opened:
+ * @client: an #EClient
+ *
+ * Check if this @client is fully opened. This includes
+ * everything from e_client_open() call up to the authentication,
+ * if required by a backend. Client cannot do any other operation
+ * during the opening phase except of authenticate or cancel it.
+ * Every other operation results in an %E_CLIENT_ERROR_BUSY error.
+ *
+ * Returns: %TRUE if this @client is fully opened, otherwise %FALSE.
+ *
+ * Since: 3.2.
+ **/
+gboolean
+e_client_is_opened (EClient *client)
+{
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+
+	return client->priv->opened;
+}
+
+/*
+ * client_cancel_op:
+ * @client: an #EClient
+ * @opid: asynchronous operation ID
+ *
+ * Cancels particular asynchronous operation. The @opid is returned from
+ * an e_client_register_op(). The function does nothing if the asynchronous
+ * operation doesn't exist any more.
+ *
+ * Since: 3.2
+ */
+static void
+client_cancel_op (EClient *client, guint32 opid)
+{
+	GCancellable *cancellable;
+
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CLIENT (client));
+	g_return_if_fail (client->priv != NULL);
+	g_return_if_fail (client->priv->ops != NULL);
+
+	g_static_rec_mutex_lock (&client->priv->ops_mutex);
+
+	cancellable = g_hash_table_lookup (client->priv->ops, GINT_TO_POINTER (opid));
+	if (cancellable)
+		g_cancellable_cancel (cancellable);
+
+	g_static_rec_mutex_unlock (&client->priv->ops_mutex);
+}
+
+static void
+gather_opids_cb (gpointer opid, gpointer cancellable, gpointer ids_list)
+{
+	GSList **ids = ids_list;
+
+	g_return_if_fail (ids_list != NULL);
+
+	*ids = g_slist_prepend (*ids, opid);
+}
+
+static void
+cancel_op_cb (gpointer opid, gpointer client)
+{
+	client_cancel_op (client, GPOINTER_TO_INT (opid));
+}
+
+/**
+ * e_client_cancel_all:
+ * @client: an #EClient
+ *
+ * Cancels all pending operations started on @client.
+ *
+ * Since: 3.2
+ **/
+void
+e_client_cancel_all (EClient *client)
+{
+	GSList *opids = NULL;
+
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CLIENT (client));
+	g_return_if_fail (client->priv != NULL);
+	g_return_if_fail (client->priv->ops != NULL);
+
+	g_static_rec_mutex_lock (&client->priv->ops_mutex);
+
+	g_hash_table_foreach (client->priv->ops, gather_opids_cb, &opids);
+
+	g_slist_foreach (opids, cancel_op_cb, client);
+	g_slist_free (opids);
+
+	g_static_rec_mutex_unlock (&client->priv->ops_mutex);
+}
+
+guint32
+e_client_register_op (EClient *client, GCancellable *cancellable)
+{
+	guint32 opid;
+
+	g_return_val_if_fail (client != NULL, 0);
+	g_return_val_if_fail (E_IS_CLIENT (client), 0);
+	g_return_val_if_fail (client->priv != NULL, 0);
+	g_return_val_if_fail (client->priv->ops != NULL, 0);
+	g_return_val_if_fail (cancellable != NULL, 0);
+
+	g_static_rec_mutex_lock (&client->priv->ops_mutex);
+
+	client->priv->last_opid++;
+	if (!client->priv->last_opid)
+		client->priv->last_opid++;
+
+	while (g_hash_table_lookup (client->priv->ops, GINT_TO_POINTER (client->priv->last_opid)))
+		client->priv->last_opid++;
+
+	g_return_val_if_fail (client->priv->last_opid != 0, 0);
+
+	opid = client->priv->last_opid;
+	g_hash_table_insert (client->priv->ops, GINT_TO_POINTER (opid), g_object_ref (cancellable));
+
+	g_static_rec_mutex_unlock (&client->priv->ops_mutex);
+
+	return opid;
+}
+
+void
+e_client_unregister_op (EClient *client, guint32 opid)
+{
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CLIENT (client));
+	g_return_if_fail (client->priv != NULL);
+	g_return_if_fail (client->priv->ops != NULL);
+
+	g_static_rec_mutex_lock (&client->priv->ops_mutex);
+	g_hash_table_remove (client->priv->ops, GINT_TO_POINTER (opid));
+	g_static_rec_mutex_unlock (&client->priv->ops_mutex);
+}
+
+static void
+client_handle_authentication (EClient *client, const ECredentials *credentials)
+{
+	EClientClass *klass;
+
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CLIENT (client));
+	g_return_if_fail (credentials != NULL);
+
+	klass = E_CLIENT_GET_CLASS (client);
+	g_return_if_fail (klass != NULL);
+	g_return_if_fail (klass->handle_authentication != NULL);
+
+	return klass->handle_authentication (client, credentials);
+}
+
+/* Processes authentication request in a new thread. Usual steps are:
+   a) backend sends an auth-required signal
+   b) EClient implementation calls this function
+   c) a new thread is run which emits authenticate signal by e_client_emit_authenticate()
+   d) if anyone responds (returns true), the EClient::handle_authentication
+      is called from the same extra thread with new credentials
+   e) EClient implementation passes results to backend in the EClient::handle_authentication
+*/
+void
+e_client_process_authentication (EClient *client, const ECredentials *credentials)
+{
+	EClientOpData *op_data;
+
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CLIENT (client));
+
+	op_data = g_new0 (EClientOpData, 1);
+	op_data->client = g_object_ref (client);
+	op_data->op = E_CLIENT_OP_AUTHENTICATE;
+	op_data->d.credentials = credentials ? e_credentials_new_clone (credentials) : e_credentials_new ();
+
+	e_operation_pool_push (ops_pool, op_data);
+}
+
+gboolean
+e_client_emit_authenticate (EClient *client, ECredentials *credentials)
+{
+	gboolean handled = FALSE;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
+	g_return_val_if_fail (credentials != NULL, FALSE);
+
+	g_signal_emit (client, signals[AUTHENTICATE], 0, credentials, &handled);
+
+	return handled;
+}
+
+void
+e_client_emit_opened (EClient *client, const GError *dbus_error)
+{
+	GError *local_error = NULL;
+
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CLIENT (client));
+	g_return_if_fail (client->priv != NULL);
+
+	client->priv->opened = dbus_error == NULL;
+
+	if (dbus_error) {
+		local_error = g_error_copy (dbus_error);
+		e_client_unwrap_dbus_error (client, local_error, &local_error);
+	}
+
+	g_signal_emit (client, signals[OPENED], 0, local_error);
+
+	if (local_error)
+		g_error_free (local_error);
+}
+
+void
+e_client_emit_backend_error (EClient *client, const gchar *error_msg)
+{
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CLIENT (client));
+	g_return_if_fail (error_msg != NULL);
+
+	g_signal_emit (client, signals[BACKEND_ERROR], 0, error_msg);
+}
+
+void
+e_client_emit_backend_died (EClient *client)
+{
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CLIENT (client));
+
+	g_signal_emit (client, signals[BACKEND_DIED], 0);
+}
+
+/**
+ * e_client_get_backend_property:
+ * @client: an #EClient
+ * @prop_name: property name, whose value to retrieve; cannot be %NULL
+ * @cancellable: a #GCancellable; can be %NULL
+ * @callback: callback to call when a result is ready
+ * @user_data: user data for the @callback
+ *
+ * Queries @client's backend for a property of name @prop_name.
+ * The call is finished by e_client_get_backend_property_finish()
+ * from the @callback.
+ *
+ * Since: 3.2
+ **/
+void
+e_client_get_backend_property (EClient *client, const gchar *prop_name, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	EClientClass *klass;
+
+	g_return_if_fail (callback != NULL);
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CLIENT (client));
+	g_return_if_fail (client->priv != NULL);
+	g_return_if_fail (prop_name != NULL);
+
+	klass = E_CLIENT_GET_CLASS (client);
+	g_return_if_fail (klass != NULL);
+	g_return_if_fail (klass->get_backend_property != NULL);
+
+	klass->get_backend_property (client, prop_name, cancellable, callback, user_data);
+}
+
+/**
+ * e_client_get_backend_property_finish:
+ * @client: an #EClient
+ * @result: a #GAsyncResult
+ * @prop_value: (out): Retrieved backend property value; cannot be %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Finishes previous call of e_client_get_backend_property().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_client_get_backend_property_finish (EClient *client, GAsyncResult *result, gchar **prop_value, GError **error)
+{
+	EClientClass *klass;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+	g_return_val_if_fail (prop_value != NULL, FALSE);
+
+	klass = E_CLIENT_GET_CLASS (client);
+	g_return_val_if_fail (klass != NULL, FALSE);
+	g_return_val_if_fail (klass->get_backend_property_finish != NULL, FALSE);
+
+	return klass->get_backend_property_finish (client, result, prop_value, error);
+}
+
+/**
+ * e_client_get_backend_property_sync:
+ * @client: an #EClient
+ * @prop_name: property name, whose value to retrieve; cannot be %NULL
+ * @prop_value: (out): Retrieved backend property value; cannot be %NULL
+ * @cancellable: a #GCancellable; can be %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Queries @client's backend for a property of name @prop_name.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_client_get_backend_property_sync (EClient *client, const gchar *prop_name, gchar **prop_value, GCancellable *cancellable, GError **error)
+{
+	EClientClass *klass;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+	g_return_val_if_fail (prop_name != NULL, FALSE);
+	g_return_val_if_fail (prop_value != NULL, FALSE);
+
+	klass = E_CLIENT_GET_CLASS (client);
+	g_return_val_if_fail (klass != NULL, FALSE);
+	g_return_val_if_fail (klass->get_backend_property_sync != NULL, FALSE);
+
+	return klass->get_backend_property_sync (client, prop_name, prop_value, cancellable, error);
+}
+
+/**
+ * e_client_set_backend_property:
+ * @client: an #EClient
+ * @prop_name: property name, whose value to change; cannot be %NULL
+ * @prop_value: property value, to set; cannot be %NULL
+ * @cancellable: a #GCancellable; can be %NULL
+ * @callback: callback to call when a result is ready
+ * @user_data: user data for the @callback
+ *
+ * Sets @client's backend property of name @prop_name
+ * to value @prop_value. The call is finished
+ * by e_client_set_backend_property_finish() from the @callback.
+ *
+ * Since: 3.2
+ **/
+void
+e_client_set_backend_property (EClient *client, const gchar *prop_name, const gchar *prop_value, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	EClientClass *klass;
+
+	g_return_if_fail (callback != NULL);
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CLIENT (client));
+	g_return_if_fail (client->priv != NULL);
+	g_return_if_fail (prop_name != NULL);
+	g_return_if_fail (prop_value != NULL);
+
+	klass = E_CLIENT_GET_CLASS (client);
+	g_return_if_fail (klass != NULL);
+	g_return_if_fail (klass->set_backend_property != NULL);
+
+	klass->set_backend_property (client, prop_name, prop_value, cancellable, callback, user_data);
+}
+
+/**
+ * e_client_set_backend_property_finish:
+ * @client: an #EClient
+ * @result: a #GAsyncResult
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Finishes previous call of e_client_set_backend_property().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_client_set_backend_property_finish (EClient *client, GAsyncResult *result, GError **error)
+{
+	EClientClass *klass;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+
+	klass = E_CLIENT_GET_CLASS (client);
+	g_return_val_if_fail (klass != NULL, FALSE);
+	g_return_val_if_fail (klass->set_backend_property_finish != NULL, FALSE);
+
+	return klass->set_backend_property_finish (client, result, error);
+}
+
+/**
+ * e_client_set_backend_property_sync:
+ * @client: an #EClient
+ * @prop_name: property name, whose value to change; cannot be %NULL
+ * @prop_value: property value, to set; cannot be %NULL
+ * @cancellable: a #GCancellable; can be %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Sets @client's backend property of name @prop_name
+ * to value @prop_value.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_client_set_backend_property_sync (EClient *client, const gchar *prop_name, const gchar *prop_value, GCancellable *cancellable, GError **error)
+{
+	EClientClass *klass;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+	g_return_val_if_fail (prop_name != NULL, FALSE);
+	g_return_val_if_fail (prop_value != NULL, FALSE);
+
+	klass = E_CLIENT_GET_CLASS (client);
+	g_return_val_if_fail (klass != NULL, FALSE);
+	g_return_val_if_fail (klass->set_backend_property_sync != NULL, FALSE);
+
+	return klass->set_backend_property_sync (client, prop_name, prop_value, cancellable, error);
+}
+
+/**
+ * e_client_open:
+ * @client: an #EClient
+ * @only_if_exists: if %TRUE, fail if this book doesn't already exist, otherwise create it first
+ * @cancellable: a #GCancellable; can be %NULL
+ * @callback: callback to call when a result is ready
+ * @user_data: user data for the @callback
+ *
+ * Opens the @client, making it ready for queries and other operations.
+ * The call is finished by e_client_open_finish() from the @callback.
+ *
+ * Since: 3.2
+ **/
+void
+e_client_open (EClient *client, gboolean only_if_exists, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	EClientClass *klass;
+
+	g_return_if_fail (callback != NULL);
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CLIENT (client));
+	g_return_if_fail (client->priv != NULL);
+
+	klass = E_CLIENT_GET_CLASS (client);
+	g_return_if_fail (klass != NULL);
+	g_return_if_fail (klass->open != NULL);
+
+	klass->open (client, only_if_exists, cancellable, callback, user_data);
+}
+
+/**
+ * e_client_open_finish:
+ * @client: an #EClient
+ * @result: a #GAsyncResult
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Finishes previous call of e_client_open().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_client_open_finish (EClient *client, GAsyncResult *result, GError **error)
+{
+	EClientClass *klass;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+
+	klass = E_CLIENT_GET_CLASS (client);
+	g_return_val_if_fail (klass != NULL, FALSE);
+	g_return_val_if_fail (klass->open_finish != NULL, FALSE);
+
+	return klass->open_finish (client, result, error);
+}
+
+/**
+ * e_client_open_sync:
+ * @client: an #EClient
+ * @only_if_exists: if %TRUE, fail if this book doesn't already exist, otherwise create it first
+ * @cancellable: a #GCancellable; can be %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Opens the @client, making it ready for queries and other operations.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_client_open_sync (EClient *client, gboolean only_if_exists, GCancellable *cancellable, GError **error)
+{
+	EClientClass *klass;
+
+	klass = E_CLIENT_GET_CLASS (client);
+	g_return_val_if_fail (klass != NULL, FALSE);
+	g_return_val_if_fail (klass->open_sync != NULL, FALSE);
+
+	return klass->open_sync (client, only_if_exists, cancellable, error);
+}
+
+/**
+ * e_client_remove:
+ * @client: an #EClient
+ * @cancellable: a #GCancellable; can be %NULL
+ * @callback: callback to call when a result is ready
+ * @user_data: user data for the @callback
+ *
+ * Removes the backing data for this #EClient. For example, with the file backend this
+ * deletes the database file. You cannot get it back!
+ * The call is finished by e_client_remove_finish() from the @callback.
+ *
+ * Since: 3.2
+ **/
+void
+e_client_remove (EClient *client, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	EClientClass *klass;
+
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CLIENT (client));
+	g_return_if_fail (client->priv != NULL);
+	g_return_if_fail (callback != NULL);
+
+	klass = E_CLIENT_GET_CLASS (client);
+	g_return_if_fail (klass != NULL);
+	g_return_if_fail (klass->remove != NULL);
+
+	klass->remove (client, cancellable, callback, user_data);
+}
+
+/**
+ * e_client_remove_finish:
+ * @client: an #EClient
+ * @result: a #GAsyncResult
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Finishes previous call of e_client_remove().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_client_remove_finish (EClient *client, GAsyncResult *result, GError **error)
+{
+	EClientClass *klass;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+
+	klass = E_CLIENT_GET_CLASS (client);
+	g_return_val_if_fail (klass != NULL, FALSE);
+	g_return_val_if_fail (klass->remove_finish != NULL, FALSE);
+
+	return klass->remove_finish (client, result, error);
+}
+
+/**
+ * e_client_remove_sync:
+ * @client: an #EClient
+ * @cancellable: a #GCancellable; can be %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Removes the backing data for this #EClient. For example, with the file backend this
+ * deletes the database file. You cannot get it back!
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_client_remove_sync (EClient *client, GCancellable *cancellable, GError **error)
+{
+	EClientClass *klass;
+
+	klass = E_CLIENT_GET_CLASS (client);
+	g_return_val_if_fail (klass != NULL, FALSE);
+	g_return_val_if_fail (klass->remove_sync != NULL, FALSE);
+
+	return klass->remove_sync (client, cancellable, error);
+}
+
+/**
+ * e_client_refresh:
+ * @client: an #EClient
+ * @cancellable: a #GCancellable; can be %NULL
+ * @callback: callback to call when a result is ready
+ * @user_data: user data for the @callback
+ *
+ * Initiates refresh on the @client. Finishing the method doesn't mean
+ * that the refresh is done, backend only notifies whether it started
+ * refreshing or not. Use e_client_check_refresh_supported() to check
+ * whether the backend supports this method.
+ * The call is finished by e_client_refresh_finish() from the @callback.
+ *
+ * Since: 3.2
+ **/
+void
+e_client_refresh (EClient *client, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	EClientClass *klass;
+
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CLIENT (client));
+	g_return_if_fail (client->priv != NULL);
+	g_return_if_fail (callback != NULL);
+
+	klass = E_CLIENT_GET_CLASS (client);
+	g_return_if_fail (klass != NULL);
+	g_return_if_fail (klass->refresh != NULL);
+
+	klass->refresh (client, cancellable, callback, user_data);
+}
+
+/**
+ * e_client_refresh_finish:
+ * @client: an #EClient
+ * @result: a #GAsyncResult
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Finishes previous call of e_client_refresh().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_client_refresh_finish (EClient *client, GAsyncResult *result, GError **error)
+{
+	EClientClass *klass;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
+	g_return_val_if_fail (client->priv != NULL, FALSE);
+
+	klass = E_CLIENT_GET_CLASS (client);
+	g_return_val_if_fail (klass != NULL, FALSE);
+	g_return_val_if_fail (klass->refresh_finish != NULL, FALSE);
+
+	return klass->refresh_finish (client, result, error);
+}
+
+/**
+ * e_client_refresh_sync:
+ * @client: an #EClient
+ * @cancellable: a #GCancellable; can be %NULL
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Initiates refresh on the @client. Finishing the method doesn't mean
+ * that the refresh is done, backend only notifies whether it started
+ * refreshing or not. Use e_client_check_refresh_supported() to check
+ * whether the backend supports this method.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_client_refresh_sync (EClient *client, GCancellable *cancellable, GError **error)
+{
+	EClientClass *klass;
+
+	klass = E_CLIENT_GET_CLASS (client);
+	g_return_val_if_fail (klass != NULL, FALSE);
+	g_return_val_if_fail (klass->refresh_sync != NULL, FALSE);
+
+	return klass->refresh_sync (client, cancellable, error);
+}
+
+/**
+ * e_client_util_slist_to_strv:
+ * @strings: a #GSList of strings (const gchar *)
+ *
+ * Convert list of strings into NULL-terminates array of strings.
+ *
+ * Returns: Newly allocated NULL-terminated array of strings.
+ * Returned pointer should be freed with g_strfreev().
+ *
+ * Note: Pair function for this is e_client_util_strv_to_slist().
+ *
+ * Sice: 3.2
+ **/
+gchar **
+e_client_util_slist_to_strv (const GSList *strings)
+{
+	const GSList *iter;
+	GPtrArray *array;
+
+	array = g_ptr_array_sized_new (g_slist_length ((GSList *) strings) + 1);
+
+	for (iter = strings; iter; iter = iter->next) {
+		const gchar *str = iter->data;
+
+		if (str)
+			g_ptr_array_add (array, g_strdup (str));
+	}
+
+	/* NULL-terminated */
+	g_ptr_array_add (array, NULL);
+
+	return (gchar **) g_ptr_array_free (array, FALSE);
+}
+
+/**
+ * e_client_util_strv_to_slist:
+ * @strv: a NULL-terminated array of strings (const gchar *)
+ *
+ * Convert NULL-terminated array of strings to a list of strings.
+ *
+ * Returns: Newly allocated #GSList of newly allocated strings.
+ * Returned pointer should be freed with e_client_util_free_string_slist().
+ *
+ * Note: Pair function for this is e_client_util_slist_to_strv().
+ *
+ * Sice: 3.2
+ **/
+GSList *
+e_client_util_strv_to_slist (const gchar * const *strv)
+{
+	GSList *slist = NULL;
+	gint ii;
+
+	if (!strv)
+		return NULL;
+
+	for (ii = 0; strv[ii]; ii++) {
+		slist = g_slist_prepend (slist, g_strdup (strv[ii]));
+	}
+
+	return g_slist_reverse (slist);
+}
+
+/**
+ * e_client_util_copy_string_slist:
+ * @copy_to: Where to copy; can be NULL
+ * @strings: GSList of strings to be copied
+ *
+ * Copies GSList of strings at the end of @copy_to.
+ *
+ * Returns: New head of @copy_to.
+ * Returned pointer can be freed with e_client_util_free_string_slist().
+ *
+ * Since: 3.2
+ **/
+GSList *
+e_client_util_copy_string_slist	(GSList *copy_to, const GSList *strings)
+{
+	GSList *res = copy_to;
+	const GSList *iter;
+
+	for (iter = strings; iter; iter = iter->next) {
+		res = g_slist_append (res, g_strdup (iter->data));
+	}
+
+	return res;
+}
+
+/**
+ * e_client_util_copy_object_slist:
+ * @copy_to: Where to copy; can be NULL
+ * @objects: GSList of GObject-s to be copied
+ *
+ * Copies GSList of GObject-s at the end of @copy_to.
+ *
+ * Returns: New head of @copy_to.
+ * Returned pointer can be freed with e_client_util_free_object_slist().
+ *
+ * Since: 3.2
+ **/
+GSList *
+e_client_util_copy_object_slist	(GSList *copy_to, const GSList *objects)
+{
+	GSList *res = copy_to;
+	const GSList *iter;
+
+	for (iter = objects; iter; iter = iter->next) {
+		res = g_slist_append (res, g_object_ref (iter->data));
+	}
+
+	return res;
+}
+
+/**
+ * e_client_util_free_string_slist:
+ * @strings: a #GSList of strings (gchar *)
+ *
+ * Frees memory previously allocated by e_client_util_strv_to_slist().
+ *
+ * Sice: 3.2
+ **/
+void
+e_client_util_free_string_slist (GSList *strings)
+{
+	if (!strings)
+		return;
+
+	g_slist_foreach (strings, (GFunc) g_free, NULL);
+	g_slist_free (strings);
+}
+
+/**
+ * e_client_util_free_object_slist:
+ * @objects: a #GSList of #GObject-s
+ *
+ * Calls g_object_unref() on each member of @objects and then frees
+ * also @objects itself.
+ *
+ * Sice: 3.2
+ **/
+void
+e_client_util_free_object_slist (GSList *objects)
+{
+	if (!objects)
+		return;
+
+	g_slist_foreach (objects, (GFunc) g_object_unref, NULL);
+	g_slist_free (objects);
+}
+
+/**
+ * e_client_util_parse_comma_strings:
+ * @strings: string of comma-separated values
+ *
+ * Parses comma-separated list of values into #GSList.
+ *
+ * Returns: Newly allocated #GSList of newly allocated strings
+ * corresponding to values parsed from @strings.
+ * Free returned pointer with e_client_util_free_string_slist().
+ *
+ * Since: 3.2
+ **/
+GSList *
+e_client_util_parse_comma_strings (const gchar *strings)
+{
+	GSList *strs_slist = NULL;
+	gchar **strs_strv = NULL;
+	gint ii;
+
+	if (!strings || !*strings)
+		return NULL;
+
+	strs_strv = g_strsplit (strings, ",", -1);
+	g_return_val_if_fail (strs_strv != NULL, NULL);
+
+	for (ii = 0; strs_strv && strs_strv[ii]; ii++) {
+		gchar *str = g_strstrip (strs_strv[ii]);
+
+		if (str && *str)
+			strs_slist = g_slist_prepend (strs_slist, g_strdup (str));
+	}
+
+	g_strfreev (strs_strv);
+
+	return g_slist_reverse (strs_slist);
+}
+
+/* for each known source calls check_func, which should return TRUE if the required
+   source have been found. Function returns NULL or the source on which was returned
+   TRUE by the check_func. Non-NULL pointer should be unreffed by g_object_unref. */
+static ESource *
+search_known_sources (ESourceList *sources, gboolean (*check_func)(ESource *source, gpointer user_data), gpointer user_data)
+{
+	ESource *res = NULL;
+	GSList *g;
+
+	g_return_val_if_fail (check_func != NULL, NULL);
+	g_return_val_if_fail (sources != NULL, 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 (check_func (source, user_data)) {
+				res = g_object_ref (source);
+				break;
+			}
+		}
+
+		if (res)
+			break;
+	}
+
+	return res;
+}
+
+static gboolean
+check_uri (ESource *source, gpointer uri)
+{
+	const gchar *suri;
+	gchar *suri2;
+	gboolean res;
+
+	g_return_val_if_fail (source != NULL, FALSE);
+	g_return_val_if_fail (uri != NULL, FALSE);
+
+	suri = e_source_peek_absolute_uri (source);
+
+	if (suri)
+		return g_ascii_strcasecmp (suri, uri) == 0;
+
+	suri2 = e_source_get_uri (source);
+	res = suri2 && g_ascii_strcasecmp (suri2, uri) == 0;
+	g_free (suri2);
+
+	return res;
+}
+
+struct check_system_data
+{
+	const gchar *uri;
+	ESource *uri_source;
+};
+
+static gboolean
+check_system (ESource *source, gpointer data)
+{
+	struct check_system_data *csd = data;
+
+	g_return_val_if_fail (source != NULL, FALSE);
+	g_return_val_if_fail (data != NULL, FALSE);
+
+	if (e_source_get_property (source, "system")) {
+		return TRUE;
+	}
+
+	if (check_uri (source, (gpointer) csd->uri)) {
+		if (csd->uri_source)
+			g_object_unref (csd->uri_source);
+		csd->uri_source = g_object_ref (source);
+	}
+
+	return FALSE;
+}
+
+ESource *
+e_client_util_get_system_source (ESourceList *source_list)
+{
+	struct check_system_data csd;
+	ESource *system_source = NULL;
+
+	g_return_val_if_fail (source_list != NULL, NULL);
+	g_return_val_if_fail (E_IS_SOURCE_LIST (source_list), NULL);
+
+	csd.uri = "local:system";
+	csd.uri_source = NULL;
+
+	system_source = search_known_sources (source_list, check_system, &csd);
+
+	if (!system_source) {
+		system_source = csd.uri_source;
+		csd.uri_source = NULL;
+	}
+
+	if (csd.uri_source)
+		g_object_unref (csd.uri_source);
+
+	if (!system_source) {
+		/* create a new one, if not found */
+		ESourceGroup *on_this_computer;
+
+		on_this_computer = e_source_list_ensure_group (source_list,
+						       _("On This Computer"),
+						       "local:", TRUE);
+		if (on_this_computer) {
+			GError *error = NULL;
+
+			system_source = e_source_new (_("Personal"), "system");
+			e_source_set_color_spec (system_source, "#BECEDD");
+			e_source_group_add_source (on_this_computer, system_source, -1);
+
+			if (!e_source_list_sync (source_list, &error))
+				g_warning ("Cannot add system source to GConf: %s", error ? error->message : "Unknown error");
+
+			if (error)
+				g_error_free (error);
+		}
+	}
+
+	return system_source;
+}
+
+gboolean
+e_client_util_set_default (ESourceList *source_list, ESource *source)
+{
+	const gchar *uid;
+	GSList *g;
+
+	g_return_val_if_fail (source_list != NULL, FALSE);
+	g_return_val_if_fail (E_IS_SOURCE_LIST (source_list), FALSE);
+	g_return_val_if_fail (source != NULL, FALSE);
+	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+
+	uid = e_source_peek_uid (source);
+
+	/* make sure the source is actually in the ESourceList.  If
+	   it's not we don't bother adding it, just return an error */
+	source = e_source_list_peek_source_by_uid (source_list, uid);
+	if (!source)
+		return FALSE;
+
+	/* loop over all the sources clearing out any "default"
+	   properties we find */
+	for (g = e_source_list_peek_groups (source_list); g; g = g->next) {
+		GSList *s;
+		for (s = e_source_group_peek_sources (E_SOURCE_GROUP (g->data));
+		     s; s = s->next) {
+			e_source_set_property (E_SOURCE (s->data), "default", NULL);
+		}
+	}
+
+	/* set the "default" property on the source */
+	e_source_set_property (source, "default", "true");
+
+	return TRUE;
+}
+
+ESource *
+e_client_util_get_source_for_uri (ESourceList *source_list, const gchar *uri)
+{
+	ESource *source;
+
+	g_return_val_if_fail (source_list != NULL, NULL);
+	g_return_val_if_fail (E_IS_SOURCE_LIST (source_list), NULL);
+	g_return_val_if_fail (uri != NULL, NULL);
+
+	source = search_known_sources (source_list, check_uri, (gpointer) uri);
+	if (!source)
+		source = e_source_new_with_absolute_uri ("", uri);
+
+	return source;
+}
+
+GDBusProxy *
+e_client_get_dbus_proxy (EClient *client)
+{
+	EClientClass *klass;
+
+	g_return_val_if_fail (client != NULL, NULL);
+	g_return_val_if_fail (E_IS_CLIENT (client), NULL);
+
+	klass = E_CLIENT_GET_CLASS (client);
+	g_return_val_if_fail (klass != NULL, NULL);
+	g_return_val_if_fail (klass->get_dbus_proxy != NULL, NULL);
+
+	return klass->get_dbus_proxy (client);
+}
+
+/**
+ * Unwraps D-Bus error to local error. dbus_error is automatically freed.
+ * dbus_erorr and out_error can point to the same variable.
+ **/
+void
+e_client_unwrap_dbus_error (EClient *client, GError *dbus_error, GError **out_error)
+{
+	EClientClass *klass;
+
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CLIENT (client));
+
+	klass = E_CLIENT_GET_CLASS (client);
+	g_return_if_fail (klass != NULL);
+	g_return_if_fail (klass->unwrap_dbus_error != NULL);
+
+	if (!dbus_error || !out_error) {
+		if (dbus_error)
+			g_error_free (dbus_error);
+	} else {
+		klass->unwrap_dbus_error (client, dbus_error, out_error);
+	}
+}
+
+/**
+ * e_client_util_unwrap_dbus_error:
+ * @dbus_error: DBus #GError to unwrap
+ * @client_error: (out): Resulting #GError; can be %NULL
+ * @known_errors: List of known errors against which try to match
+ * @known_errors_count: How many items are stored in @known_errors
+ * @known_errors_domain: Error domain for @known_errors
+ * @fail_when_none_matched: Whether to fail when none of @known_errors matches
+ *
+ * The function takes a @dbus_error and tries to find a match in @known_errors for it,
+ * if it is a G_IO_ERROR, G_IO_ERROR_DBUS_ERROR. If it is anything else then the @dbus_error
+ * is moved to @client_error.
+ *
+ * The @fail_when_none_matched influences behaviour. If it's %TRUE, and none of @known_errors matches,
+ * or this is not a G_IO_ERROR_DBUS_ERROR, then %FALSE is returned and the @client_error
+ * is left without change. Otherwise, the @fail_when_none_matched is %FALSE, the error is always
+ * processed and will result in E_CLIENT_ERROR, E_CLIENT_ERROR_OTHER_ERROR if none of @known_error matches.
+ *
+ * Returns: Whether was @dbus_error processed into @client_error.
+ *
+ * Note: The @dbus_error is automatically freed if returned %TRUE.
+ **/
+gboolean
+e_client_util_unwrap_dbus_error (GError *dbus_error, GError **client_error, const struct EClientErrorsList *known_errors, guint known_errors_count, GQuark known_errors_domain, gboolean fail_when_none_matched)
+{
+	if (!client_error) {
+		if (dbus_error)
+			g_error_free (dbus_error);
+		return TRUE;
+	}
+
+	if (!dbus_error) {
+		*client_error = NULL;
+		return TRUE;
+	}
+
+	if (dbus_error->domain == known_errors_domain) {
+		*client_error = dbus_error;
+		return TRUE;
+	}
+
+	if (known_errors) {
+		if (g_error_matches (dbus_error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR)) {
+			gchar *name;
+			gint ii;
+
+			name = g_dbus_error_get_remote_error (dbus_error);
+
+			for (ii = 0; ii < known_errors_count; ii++) {
+				if (g_ascii_strcasecmp (known_errors[ii].name, name) == 0) {
+					g_free (name);
+
+					g_dbus_error_strip_remote_error (dbus_error);
+					*client_error = g_error_new_literal (known_errors_domain, known_errors[ii].err_code, dbus_error->message);
+					g_error_free (dbus_error);
+					return TRUE;
+				}
+			}
+
+			g_free (name);
+		}
+	}
+
+	if (fail_when_none_matched)
+		return FALSE;
+
+	if (g_error_matches (dbus_error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR)) {
+		g_dbus_error_strip_remote_error (dbus_error);
+		*client_error = g_error_new_literal (E_CLIENT_ERROR, E_CLIENT_ERROR_OTHER_ERROR, dbus_error->message);
+		g_error_free (dbus_error);
+	} else {
+		if (dbus_error->domain == G_DBUS_ERROR)
+			g_dbus_error_strip_remote_error (dbus_error);
+		*client_error = dbus_error;
+	}
+
+	return TRUE;
+}
+
+typedef struct _EClientAsyncOpData
+{
+	EClient *client;
+	guint32 opid;
+
+	gpointer source_tag;
+	GAsyncReadyCallback callback;
+	gpointer user_data;
+
+	gboolean result; /* result of the finish function call */
+
+	/* only one can be non-NULL, and the type is telling which 'out' value is valid */
+	EClientProxyFinishVoidFunc finish_void;
+	EClientProxyFinishBooleanFunc finish_boolean;
+	EClientProxyFinishStringFunc finish_string;
+	EClientProxyFinishStrvFunc finish_strv;
+	EClientProxyFinishUintFunc finish_uint;
+
+	union {
+		gboolean val_boolean;
+		gchar *val_string;
+		gchar **val_strv;
+		guint val_uint;
+	} out;
+} EClientAsyncOpData;
+
+static void
+async_data_free (EClientAsyncOpData *async_data)
+{
+	g_return_if_fail (async_data != NULL);
+	g_return_if_fail (async_data->client != NULL);
+
+	e_client_unregister_op (async_data->client, async_data->opid);
+
+	if (async_data->finish_string)
+		g_free (async_data->out.val_string);
+	else if (async_data->finish_strv)
+		g_strfreev (async_data->out.val_strv);
+
+	g_object_unref (async_data->client);
+	g_free (async_data);
+}
+
+static gboolean
+complete_async_op_in_idle_cb (gpointer user_data)
+{
+	GSimpleAsyncResult *simple = user_data;
+	gint run_main_depth;
+
+	g_return_val_if_fail (simple != NULL, FALSE);
+
+	run_main_depth = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (simple), "run-main-depth"));
+	if (run_main_depth < 1)
+		run_main_depth = 1;
+
+	/* do not receive in higher level than was initially run */
+	if (g_main_depth () > run_main_depth) {
+		return TRUE;
+	}
+
+	g_simple_async_result_complete (simple);
+	g_object_unref (simple);
+
+	return FALSE;
+}
+
+static void
+finish_async_op (EClientAsyncOpData *async_data, const GError *error, gboolean in_idle)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_if_fail (async_data != NULL);
+	g_return_if_fail (async_data->source_tag != NULL);
+	g_return_if_fail (async_data->client != NULL);
+
+	simple = g_simple_async_result_new (G_OBJECT (async_data->client), async_data->callback, async_data->user_data, async_data->source_tag);
+	g_simple_async_result_set_op_res_gpointer (simple, async_data, (GDestroyNotify) async_data_free);
+
+	if (error != NULL)
+		g_simple_async_result_set_from_error (simple, error);
+
+	if (in_idle) {
+		g_object_set_data (G_OBJECT (simple), "run-main-depth", GINT_TO_POINTER (g_main_depth ()));
+		g_idle_add (complete_async_op_in_idle_cb, simple);
+	} else {
+		g_simple_async_result_complete (simple);
+		g_object_unref (simple);
+	}
+}
+
+static void
+async_result_ready_cb (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	GError *error = NULL;
+	EClientAsyncOpData *async_data;
+	EClient *client;
+
+	g_return_if_fail (result != NULL);
+	g_return_if_fail (source_object != NULL);
+
+	async_data = user_data;
+	g_return_if_fail (async_data != NULL);
+	g_return_if_fail (async_data->client != NULL);
+
+	client = async_data->client;
+	g_return_if_fail (e_client_get_dbus_proxy (client) == G_DBUS_PROXY (source_object));
+
+	if (async_data->finish_void)
+		async_data->result = async_data->finish_void (G_DBUS_PROXY (source_object), result, &error);
+	else if (async_data->finish_boolean)
+		async_data->result = async_data->finish_boolean (G_DBUS_PROXY (source_object), result, &async_data->out.val_boolean, &error);
+	else if (async_data->finish_string)
+		async_data->result = async_data->finish_string (G_DBUS_PROXY (source_object), result, &async_data->out.val_string, &error);
+	else if (async_data->finish_strv)
+		async_data->result = async_data->finish_strv (G_DBUS_PROXY (source_object), result, &async_data->out.val_strv, &error);
+	else if (async_data->finish_uint)
+		async_data->result = async_data->finish_uint (G_DBUS_PROXY (source_object), result, &async_data->out.val_uint, &error);
+	else
+		g_warning ("%s: Do not know how to finish async operation", G_STRFUNC);
+
+	finish_async_op (async_data, error, FALSE);
+
+	if (error != NULL)
+		g_error_free (error);
+}
+
+static EClientAsyncOpData *
+prepare_async_data (EClient *client, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data, gpointer source_tag, gboolean error_report_only, EClientProxyFinishVoidFunc finish_void, EClientProxyFinishBooleanFunc finish_boolean, EClientProxyFinishStringFunc finish_string, EClientProxyFinishStrvFunc finish_strv, EClientProxyFinishUintFunc finish_uint, GDBusProxy **proxy, GCancellable **out_cancellable)
+{
+	EClientAsyncOpData *async_data;
+	GCancellable *use_cancellable;
+	guint32 opid;
+
+	g_return_val_if_fail (client != NULL, NULL);
+	g_return_val_if_fail (callback != NULL, NULL);
+	g_return_val_if_fail (source_tag != NULL, NULL);
+
+	if (!error_report_only) {
+		g_return_val_if_fail (proxy != NULL, NULL);
+		g_return_val_if_fail (out_cancellable != NULL, NULL);
+		g_return_val_if_fail (finish_void || finish_boolean || finish_string || finish_strv || finish_uint, NULL);
+
+		if (finish_void) {
+			g_return_val_if_fail (finish_boolean == NULL, NULL);
+			g_return_val_if_fail (finish_string == NULL, NULL);
+			g_return_val_if_fail (finish_strv == NULL, NULL);
+			g_return_val_if_fail (finish_uint == NULL, NULL);
+		}
+
+		if (finish_boolean) {
+			g_return_val_if_fail (finish_void == NULL, NULL);
+			g_return_val_if_fail (finish_string == NULL, NULL);
+			g_return_val_if_fail (finish_strv == NULL, NULL);
+			g_return_val_if_fail (finish_uint == NULL, NULL);
+		}
+
+		if (finish_string) {
+			g_return_val_if_fail (finish_void == NULL, NULL);
+			g_return_val_if_fail (finish_boolean == NULL, NULL);
+			g_return_val_if_fail (finish_strv == NULL, NULL);
+			g_return_val_if_fail (finish_uint == NULL, NULL);
+		}
+
+		if (finish_strv) {
+			g_return_val_if_fail (finish_void == NULL, NULL);
+			g_return_val_if_fail (finish_boolean == NULL, NULL);
+			g_return_val_if_fail (finish_string == NULL, NULL);
+			g_return_val_if_fail (finish_uint == NULL, NULL);
+		}
+
+		if (finish_uint) {
+			g_return_val_if_fail (finish_void == NULL, NULL);
+			g_return_val_if_fail (finish_boolean == NULL, NULL);
+			g_return_val_if_fail (finish_string == NULL, NULL);
+			g_return_val_if_fail (finish_strv == NULL, NULL);
+		}
+
+		*proxy = e_client_get_dbus_proxy (client);
+		if (!*proxy)
+			return NULL;
+	}
+
+	use_cancellable = cancellable;
+	if (!use_cancellable)
+		use_cancellable = g_cancellable_new ();
+
+	opid = e_client_register_op (client, use_cancellable);
+	async_data = g_new0 (EClientAsyncOpData, 1);
+	async_data->client = g_object_ref (client);
+	async_data->opid = opid;
+	async_data->source_tag = source_tag;
+	async_data->callback = callback;
+	async_data->user_data = user_data;
+	async_data->finish_void = finish_void;
+	async_data->finish_boolean = finish_boolean;
+	async_data->finish_string = finish_string;
+	async_data->finish_strv = finish_strv;
+	async_data->finish_uint = finish_uint;
+
+	/* EClient from e_client_register_op() took ownership of the use_cancellable */
+	if (use_cancellable != cancellable)
+		g_object_unref (use_cancellable);
+
+	if (out_cancellable)
+		*out_cancellable = use_cancellable;
+
+	return async_data;
+}
+
+void
+e_client_proxy_return_async_error (EClient *client, const GError *error, GAsyncReadyCallback callback, gpointer user_data, gpointer source_tag)
+{
+	EClientAsyncOpData *async_data;
+
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CLIENT (client));
+	g_return_if_fail (error != NULL);
+	g_return_if_fail (callback != NULL);
+
+	async_data = prepare_async_data (client, NULL, callback, user_data, source_tag, TRUE, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+	g_return_if_fail (async_data != NULL);
+
+	finish_async_op (async_data, error, TRUE);
+}
+
+void
+e_client_proxy_call_void (EClient *client, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data, gpointer source_tag, void (*func) (GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data), EClientProxyFinishVoidFunc finish_void, EClientProxyFinishBooleanFunc finish_boolean, EClientProxyFinishStringFunc finish_string, EClientProxyFinishStrvFunc finish_strv, EClientProxyFinishUintFunc finish_uint)
+{
+	EClientAsyncOpData *async_data;
+	GDBusProxy *proxy = NULL;
+
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CLIENT (client));
+	g_return_if_fail (callback != NULL);
+	g_return_if_fail (source_tag != NULL);
+	e_client_return_async_if_fail (func != NULL, client, callback, user_data, source_tag);
+
+	async_data = prepare_async_data (client, cancellable, callback, user_data, source_tag, FALSE, finish_void, finish_boolean, finish_string, finish_strv, finish_uint, &proxy, &cancellable);
+	e_client_return_async_if_fail (async_data != NULL, client, callback, user_data, source_tag);
+
+	func (proxy, cancellable, async_result_ready_cb, async_data);
+}
+
+void
+e_client_proxy_call_boolean (EClient *client, gboolean in_boolean, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data, gpointer source_tag, void (*func) (GDBusProxy *proxy, gboolean in_boolean, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data), EClientProxyFinishVoidFunc finish_void, EClientProxyFinishBooleanFunc finish_boolean, EClientProxyFinishStringFunc finish_string, EClientProxyFinishStrvFunc finish_strv, EClientProxyFinishUintFunc finish_uint)
+{
+	EClientAsyncOpData *async_data;
+	GDBusProxy *proxy = NULL;
+
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CLIENT (client));
+	g_return_if_fail (callback != NULL);
+	g_return_if_fail (source_tag != NULL);
+	e_client_return_async_if_fail (func != NULL, client, callback, user_data, source_tag);
+
+	async_data = prepare_async_data (client, cancellable, callback, user_data, source_tag, FALSE, finish_void, finish_boolean, finish_string, finish_strv, finish_uint, &proxy, &cancellable);
+	e_client_return_async_if_fail (async_data != NULL, client, callback, user_data, source_tag);
+
+	func (proxy, in_boolean, cancellable, async_result_ready_cb, async_data);
+}
+
+void
+e_client_proxy_call_string (EClient *client, const gchar *in_string, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data, gpointer source_tag, void (*func) (GDBusProxy *proxy, const gchar * in_string, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data), EClientProxyFinishVoidFunc finish_void, EClientProxyFinishBooleanFunc finish_boolean, EClientProxyFinishStringFunc finish_string, EClientProxyFinishStrvFunc finish_strv, EClientProxyFinishUintFunc finish_uint)
+{
+	EClientAsyncOpData *async_data;
+	GDBusProxy *proxy = NULL;
+
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CLIENT (client));
+	g_return_if_fail (callback != NULL);
+	g_return_if_fail (source_tag != NULL);
+	e_client_return_async_if_fail (func != NULL, client, callback, user_data, source_tag);
+	e_client_return_async_if_fail (in_string != NULL, client, callback, user_data, source_tag);
+
+	async_data = prepare_async_data (client, cancellable, callback, user_data, source_tag, FALSE, finish_void, finish_boolean, finish_string, finish_strv, finish_uint, &proxy, &cancellable);
+	e_client_return_async_if_fail (async_data != NULL, client, callback, user_data, source_tag);
+
+	func (proxy, in_string, cancellable, async_result_ready_cb, async_data);
+}
+
+void
+e_client_proxy_call_strv (EClient *client, const gchar * const *in_strv, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data, gpointer source_tag, void (*func) (GDBusProxy *proxy, const gchar * const * in_strv, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data), EClientProxyFinishVoidFunc finish_void, EClientProxyFinishBooleanFunc finish_boolean, EClientProxyFinishStringFunc finish_string, EClientProxyFinishStrvFunc finish_strv, EClientProxyFinishUintFunc finish_uint)
+{
+	EClientAsyncOpData *async_data;
+	GDBusProxy *proxy = NULL;
+
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CLIENT (client));
+	g_return_if_fail (callback != NULL);
+	g_return_if_fail (source_tag != NULL);
+	e_client_return_async_if_fail (func != NULL, client, callback, user_data, source_tag);
+	e_client_return_async_if_fail (in_strv != NULL, client, callback, user_data, source_tag);
+
+	async_data = prepare_async_data (client, cancellable, callback, user_data, source_tag, FALSE, finish_void, finish_boolean, finish_string, finish_strv, finish_uint, &proxy, &cancellable);
+	e_client_return_async_if_fail (async_data != NULL, client, callback, user_data, source_tag);
+
+	func (proxy, in_strv, cancellable, async_result_ready_cb, async_data);
+}
+
+void
+e_client_proxy_call_uint (EClient *client, guint in_uint, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data, gpointer source_tag, void (*func) (GDBusProxy *proxy, guint in_uint, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data), EClientProxyFinishVoidFunc finish_void, EClientProxyFinishBooleanFunc finish_boolean, EClientProxyFinishStringFunc finish_string, EClientProxyFinishStrvFunc finish_strv, EClientProxyFinishUintFunc finish_uint)
+{
+	EClientAsyncOpData *async_data;
+	GDBusProxy *proxy = NULL;
+
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (E_IS_CLIENT (client));
+	g_return_if_fail (callback != NULL);
+	g_return_if_fail (source_tag != NULL);
+	e_client_return_async_if_fail (func != NULL, client, callback, user_data, source_tag);
+
+	async_data = prepare_async_data (client, cancellable, callback, user_data, source_tag, FALSE, finish_void, finish_boolean, finish_string, finish_strv, finish_uint, &proxy, &cancellable);
+	e_client_return_async_if_fail (async_data != NULL, client, callback, user_data, source_tag);
+
+	func (proxy, in_uint, cancellable, async_result_ready_cb, async_data);
+}
+
+gboolean
+e_client_proxy_call_finish_void (EClient *client, GAsyncResult *result, GError **error, gpointer source_tag)
+{
+	GSimpleAsyncResult *simple;
+	GError *local_error = NULL;
+	EClientAsyncOpData *async_data;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
+	g_return_val_if_fail (result != NULL, FALSE);
+	g_return_val_if_fail (source_tag != NULL, FALSE);
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (client), source_tag), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	if (g_simple_async_result_propagate_error (simple, &local_error)) {
+		e_client_unwrap_dbus_error (client, local_error, error);
+		return FALSE;
+	}
+
+	async_data = g_simple_async_result_get_op_res_gpointer (simple);
+	g_return_val_if_fail (async_data != NULL, FALSE);
+
+	return async_data->result;
+}
+
+gboolean
+e_client_proxy_call_finish_boolean (EClient *client, GAsyncResult *result, gboolean *out_boolean, GError **error, gpointer source_tag)
+{
+	GSimpleAsyncResult *simple;
+	GError *local_error = NULL;
+	EClientAsyncOpData *async_data;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
+	g_return_val_if_fail (result != NULL, FALSE);
+	g_return_val_if_fail (source_tag != NULL, FALSE);
+	g_return_val_if_fail (out_boolean != NULL, FALSE);
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (client), source_tag), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	if (g_simple_async_result_propagate_error (simple, &local_error)) {
+		e_client_unwrap_dbus_error (client, local_error, error);
+		return FALSE;
+	}
+
+	async_data = g_simple_async_result_get_op_res_gpointer (simple);
+	g_return_val_if_fail (async_data != NULL, FALSE);
+
+	*out_boolean = async_data->out.val_boolean;
+
+	return async_data->result;
+}
+
+gboolean
+e_client_proxy_call_finish_string (EClient *client, GAsyncResult *result, gchar **out_string, GError **error, gpointer source_tag)
+{
+	GSimpleAsyncResult *simple;
+	GError *local_error = NULL;
+	EClientAsyncOpData *async_data;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
+	g_return_val_if_fail (result != NULL, FALSE);
+	g_return_val_if_fail (source_tag != NULL, FALSE);
+	g_return_val_if_fail (out_string != NULL, FALSE);
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (client), source_tag), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	if (g_simple_async_result_propagate_error (simple, &local_error)) {
+		e_client_unwrap_dbus_error (client, local_error, error);
+		return FALSE;
+	}
+
+	async_data = g_simple_async_result_get_op_res_gpointer (simple);
+	g_return_val_if_fail (async_data != NULL, FALSE);
+
+	*out_string = async_data->out.val_string;
+	async_data->out.val_string = NULL;
+
+	return async_data->result;
+}
+
+gboolean
+e_client_proxy_call_finish_strv (EClient *client, GAsyncResult *result, gchar ***out_strv, GError **error, gpointer source_tag)
+{
+	GSimpleAsyncResult *simple;
+	GError *local_error = NULL;
+	EClientAsyncOpData *async_data;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
+	g_return_val_if_fail (result != NULL, FALSE);
+	g_return_val_if_fail (source_tag != NULL, FALSE);
+	g_return_val_if_fail (out_strv != NULL, FALSE);
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (client), source_tag), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	if (g_simple_async_result_propagate_error (simple, &local_error)) {
+		e_client_unwrap_dbus_error (client, local_error, error);
+		return FALSE;
+	}
+
+	async_data = g_simple_async_result_get_op_res_gpointer (simple);
+	g_return_val_if_fail (async_data != NULL, FALSE);
+
+	*out_strv = async_data->out.val_strv;
+	async_data->out.val_strv = NULL;
+
+	return async_data->result;
+}
+
+gboolean
+e_client_proxy_call_finish_uint (EClient *client, GAsyncResult *result, guint *out_uint, GError **error, gpointer source_tag)
+{
+	GSimpleAsyncResult *simple;
+	GError *local_error = NULL;
+	EClientAsyncOpData *async_data;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
+	g_return_val_if_fail (result != NULL, FALSE);
+	g_return_val_if_fail (source_tag != NULL, FALSE);
+	g_return_val_if_fail (out_uint != NULL, FALSE);
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (client), source_tag), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	if (g_simple_async_result_propagate_error (simple, &local_error)) {
+		e_client_unwrap_dbus_error (client, local_error, error);
+		return FALSE;
+	}
+
+	async_data = g_simple_async_result_get_op_res_gpointer (simple);
+	g_return_val_if_fail (async_data != NULL, FALSE);
+
+	*out_uint = async_data->out.val_uint;
+
+	return async_data->result;
+}
+
+#define SYNC_CALL_TEMPLATE(_out_test,_the_call)			\
+	GDBusProxy *proxy;					\
+	GCancellable *use_cancellable;				\
+	guint32 opid;						\
+	gboolean result;					\
+	GError *local_error = NULL;				\
+								\
+	g_return_val_if_fail (client != NULL, FALSE);		\
+	g_return_val_if_fail (E_IS_CLIENT (client), FALSE);	\
+	g_return_val_if_fail (func != NULL, FALSE);		\
+	g_return_val_if_fail (_out_test != NULL, FALSE);	\
+								\
+	proxy = e_client_get_dbus_proxy (client);		\
+	g_return_val_if_fail (proxy != NULL, FALSE);		\
+								\
+	use_cancellable = cancellable;				\
+	if (!use_cancellable)					\
+		use_cancellable = g_cancellable_new ();		\
+								\
+	g_object_ref (client);					\
+	opid = e_client_register_op (client, use_cancellable);	\
+								\
+	result = func _the_call;				\
+								\
+	e_client_unregister_op (client, opid);			\
+	g_object_unref (client);				\
+								\
+	if (use_cancellable != cancellable)			\
+		g_object_unref (use_cancellable);		\
+								\
+	e_client_unwrap_dbus_error (client, local_error, error);\
+								\
+	return result;
+
+gboolean
+e_client_proxy_call_sync_void__void (EClient *client, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, GCancellable *cancellable, GError **error))
+{
+	SYNC_CALL_TEMPLATE (client, (proxy, use_cancellable, &local_error))
+}
+
+gboolean
+e_client_proxy_call_sync_void__boolean (EClient *client, gboolean *out_boolean, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, gboolean *out_boolean, GCancellable *cancellable, GError **error))
+{
+	SYNC_CALL_TEMPLATE (out_boolean, (proxy, out_boolean, use_cancellable, &local_error))
+}
+
+gboolean
+e_client_proxy_call_sync_void__string (EClient *client, gchar **out_string, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, gchar **out_string, GCancellable *cancellable, GError **error))
+{
+	SYNC_CALL_TEMPLATE (out_string, (proxy, out_string, use_cancellable, &local_error))
+}
+
+gboolean
+e_client_proxy_call_sync_void__strv (EClient *client, gchar ***out_strv, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, gchar ***out_strv, GCancellable *cancellable, GError **error))
+{
+	SYNC_CALL_TEMPLATE (out_strv, (proxy, out_strv, use_cancellable, &local_error))
+}
+
+gboolean
+e_client_proxy_call_sync_void__uint (EClient *client, guint *out_uint, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, guint *out_uint, GCancellable *cancellable, GError **error))
+{
+	SYNC_CALL_TEMPLATE (out_uint, (proxy, out_uint, use_cancellable, &local_error))
+}
+
+gboolean
+e_client_proxy_call_sync_boolean__void (EClient *client, gboolean in_boolean, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, gboolean in_boolean, GCancellable *cancellable, GError **error))
+{
+	SYNC_CALL_TEMPLATE (client, (proxy, in_boolean, use_cancellable, &local_error))
+}
+
+gboolean
+e_client_proxy_call_sync_boolean__boolean (EClient *client, gboolean in_boolean, gboolean *out_boolean, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, gboolean in_boolean, gboolean *out_boolean, GCancellable *cancellable, GError **error))
+{
+	SYNC_CALL_TEMPLATE (out_boolean, (proxy, in_boolean, out_boolean, use_cancellable, &local_error))
+}
+
+gboolean
+e_client_proxy_call_sync_boolean__string (EClient *client, gboolean in_boolean, gchar **out_string, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, gboolean in_boolean, gchar **out_string, GCancellable *cancellable, GError **error))
+{
+	SYNC_CALL_TEMPLATE (out_string, (proxy, in_boolean, out_string, use_cancellable, &local_error))
+}
+
+gboolean
+e_client_proxy_call_sync_boolean__strv (EClient *client, gboolean in_boolean, gchar ***out_strv, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, gboolean in_boolean, gchar ***out_strv, GCancellable *cancellable, GError **error))
+{
+	SYNC_CALL_TEMPLATE (out_strv, (proxy, in_boolean, out_strv, use_cancellable, &local_error))
+}
+
+gboolean
+e_client_proxy_call_sync_boolean__uint (EClient *client, gboolean in_boolean, guint *out_uint, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, gboolean in_boolean, guint *out_uint, GCancellable *cancellable, GError **error))
+{
+	SYNC_CALL_TEMPLATE (out_uint, (proxy, in_boolean, out_uint, use_cancellable, &local_error))
+}
+
+gboolean
+e_client_proxy_call_sync_string__void (EClient *client, const gchar *in_string, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, const gchar *in_string, GCancellable *cancellable, GError **error))
+{
+	SYNC_CALL_TEMPLATE (client, (proxy, in_string, use_cancellable, &local_error))
+}
+
+gboolean
+e_client_proxy_call_sync_string__boolean (EClient *client, const gchar *in_string, gboolean *out_boolean, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, const gchar *in_string, gboolean *out_boolean, GCancellable *cancellable, GError **error))
+{
+	SYNC_CALL_TEMPLATE (out_boolean, (proxy, in_string, out_boolean, use_cancellable, &local_error))
+}
+
+gboolean
+e_client_proxy_call_sync_string__string (EClient *client, const gchar *in_string, gchar **out_string, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, const gchar *in_string, gchar **out_string, GCancellable *cancellable, GError **error))
+{
+	SYNC_CALL_TEMPLATE (out_string, (proxy, in_string, out_string, use_cancellable, &local_error))
+}
+
+gboolean
+e_client_proxy_call_sync_string__strv (EClient *client, const gchar *in_string, gchar ***out_strv, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, const gchar *in_string, gchar ***out_strv, GCancellable *cancellable, GError **error))
+{
+	SYNC_CALL_TEMPLATE (out_strv, (proxy, in_string, out_strv, use_cancellable, &local_error))
+}
+
+gboolean
+e_client_proxy_call_sync_string__uint (EClient *client, const gchar *in_string, guint *out_uint, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, const gchar *in_string, guint *out_uint, GCancellable *cancellable, GError **error))
+{
+	SYNC_CALL_TEMPLATE (out_uint, (proxy, in_string, out_uint, use_cancellable, &local_error))
+}
+
+gboolean
+e_client_proxy_call_sync_strv__void (EClient *client, const gchar * const *in_strv, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, const gchar * const *in_strv, GCancellable *cancellable, GError **error))
+{
+	SYNC_CALL_TEMPLATE (client, (proxy, in_strv, use_cancellable, &local_error))
+}
+
+gboolean
+e_client_proxy_call_sync_strv__boolean (EClient *client, const gchar * const *in_strv, gboolean *out_boolean, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, const gchar * const *in_strv, gboolean *out_boolean, GCancellable *cancellable, GError **error))
+{
+	SYNC_CALL_TEMPLATE (out_boolean, (proxy, in_strv, out_boolean, use_cancellable, &local_error))
+}
+
+gboolean
+e_client_proxy_call_sync_strv__string (EClient *client, const gchar * const *in_strv, gchar **out_string, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, const gchar * const *in_strv, gchar **out_string, GCancellable *cancellable, GError **error))
+{
+	SYNC_CALL_TEMPLATE (out_string, (proxy, in_strv, out_string, use_cancellable, &local_error))
+}
+
+gboolean
+e_client_proxy_call_sync_strv__strv (EClient *client, const gchar * const *in_strv, gchar ***out_strv, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, const gchar * const *in_strv, gchar ***out_strv, GCancellable *cancellable, GError **error))
+{
+	SYNC_CALL_TEMPLATE (out_strv, (proxy, in_strv, out_strv, use_cancellable, &local_error))
+}
+
+gboolean
+e_client_proxy_call_sync_strv__uint (EClient *client, const gchar * const *in_strv, guint *out_uint, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, const gchar * const *in_strv, guint *out_uint, GCancellable *cancellable, GError **error))
+{
+	SYNC_CALL_TEMPLATE (out_uint, (proxy, in_strv, out_uint, use_cancellable, &local_error))
+}
+
+gboolean
+e_client_proxy_call_sync_uint__void (EClient *client, guint in_uint, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, guint in_uint, GCancellable *cancellable, GError **error))
+{
+	SYNC_CALL_TEMPLATE (client, (proxy, in_uint, use_cancellable, &local_error))
+}
+
+gboolean
+e_client_proxy_call_sync_uint__boolean (EClient *client, guint in_uint, gboolean *out_boolean, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, guint in_uint, gboolean *out_boolean, GCancellable *cancellable, GError **error))
+{
+	SYNC_CALL_TEMPLATE (out_boolean, (proxy, in_uint, out_boolean, use_cancellable, &local_error))
+}
+
+gboolean
+e_client_proxy_call_sync_uint__string (EClient *client, guint in_uint, gchar **out_string, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, guint in_uint, gchar **out_string, GCancellable *cancellable, GError **error))
+{
+	SYNC_CALL_TEMPLATE (out_string, (proxy, in_uint, out_string, use_cancellable, &local_error))
+}
+
+gboolean
+e_client_proxy_call_sync_uint__strv (EClient *client, guint in_uint, gchar ***out_strv, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, guint in_uint, gchar ***out_strv, GCancellable *cancellable, GError **error))
+{
+	SYNC_CALL_TEMPLATE (out_strv, (proxy, in_uint, out_strv, use_cancellable, &local_error))
+}
+
+gboolean
+e_client_proxy_call_sync_uint__uint (EClient *client, guint in_uint, guint *out_uint, GCancellable *cancellable, GError **error, gboolean (*func) (GDBusProxy *proxy, guint in_uint, guint *out_uint, GCancellable *cancellable, GError **error))
+{
+	SYNC_CALL_TEMPLATE (out_uint, (proxy, in_uint, out_uint, use_cancellable, &local_error))
+}
+
+#undef SYNC_CALL_TEMPLATE
diff --git a/libedataserver/e-client.h b/libedataserver/e-client.h
new file mode 100644
index 0000000..0d6f793
--- /dev/null
+++ b/libedataserver/e-client.h
@@ -0,0 +1,167 @@
+/*
+ * e-client.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 2011 Red Hat, Inc. (www.redhat.com)
+ *
+ */
+
+#ifndef E_CLIENT_H
+#define E_CLIENT_H
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#include <libedataserver/e-credentials.h>
+#include <libedataserver/e-source.h>
+#include <libedataserver/e-source-list.h>
+
+#define E_TYPE_CLIENT		(e_client_get_type ())
+#define E_CLIENT(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_CLIENT, EClient))
+#define E_CLIENT_CLASS(k)	(G_TYPE_CHECK_CLASS_CAST ((k), E_TYPE_CLIENT, EClientClass))
+#define E_IS_CLIENT(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_CLIENT))
+#define E_IS_CLIENT_CLASS(k)	(G_TYPE_CHECK_CLASS_TYPE ((k), E_TYPE_CLIENT))
+#define E_CLIENT_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS ((obj), E_TYPE_CLIENT, EClientClass))
+
+#define CLIENT_BACKEND_PROPERTY_OPENED			"opened"
+#define CLIENT_BACKEND_PROPERTY_OPENING			"opening"
+#define CLIENT_BACKEND_PROPERTY_ONLINE			"online"
+#define CLIENT_BACKEND_PROPERTY_READONLY		"readonly"
+#define CLIENT_BACKEND_PROPERTY_CACHE_DIR		"cache-dir"
+#define CLIENT_BACKEND_PROPERTY_CAPABILITIES		"capabilities"
+
+#define E_CLIENT_ERROR		e_client_error_quark ()
+
+GQuark e_client_error_quark (void) G_GNUC_CONST;
+
+typedef enum {
+	E_CLIENT_ERROR_INVALID_ARG,
+	E_CLIENT_ERROR_BUSY,
+	E_CLIENT_ERROR_SOURCE_NOT_LOADED,
+	E_CLIENT_ERROR_SOURCE_ALREADY_LOADED,
+	E_CLIENT_ERROR_AUTHENTICATION_FAILED,
+	E_CLIENT_ERROR_AUTHENTICATION_REQUIRED,
+	E_CLIENT_ERROR_REPOSITORY_OFFLINE,
+	E_CLIENT_ERROR_PERMISSION_DENIED,
+	E_CLIENT_ERROR_CANCELLED,
+	E_CLIENT_ERROR_COULD_NOT_CANCEL,
+	E_CLIENT_ERROR_NOT_SUPPORTED,
+	E_CLIENT_ERROR_DBUS_ERROR,
+	E_CLIENT_ERROR_OTHER_ERROR
+} EClientError;
+
+const gchar *e_client_error_to_string (EClientError code);
+
+typedef struct _EClient        EClient;
+typedef struct _EClientClass   EClientClass;
+typedef struct _EClientPrivate EClientPrivate;
+
+struct _EClient {
+	GObject parent;
+
+	/*< private >*/
+	EClientPrivate *priv;
+};
+
+struct _EClientClass {
+	GObjectClass parent;
+
+	/* virtual methods */
+	GDBusProxy *	(* get_dbus_proxy) (EClient *client);
+	void		(* unwrap_dbus_error) (EClient *client, GError *dbus_error, GError **out_error);
+
+	void		(* get_backend_property) (EClient *client, const gchar *prop_name, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+	gboolean	(* get_backend_property_finish) (EClient *client, GAsyncResult *result, gchar **prop_value, GError **error);
+	gboolean	(* get_backend_property_sync) (EClient *client, const gchar *prop_name, gchar **prop_value, GCancellable *cancellable, GError **error);
+
+	void		(* set_backend_property) (EClient *client, const gchar *prop_name, const gchar *prop_value, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+	gboolean	(* set_backend_property_finish) (EClient *client, GAsyncResult *result, GError **error);
+	gboolean	(* set_backend_property_sync) (EClient *client, const gchar *prop_name, const gchar *prop_value, GCancellable *cancellable, GError **error);
+
+	void		(* open) (EClient *client, gboolean only_if_exists, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+	gboolean	(* open_finish) (EClient *client, GAsyncResult *result, GError **error);
+	gboolean	(* open_sync) (EClient *client, gboolean only_if_exists, GCancellable *cancellable, GError **error);
+
+	void		(* remove) (EClient *client, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+	gboolean	(* remove_finish) (EClient *client, GAsyncResult *result, GError **error);
+	gboolean	(* remove_sync) (EClient *client, GCancellable *cancellable, GError **error);
+
+	void		(* refresh) (EClient *client, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+	gboolean	(* refresh_finish) (EClient *client, GAsyncResult *result, GError **error);
+	gboolean	(* refresh_sync) (EClient *client, GCancellable *cancellable, GError **error);
+
+	void		(* handle_authentication) (EClient *client, const ECredentials *credentials);
+	gchar *		(* retrieve_capabilities) (EClient *client);
+
+	/* signals */
+	gboolean	(* authenticate) (EClient *client, ECredentials *credentials);
+	void		(* opened) (EClient *client, const GError *error);
+	void		(* backend_error) (EClient *client, const gchar *error_msg);
+	void		(* backend_died) (EClient *client);
+};
+
+GType		e_client_get_type			(void);
+
+ESource *	e_client_get_source			(EClient *client);
+const gchar *	e_client_get_uri			(EClient *client);
+const GSList *	e_client_get_capabilities		(EClient *client);
+gboolean	e_client_check_capability		(EClient *client, const gchar *capability);
+gboolean	e_client_check_refresh_supported	(EClient *client);
+gboolean	e_client_is_readonly			(EClient *client);
+gboolean	e_client_is_online			(EClient *client);
+gboolean	e_client_is_opened			(EClient *client);
+
+void		e_client_cancel_all			(EClient *client);
+
+void		e_client_get_backend_property		(EClient *client, const gchar *prop_name, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_client_get_backend_property_finish	(EClient *client, GAsyncResult *result, gchar **prop_value, GError **error);
+gboolean	e_client_get_backend_property_sync	(EClient *client, const gchar *prop_name, gchar **prop_value, GCancellable *cancellable, GError **error);
+
+void		e_client_set_backend_property		(EClient *client, const gchar *prop_name, const gchar *prop_value, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_client_set_backend_property_finish	(EClient *client, GAsyncResult *result, GError **error);
+gboolean	e_client_set_backend_property_sync	(EClient *client, const gchar *prop_name, const gchar *prop_value, GCancellable *cancellable, GError **error);
+
+void		e_client_open				(EClient *client, gboolean only_if_exists, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_client_open_finish			(EClient *client, GAsyncResult *result, GError **error);
+gboolean	e_client_open_sync			(EClient *client, gboolean only_if_exists, GCancellable *cancellable, GError **error);
+
+void		e_client_remove				(EClient *client, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_client_remove_finish			(EClient *client, GAsyncResult *result, GError **error);
+gboolean	e_client_remove_sync			(EClient *client, GCancellable *cancellable, GError **error);
+
+void		e_client_refresh			(EClient *client, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+gboolean	e_client_refresh_finish			(EClient *client, GAsyncResult *result, GError **error);
+gboolean	e_client_refresh_sync			(EClient *client, GCancellable *cancellable, GError **error);
+
+/* utility functions */
+gchar **	e_client_util_slist_to_strv		(const GSList *strings);
+GSList *	e_client_util_strv_to_slist		(const gchar * const *strv);
+GSList *	e_client_util_copy_string_slist		(GSList *copy_to, const GSList *strings);
+GSList *	e_client_util_copy_object_slist		(GSList *copy_to, const GSList *objects);
+void		e_client_util_free_string_slist		(GSList *strings);
+void		e_client_util_free_object_slist		(GSList *objects);
+GSList *	e_client_util_parse_comma_strings	(const gchar *capabilities);
+
+struct EClientErrorsList {
+	const gchar *name;
+	gint err_code;
+};
+
+gboolean	e_client_util_unwrap_dbus_error		(GError *dbus_error, GError **client_error, const struct EClientErrorsList *known_errors, guint known_errors_count, GQuark known_errors_domain, gboolean fail_when_none_matched);
+
+G_END_DECLS
+
+#endif /* E_CLIENT_H */
diff --git a/libedataserver/e-credentials.c b/libedataserver/e-credentials.c
new file mode 100644
index 0000000..ab4910c
--- /dev/null
+++ b/libedataserver/e-credentials.c
@@ -0,0 +1,560 @@
+/*
+ * e-credentials.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 2011 Red Hat, Inc. (www.redhat.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "e-data-server-util.h"
+
+#include "e-credentials.h"
+
+struct _ECredentialsPrivate
+{
+	GHashTable *keys;
+	GHashTable *peek_keys;
+};
+
+static gboolean
+key_equal (gconstpointer str1, gconstpointer str2)
+{
+	g_return_val_if_fail (str1 != NULL, FALSE);
+	g_return_val_if_fail (str2 != NULL, FALSE);
+
+	if (str1 == str2)
+		return TRUE;
+
+	return g_ascii_strcasecmp (str1, str2) == 0;
+}
+
+ECredentials *
+e_credentials_new (void)
+{
+	ECredentials *credentials;
+
+	credentials = g_new0 (ECredentials, 1);
+	credentials->priv = g_new0 (ECredentialsPrivate, 1);
+	credentials->priv->keys = g_hash_table_new_full (g_str_hash, key_equal, g_free, (GDestroyNotify) e_credentials_util_safe_free_string);
+	credentials->priv->peek_keys = g_hash_table_new_full (g_str_hash, key_equal, g_free, (GDestroyNotify) e_credentials_util_safe_free_string);
+
+	return credentials;
+}
+
+/* Expects @keys as NULL terminate list of strings "key:encoded_value".
+   The same can be returned from e_credentials_to_strv().
+*/
+ECredentials *
+e_credentials_new_strv (const gchar * const *keys)
+{
+	ECredentials *credentials;
+	gint ii;
+
+	g_return_val_if_fail (keys != NULL, NULL);
+
+	credentials = e_credentials_new ();
+
+	for (ii = 0; keys[ii]; ii++) {
+		const gchar *key = keys[ii], *sep;
+
+		sep = strchr (key, ':');
+
+		/* skip empty and invalid values */
+		if (sep)
+			g_hash_table_insert (credentials->priv->keys, g_strndup (key, sep - key), g_strdup (sep + 1));
+	}
+
+	return credentials;
+}
+
+/* NULL-terminated list of string pairs <key, value>; value is in a clear form */
+ECredentials *
+e_credentials_new_args	(const gchar *key, ...)
+{
+	ECredentials *credentials;
+	va_list va;
+
+	g_return_val_if_fail (key != NULL, NULL);
+
+	credentials = e_credentials_new ();
+
+	va_start (va, key);
+
+	while (key) {
+		const gchar *value = va_arg (va, const gchar *);
+
+		if (key && *key && value && *value)
+			e_credentials_set (credentials, key, value);
+
+		key = va_arg (va, const gchar *);
+	}
+
+	va_end (va);
+
+	return credentials;
+}
+
+static void
+copy_keys_cb (gpointer key, gpointer value, gpointer hash_table)
+{
+	g_hash_table_insert (hash_table, g_strdup (key), g_strdup (value));
+}
+
+ECredentials *
+e_credentials_new_clone	(const ECredentials *credentials)
+{
+	ECredentials *res;
+
+	g_return_val_if_fail (credentials != NULL, NULL);
+	g_return_val_if_fail (credentials->priv != NULL, NULL);
+	g_return_val_if_fail (credentials->priv->keys != NULL, NULL);
+
+	res = e_credentials_new ();
+
+	g_hash_table_foreach (credentials->priv->keys, copy_keys_cb, res->priv->keys);
+
+	return res;
+}
+
+void
+e_credentials_free (ECredentials *credentials)
+{
+	if (!credentials)
+		return;
+
+	g_return_if_fail (credentials->priv != NULL);
+
+	g_hash_table_destroy (credentials->priv->keys);
+	g_hash_table_destroy (credentials->priv->peek_keys);
+	g_free (credentials->priv);
+	g_free (credentials);
+}
+
+static void
+add_to_array_cb (gpointer key, gpointer value, gpointer ptr_array)
+{
+	if (key && value && ptr_array) {
+		gchar *str = g_strconcat (key, ":", value, NULL);
+
+		g_ptr_array_add (ptr_array, e_util_utf8_make_valid (str));
+
+		g_free (str);
+	}
+}
+
+/* Returns NULL-terminated array of strings with keys and encoded values;
+   To read them back pass this pointer to e_credentials_new(). As it returns
+   newly allocated string then this should be freed with g_strfreev()
+   when no longer needed.
+*/
+gchar **
+e_credentials_to_strv (const ECredentials *credentials)
+{
+	GPtrArray *array;
+
+	g_return_val_if_fail (credentials != NULL, NULL);
+	g_return_val_if_fail (credentials->priv != NULL, NULL);
+	g_return_val_if_fail (credentials->priv->keys != NULL, NULL);
+
+	array = g_ptr_array_sized_new (g_hash_table_size (credentials->priv->keys) + 1);
+
+	g_hash_table_foreach (credentials->priv->keys, add_to_array_cb, array);
+
+	/* NULL-terminated */
+	g_ptr_array_add (array, NULL);
+
+	return (gchar **) g_ptr_array_free (array, FALSE);
+}
+
+static gchar *
+encode_string (const gchar *decoded)
+{
+	gsize len, ii;
+	guchar xval, *copy;
+	gchar *res;
+
+	if (!decoded || !*decoded)
+		return NULL;
+
+	copy = (guchar *) g_strdup (decoded);
+	len = strlen ((const gchar *) copy);
+
+	xval = 17;
+	for (ii = 0; ii < len; ii++) {
+		copy[ii] = copy[ii] ^ xval;
+		xval += 17;
+	}
+
+	res = g_base64_encode (copy, len);
+
+	g_free (copy);
+
+	return res;
+}
+
+static gchar *
+decode_string (const gchar *encoded)
+{
+	guchar *data, xval;
+	gsize len = 0, ii;
+	gchar *res;
+
+	g_return_val_if_fail (encoded != NULL, NULL);
+	g_return_val_if_fail (*encoded, NULL);
+
+	data = g_base64_decode (encoded, &len);
+	g_return_val_if_fail (data != NULL, NULL);
+	g_return_val_if_fail (len > 0, NULL);
+
+	xval = 17;
+	for (ii = 0; ii < len; ii++) {
+		data[ii] = data[ii] ^ xval;
+		xval += 17;
+	}
+
+	res = g_strndup ((const gchar *) data, len);
+
+	e_credentials_util_safe_free_string ((gchar *) data);
+
+	return res;
+}
+
+/* sets value for a key, if value is NULL or an empty string then the key is removed.
+   the value is supposed to be in a clear form (unencoded).
+   'key' cannot contain colon.
+*/
+void
+e_credentials_set (ECredentials *credentials, const gchar *key, const gchar *value)
+{
+	g_return_if_fail (credentials != NULL);
+	g_return_if_fail (credentials->priv != NULL);
+	g_return_if_fail (credentials->priv->keys != NULL);
+	g_return_if_fail (credentials->priv->peek_keys != NULL);
+	g_return_if_fail (key != NULL);
+	g_return_if_fail (*key);
+	g_return_if_fail (strchr (key, ':') == NULL);
+
+	g_hash_table_remove (credentials->priv->peek_keys, key);
+
+	if (!value) {
+		g_hash_table_remove (credentials->priv->keys, key);
+	} else {
+		g_hash_table_insert (credentials->priv->keys, g_strdup (key), encode_string (value));
+	}
+}
+
+/* Returned pointer should be freed with e_credentials_util_safe_free_string()
+   when no longer needed.
+*/
+gchar *
+e_credentials_get (const ECredentials *credentials, const gchar *key)
+{
+	const gchar *stored;
+
+	g_return_val_if_fail (credentials != NULL, NULL);
+	g_return_val_if_fail (credentials->priv != NULL, NULL);
+	g_return_val_if_fail (credentials->priv->keys != NULL, NULL);
+	g_return_val_if_fail (key != NULL, NULL);
+	g_return_val_if_fail (*key, NULL);
+
+	stored = g_hash_table_lookup (credentials->priv->keys, key);
+	if (!stored)
+		return NULL;
+
+	return decode_string (stored);
+}
+
+/* peeks value for a key, in a clear form. The value is valid until free
+   of the @credentials structure or until the key value is rewritten
+   by e_credentials_set()
+*/
+const gchar *
+e_credentials_peek (ECredentials *credentials, const gchar *key)
+{
+	gchar *value;
+
+	g_return_val_if_fail (credentials != NULL, NULL);
+	g_return_val_if_fail (credentials->priv != NULL, NULL);
+	g_return_val_if_fail (credentials->priv->peek_keys != NULL, NULL);
+	g_return_val_if_fail (key != NULL, NULL);
+	g_return_val_if_fail (*key, NULL);
+
+	value = g_hash_table_lookup (credentials->priv->peek_keys, key);
+	if (value)
+		return value;
+
+	value = e_credentials_get (credentials, key);
+	if (value)
+		g_hash_table_insert (credentials->priv->peek_keys, g_strdup (key), value);
+
+	return value;
+}
+
+struct equal_data
+{
+	gboolean equal;
+	GHashTable *keys;
+};
+
+static void
+check_equal_cb (gpointer key, gpointer value, gpointer user_data)
+{
+	struct equal_data *ed = user_data;
+
+	g_return_if_fail (ed != NULL);
+	g_return_if_fail (ed->keys != NULL);
+	g_return_if_fail (key != NULL);
+	g_return_if_fail (value != NULL);
+
+	ed->equal = ed->equal && g_strcmp0 (value, g_hash_table_lookup (ed->keys, key)) == 0;
+}
+
+/* Returns whether two credential structurs contain the same keys with same values */
+gboolean
+e_credentials_equal (const ECredentials *credentials1, const ECredentials *credentials2)
+{
+	struct equal_data ed;
+
+	if (!credentials1 && !credentials2)
+		return TRUE;
+
+	if (credentials1 == credentials2)
+		return TRUE;
+
+	if (!credentials1 || !credentials2)
+		return FALSE;
+
+	g_return_val_if_fail (credentials1->priv != NULL, FALSE);
+	g_return_val_if_fail (credentials1->priv->keys != NULL, FALSE);
+	g_return_val_if_fail (credentials2->priv != NULL, FALSE);
+	g_return_val_if_fail (credentials2->priv->keys != NULL, FALSE);
+
+	if (g_hash_table_size (credentials1->priv->keys) != g_hash_table_size (credentials2->priv->keys))
+		return FALSE;
+
+	ed.equal = TRUE;
+	ed.keys = credentials2->priv->keys;
+
+	g_hash_table_foreach (credentials1->priv->keys, check_equal_cb, &ed);
+
+	return ed.equal;
+}
+
+/* Returns whether two credentials structures has same keys. Key names are NULL-terminated. */
+gboolean
+e_credentials_equal_keys (const ECredentials *credentials1, const ECredentials *credentials2, const gchar *key1, ...)
+{
+	va_list va;
+	gboolean equal = TRUE;
+
+	g_return_val_if_fail (credentials1 != NULL, FALSE);
+	g_return_val_if_fail (credentials1->priv != NULL, FALSE);
+	g_return_val_if_fail (credentials1->priv->keys != NULL, FALSE);
+	g_return_val_if_fail (credentials2 != NULL, FALSE);
+	g_return_val_if_fail (credentials2->priv != NULL, FALSE);
+	g_return_val_if_fail (credentials2->priv->keys != NULL, FALSE);
+	g_return_val_if_fail (key1 != NULL, FALSE);
+
+	va_start (va, key1);
+
+	while (key1 && equal) {
+		equal = g_strcmp0 (g_hash_table_lookup (credentials1->priv->keys, key1), g_hash_table_lookup (credentials2->priv->keys, key1)) == 0;
+
+		key1 = va_arg (va, const gchar *);
+	}
+
+	va_end (va);
+
+	return equal;
+}	
+
+/**
+ * Returns whether @credentials contains @key.
+ * This key is non-NULL and non-empty string.
+ **/
+gboolean
+e_credentials_has_key (const ECredentials *credentials, const gchar *key)
+{
+	g_return_val_if_fail (credentials != NULL, FALSE);
+	g_return_val_if_fail (credentials->priv != NULL, FALSE);
+	g_return_val_if_fail (credentials->priv->keys != NULL, FALSE);
+	g_return_val_if_fail (key != NULL, FALSE);
+	g_return_val_if_fail (*key, FALSE);
+
+	return g_hash_table_lookup (credentials->priv->keys, key) != NULL;
+}
+
+guint
+e_credentials_keys_size (const ECredentials *credentials)
+{
+	g_return_val_if_fail (credentials != NULL, 0);
+	g_return_val_if_fail (credentials->priv != NULL, 0);
+	g_return_val_if_fail (credentials->priv->keys != NULL, 0);
+
+	return g_hash_table_size (credentials->priv->keys);
+}
+
+static void
+gather_key_names (gpointer key, gpointer value, gpointer pslist)
+{
+	GSList **slist = pslist;
+
+	g_return_if_fail (pslist != NULL);
+	g_return_if_fail (key != NULL);
+
+	*slist = g_slist_prepend (*slist, key);
+}
+
+/* Returns newly allocated list of key names stored in the credentials strucutre;
+   strings are internal credentials values, only the list is newly allocated.
+   Free the list with g_slist_free() when no longer needed.
+*/
+GSList *
+e_credentials_list_keys	(const ECredentials *credentials)
+{
+	GSList *keys = NULL;
+
+	g_return_val_if_fail (credentials != NULL, NULL);
+	g_return_val_if_fail (credentials->priv != NULL, NULL);
+	g_return_val_if_fail (credentials->priv->keys != NULL, NULL);
+
+	g_hash_table_foreach (credentials->priv->keys, gather_key_names, &keys);
+
+	return g_slist_reverse (keys);
+}
+
+/* Removes all keys in once. */
+void
+e_credentials_clear (ECredentials *credentials)
+{
+	g_return_if_fail (credentials != NULL);
+	g_return_if_fail (credentials->priv != NULL);
+	g_return_if_fail (credentials->priv->keys != NULL);
+	g_return_if_fail (credentials->priv->peek_keys != NULL);
+
+	g_hash_table_remove_all (credentials->priv->peek_keys);
+	g_hash_table_remove_all (credentials->priv->keys);
+}
+
+void
+e_credentials_clear_peek (ECredentials *credentials)
+{
+	g_return_if_fail (credentials != NULL);
+	g_return_if_fail (credentials->priv != NULL);
+	g_return_if_fail (credentials->priv->peek_keys != NULL);
+
+	g_hash_table_remove_all (credentials->priv->peek_keys);
+}
+
+void
+e_credentials_util_safe_free_string (gchar *str)
+{
+	if (!str)
+		return;
+
+	if (*str)
+		memset (str, 0, sizeof (gchar) * strlen (str));
+
+	g_free (str);
+}
+
+static struct _PromptFlags {
+	ECredentialsPromptFlags flag_uint;
+	const gchar *flag_string;
+	gboolean is_bit_flag; /* if false, then checked against E_CREDENTIALS_PROMPT_FLAG_REMEMBER_MASK */
+} PromptFlags[] = {
+	{ E_CREDENTIALS_PROMPT_FLAG_REMEMBER_NEVER,	"remember-never",	FALSE },
+	{ E_CREDENTIALS_PROMPT_FLAG_REMEMBER_SESSION,	"remember-session",	FALSE },
+	{ E_CREDENTIALS_PROMPT_FLAG_REMEMBER_FOREVER,	"remember-forever",	FALSE },
+
+	{ E_CREDENTIALS_PROMPT_FLAG_SECRET,		"secret",		TRUE },
+	{ E_CREDENTIALS_PROMPT_FLAG_REPROMPT,		"reprompt",		TRUE },
+	{ E_CREDENTIALS_PROMPT_FLAG_ONLINE,		"online",		TRUE },
+	{ E_CREDENTIALS_PROMPT_FLAG_DISABLE_REMEMBER,	"disable-remember",	TRUE },
+	{ E_CREDENTIALS_PROMPT_FLAG_PASSPHRASE,		"passphrase",		TRUE }
+};
+
+/* Returned pointer can be passed to e_credentials_util_string_to prompt_flags()
+   to decode it back to flags. Free returned pointer with g_free().
+*/
+gchar *
+e_credentials_util_prompt_flags_to_string (guint prompt_flags)
+{
+	gint ii;
+	guint masked = prompt_flags & E_CREDENTIALS_PROMPT_FLAG_REMEMBER_MASK;
+	GString *str = g_string_new ("");
+
+	for (ii = 0; ii < G_N_ELEMENTS (PromptFlags); ii++) {
+		const gchar *add = NULL;
+
+		if (PromptFlags[ii].is_bit_flag) {
+			if ((prompt_flags & PromptFlags[ii].flag_uint) != 0)
+				add = PromptFlags[ii].flag_string;
+		} else if (masked == PromptFlags[ii].flag_uint) {
+			add = PromptFlags[ii].flag_string;
+		}
+
+		if (!add)
+			continue;
+
+		if (str->len)
+			g_string_append (str, ",");
+
+		g_string_append (str, add);
+	}
+
+	return g_string_free (str, FALSE);
+}
+
+guint
+e_credentials_util_string_to_prompt_flags (const gchar *prompt_flags_string)
+{
+	gchar **strv;
+	gint ii, jj;
+	guint flags = 0;
+
+	if (!prompt_flags_string || !*prompt_flags_string)
+		return flags;
+
+	strv = g_strsplit (prompt_flags_string, ",", -1);
+	if (!strv)
+		return flags;
+
+	for (jj = 0; strv[jj]; jj++) {
+		const gchar *str = strv[jj];
+
+		for (ii = 0; ii < G_N_ELEMENTS (PromptFlags); ii++) {
+			if (g_str_equal (PromptFlags[ii].flag_string, str)) {
+				if (PromptFlags[ii].is_bit_flag)
+					flags |= PromptFlags[ii].flag_uint;
+				else
+					flags = (flags & (~E_CREDENTIALS_PROMPT_FLAG_REMEMBER_MASK)) | PromptFlags[ii].flag_uint;
+			}
+		}
+	}
+
+	g_strfreev (strv);
+
+	return flags;
+}
diff --git a/libedataserver/e-credentials.h b/libedataserver/e-credentials.h
new file mode 100644
index 0000000..06b0f26
--- /dev/null
+++ b/libedataserver/e-credentials.h
@@ -0,0 +1,87 @@
+/*
+ * e-credentials.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 2011 Red Hat, Inc. (www.redhat.com)
+ *
+ */
+
+#ifndef E_CREDENTIALS_H
+#define E_CREDENTIALS_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct _ECredentialsPrivate ECredentialsPrivate;
+
+typedef struct _ECredentials
+{
+	ECredentialsPrivate *priv;
+} ECredentials;
+
+#define E_CREDENTIALS_KEY_USERNAME	"username"
+#define E_CREDENTIALS_KEY_PASSWORD	"password"
+#define E_CREDENTIALS_KEY_AUTH_METHOD	"auth-method"
+#define E_CREDENTIALS_KEY_AUTH_DOMAIN	"auth-domain"
+#define E_CREDENTIALS_KEY_PROMPT_TITLE	"prompt-title"
+#define E_CREDENTIALS_KEY_PROMPT_TEXT	"prompt-text"
+#define E_CREDENTIALS_KEY_PROMPT_REASON	"prompt-reason"
+#define E_CREDENTIALS_KEY_PROMPT_KEY	"prompt-key"
+#define E_CREDENTIALS_KEY_PROMPT_FLAGS	"prompt-flags"
+
+#define E_CREDENTIALS_AUTH_DOMAIN_ADDRESSBOOK	"Addressbook"
+#define E_CREDENTIALS_AUTH_DOMAIN_CALENDAR	"Calendar"
+#define E_CREDENTIALS_AUTH_DOMAIN_MAIL		"Mail"
+
+/* this is 1:1 with EPasswordsRememberType */
+typedef enum {
+	E_CREDENTIALS_PROMPT_FLAG_REMEMBER_NEVER,
+	E_CREDENTIALS_PROMPT_FLAG_REMEMBER_SESSION,
+	E_CREDENTIALS_PROMPT_FLAG_REMEMBER_FOREVER,
+	E_CREDENTIALS_PROMPT_FLAG_REMEMBER_MASK = 0xf,
+
+	E_CREDENTIALS_PROMPT_FLAG_SECRET = 1 << 8, /* whether hide password letters in the UI */
+	E_CREDENTIALS_PROMPT_FLAG_REPROMPT = 1 << 9, /* automatically set when username and password is provided */
+	E_CREDENTIALS_PROMPT_FLAG_ONLINE = 1 << 10, /* only ask if we're online */
+	E_CREDENTIALS_PROMPT_FLAG_DISABLE_REMEMBER = 1 << 11, /* disable the 'remember password' checkbox */
+	E_CREDENTIALS_PROMPT_FLAG_PASSPHRASE = 1 << 12 /* We are asking a passphrase */
+} ECredentialsPromptFlags;
+
+ECredentials *	e_credentials_new	(void);
+ECredentials *	e_credentials_new_strv	(const gchar * const *strv);
+ECredentials *	e_credentials_new_args	(const gchar *key, ...) G_GNUC_NULL_TERMINATED;
+ECredentials *	e_credentials_new_clone	(const ECredentials *credentials);
+void		e_credentials_free	(      ECredentials *credentials);
+gchar **	e_credentials_to_strv	(const ECredentials *credentials);
+void		e_credentials_set	(      ECredentials *credentials, const gchar *key, const gchar *value);
+gchar *		e_credentials_get	(const ECredentials *credentials, const gchar *key);
+const gchar *	e_credentials_peek	(      ECredentials *credentials, const gchar *key);
+gboolean	e_credentials_equal	(const ECredentials *credentials1, const ECredentials *credentials2);
+gboolean	e_credentials_equal_keys(const ECredentials *credentials1, const ECredentials *credentials2, const gchar *key1, ...) G_GNUC_NULL_TERMINATED;
+gboolean	e_credentials_has_key	(const ECredentials *credentials, const gchar *key);
+guint		e_credentials_keys_size	(const ECredentials *credentials);
+GSList *	e_credentials_list_keys	(const ECredentials *credentials);
+void		e_credentials_clear	(      ECredentials *credentials);
+void		e_credentials_clear_peek(      ECredentials *credentials);
+
+void		e_credentials_util_safe_free_string (gchar *str);
+gchar *		e_credentials_util_prompt_flags_to_string (guint prompt_flags); /* bit-or of ECredentialsPromptFlags */
+guint		e_credentials_util_string_to_prompt_flags (const gchar *prompt_flags_string); /* bit-or of ECredentialsPromptFlags */
+
+G_END_DECLS
+
+#endif /* E_CREDENTIALS_H */
diff --git a/libedataserver/e-data-server-util.c b/libedataserver/e-data-server-util.c
index af7deac..6085b2d 100644
--- a/libedataserver/e-data-server-util.c
+++ b/libedataserver/e-data-server-util.c
@@ -910,3 +910,87 @@ e_data_server_util_get_dbus_call_timeout (void)
 {
 	return default_dbus_timeout;
 }
+
+G_LOCK_DEFINE_STATIC (ptr_tracker);
+static GHashTable *ptr_tracker = NULL;
+
+static void
+dump_left_ptrs_cb (gpointer ptr, gpointer info, gpointer user_data)
+{
+	g_print ("      %p %s%s%s", ptr, info ? "(" : "", info ? (const gchar *) info : "", info ? ")" : "");
+}
+
+static void
+dump_tracked_ptrs (gboolean is_at_exit)
+{
+	G_LOCK (ptr_tracker);
+
+	if (ptr_tracker) {
+		g_print ("\n----------------------------------------------------------\n");
+		if (g_hash_table_size (ptr_tracker) == 0) {
+			g_print ("   All tracked pointers were properly removed\n");
+		} else {
+			g_print ("   Left %d tracked pointers:\n", g_hash_table_size (ptr_tracker));
+			g_hash_table_foreach (ptr_tracker, dump_left_ptrs_cb, NULL);
+		}
+		g_print ("----------------------------------------------------------\n");
+	} else if (!is_at_exit) {
+		g_print ("\n----------------------------------------------------------\n");
+		g_print ("   Did not track any pointers yet\n");
+		g_print ("----------------------------------------------------------\n");
+	}
+
+	G_UNLOCK (ptr_tracker);
+}
+
+static void
+dump_left_at_exit_cb (void)
+{
+	dump_tracked_ptrs (TRUE);
+
+	G_LOCK (ptr_tracker);
+	if (ptr_tracker) {
+		g_hash_table_destroy (ptr_tracker);
+		ptr_tracker = NULL;
+	}
+	G_UNLOCK (ptr_tracker);
+}
+
+void
+e_pointer_tracker_track_with_info (gpointer ptr, const gchar *info)
+{
+	g_return_if_fail (ptr != NULL);
+
+	G_LOCK (ptr_tracker);
+	if (!ptr_tracker) {
+		ptr_tracker = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
+		g_atexit (dump_left_at_exit_cb);
+	}
+
+	g_hash_table_insert (ptr_tracker, ptr, g_strdup (info));
+
+	G_UNLOCK (ptr_tracker);
+}
+
+void
+e_pointer_tracker_untrack (gpointer ptr)
+{
+	g_return_if_fail (ptr != NULL);
+
+	G_LOCK (ptr_tracker);
+
+	if (!ptr_tracker)
+		g_printerr ("Pointer tracker not initialized, thus cannot remove %p\n", ptr);
+	else if (!g_hash_table_lookup (ptr_tracker, ptr))
+		g_printerr ("Pointer %p is not tracked\n", ptr);
+	else
+		g_hash_table_remove (ptr_tracker, ptr);
+
+	G_UNLOCK (ptr_tracker);
+}
+
+void
+e_pointer_tracker_dump (void)
+{
+	dump_tracked_ptrs (FALSE);
+}
diff --git a/libedataserver/e-data-server-util.h b/libedataserver/e-data-server-util.h
index 0fa514d..0a52578 100644
--- a/libedataserver/e-data-server-util.h
+++ b/libedataserver/e-data-server-util.h
@@ -73,6 +73,11 @@ gint		e_data_server_util_get_dbus_call_timeout
 void		e_data_server_util_set_dbus_call_timeout
 						(gint timeout_msec);
 
+#define		e_pointer_tracker_track(ptr) e_pointer_tracker_track_with_info (ptr, G_STRFUNC)
+void		e_pointer_tracker_track_with_info (gpointer ptr, const gchar *info);
+void		e_pointer_tracker_untrack (gpointer ptr);
+void		e_pointer_tracker_dump (void);
+
 G_END_DECLS
 
 #endif /* E_DATA_SERVER_UTIL_H */
diff --git a/addressbook/libegdbus/e-gdbus-marshallers.list b/libedataserver/e-gdbus-marshallers.list
similarity index 55%
rename from addressbook/libegdbus/e-gdbus-marshallers.list
rename to libedataserver/e-gdbus-marshallers.list
index 46f24d4..9bf81c4 100644
--- a/addressbook/libegdbus/e-gdbus-marshallers.list
+++ b/libedataserver/e-gdbus-marshallers.list
@@ -1,10 +1,13 @@
-BOOLEAN:OBJECT,STRING
-VOID:BOXED
-VOID:STRING
-VOID:UINT,STRING
+BOOLEAN:POINTER
 BOOLEAN:OBJECT
-VOID:BOOLEAN
 BOOLEAN:OBJECT,BOOLEAN
-BOOLEAN:OBJECT,STRING,STRING,STRING
 BOOLEAN:OBJECT,BOXED
-BOOLEAN:OBJECT,STRING,UINT
+BOOLEAN:OBJECT,STRING
+BOOLEAN:OBJECT,UINT
+VOID:UINT,BOXED
+VOID:UINT,BOXED,STRING
+VOID:UINT,BOXED,BOXED
+VOID:UINT,STRING
+
+VOID:BOXED
+VOID:STRING
diff --git a/libedataserver/e-gdbus-templates.c b/libedataserver/e-gdbus-templates.c
new file mode 100644
index 0000000..3d8b450
--- /dev/null
+++ b/libedataserver/e-gdbus-templates.c
@@ -0,0 +1,1710 @@
+/*
+ * e-gdbus-templates.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 2011 Red Hat, Inc. (www.redhat.com)
+ *
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gio/gio.h>
+
+#include <stdio.h>
+
+#include "e-data-server-util.h"
+#include "e-flag.h"
+#include "e-gdbus-templates.h"
+
+gboolean
+e_gdbus_signal_emission_hook_void (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, const gchar *signal_name, const gchar *iface_name)
+{
+	GObject *object;
+	GDBusConnection *connection;
+	const gchar *path;
+
+	if (n_param_values < 1 || !G_VALUE_HOLDS (&param_values[0], G_TYPE_OBJECT))
+		return FALSE;
+
+	object = g_value_get_object (&param_values[0]);
+	path = g_object_get_data (object, "gdbus-codegen-path");
+	connection = g_object_get_data (object, "gdbus-codegen-connection");
+	if (connection == NULL || path == NULL)
+		return FALSE;
+
+	g_dbus_connection_emit_signal (connection, NULL, path, iface_name, signal_name, NULL, NULL);
+
+	return TRUE;
+}
+
+gboolean
+e_gdbus_signal_emission_hook_boolean (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, const gchar *signal_name, const gchar *iface_name)
+{
+	GObject *object;
+	GDBusConnection *connection;
+	const gchar *path;
+	GVariant *params;
+	GVariant *item;
+	GVariantBuilder *builder;
+
+	if (n_param_values < 1 || !G_VALUE_HOLDS (&param_values[0], G_TYPE_OBJECT))
+		return FALSE;
+
+	object = g_value_get_object (&param_values[0]);
+	path = g_object_get_data (object, "gdbus-codegen-path");
+	connection = g_object_get_data (object, "gdbus-codegen-connection");
+	if (connection == NULL || path == NULL)
+		return FALSE;
+
+	builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
+	g_assert_cmpint (n_param_values - 1, ==, 1);
+	param_values++;
+	item = g_variant_new_boolean (g_value_get_boolean (param_values));
+	g_variant_builder_add_value (builder, item);
+	param_values++;
+	params = g_variant_builder_end (builder);
+	g_variant_builder_unref (builder);
+
+	g_dbus_connection_emit_signal (connection, NULL, path, iface_name, signal_name, params, NULL);
+
+	return TRUE;
+}
+
+gboolean
+e_gdbus_signal_emission_hook_string (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, const gchar *signal_name, const gchar *iface_name)
+{
+	GObject *object;
+	GDBusConnection *connection;
+	const gchar *path;
+	GVariant *params;
+	GVariant *item;
+	GVariantBuilder *builder;
+
+	if (n_param_values < 1 || !G_VALUE_HOLDS (&param_values[0], G_TYPE_OBJECT))
+		return FALSE;
+
+	object = g_value_get_object (&param_values[0]);
+	path = g_object_get_data (object, "gdbus-codegen-path");
+	connection = g_object_get_data (object, "gdbus-codegen-connection");
+	if (connection == NULL || path == NULL)
+		return FALSE;
+
+	builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
+	g_assert_cmpint (n_param_values - 1, ==, 1);
+	param_values++;
+	item = g_variant_new_string (g_value_get_string (param_values));
+	g_variant_builder_add_value (builder, item);
+	param_values++;
+	params = g_variant_builder_end (builder);
+	g_variant_builder_unref (builder);
+
+	g_dbus_connection_emit_signal (connection, NULL, path, iface_name, signal_name, params, NULL);
+
+	return TRUE;
+}
+
+gboolean
+e_gdbus_signal_emission_hook_strv (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, const gchar *signal_name, const gchar *iface_name)
+{
+	GObject *object;
+	GDBusConnection *connection;
+	const gchar *path;
+	GVariant *params;
+	GVariant *item;
+	GVariantBuilder *builder;
+	const gchar * const *arg_strv;
+
+	if (n_param_values < 1 || !G_VALUE_HOLDS (&param_values[0], G_TYPE_OBJECT))
+		return FALSE;
+
+	object = g_value_get_object (&param_values[0]);
+	path = g_object_get_data (object, "gdbus-codegen-path");
+	connection = g_object_get_data (object, "gdbus-codegen-connection");
+	if (connection == NULL || path == NULL)
+		return FALSE;
+
+	builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
+	g_assert_cmpint (n_param_values - 1, ==, 1);
+	param_values++;
+	arg_strv = g_value_get_boxed (param_values);
+	item = g_variant_new_strv (arg_strv, -1);
+	g_variant_builder_add_value (builder, item);
+	param_values++;
+	params = g_variant_builder_end (builder);
+	g_variant_builder_unref (builder);
+
+	g_dbus_connection_emit_signal (connection, NULL, path, iface_name, signal_name, params, NULL);
+
+	return TRUE;
+}
+
+gboolean
+e_gdbus_signal_emission_hook_uint (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, const gchar *signal_name, const gchar *iface_name)
+{
+	GObject *object;
+	GDBusConnection *connection;
+	const gchar *path;
+	GVariant *params;
+	GVariant *item;
+	GVariantBuilder *builder;
+
+	if (n_param_values < 1 || !G_VALUE_HOLDS (&param_values[0], G_TYPE_OBJECT))
+		return FALSE;
+
+	object = g_value_get_object (&param_values[0]);
+	path = g_object_get_data (object, "gdbus-codegen-path");
+	connection = g_object_get_data (object, "gdbus-codegen-connection");
+	if (connection == NULL || path == NULL)
+		return FALSE;
+
+	builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
+	g_assert_cmpint (n_param_values - 1, ==, 1);
+	param_values++;
+	item = g_variant_new_uint32 (g_value_get_uint (param_values));
+	g_variant_builder_add_value (builder, item);
+	param_values++;
+	params = g_variant_builder_end (builder);
+	g_variant_builder_unref (builder);
+
+	g_dbus_connection_emit_signal (connection, NULL, path, iface_name, signal_name, params, NULL);
+
+	return TRUE;
+}
+
+gboolean
+e_gdbus_signal_emission_hook_uint_string (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, const gchar *signal_name, const gchar *iface_name)
+{
+	GObject *object;
+	GDBusConnection *connection;
+	const gchar *path;
+	GVariant *params;
+	GVariant *item;
+	GVariantBuilder *builder;
+
+	if (n_param_values < 1 || !G_VALUE_HOLDS (&param_values[0], G_TYPE_OBJECT))
+		return FALSE;
+
+	object = g_value_get_object (&param_values[0]);
+	path = g_object_get_data (object, "gdbus-codegen-path");
+	connection = g_object_get_data (object, "gdbus-codegen-connection");
+	if (connection == NULL || path == NULL)
+		return FALSE;
+
+	builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
+	g_assert_cmpint (n_param_values - 1, ==, 2);
+	param_values++;
+	item = g_variant_new_uint32 (g_value_get_uint (param_values));
+	g_variant_builder_add_value (builder, item);
+	param_values++;
+	item = g_variant_new_string (g_value_get_string (param_values));
+	g_variant_builder_add_value (builder, item);
+	param_values++;
+	params = g_variant_builder_end (builder);
+	g_variant_builder_unref (builder);
+
+	g_dbus_connection_emit_signal (connection, NULL, path, iface_name, signal_name, params, NULL);
+
+	return TRUE;
+}
+
+gboolean
+e_gdbus_signal_emission_hook_async_void (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, const gchar *signal_name, const gchar *iface_name)
+{
+	GObject *object;
+	GDBusConnection *connection;
+	const gchar *path;
+	GVariant *params;
+	GVariant *item;
+	GVariantBuilder *builder;
+	GError *arg_error;
+
+	if (n_param_values < 1 || !G_VALUE_HOLDS (&param_values[0], G_TYPE_OBJECT))
+		return FALSE;
+
+	object = g_value_get_object (&param_values[0]);
+	path = g_object_get_data (object, "gdbus-codegen-path");
+	connection = g_object_get_data (object, "gdbus-codegen-connection");
+	if (connection == NULL || path == NULL)
+		return FALSE;
+
+	builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
+	g_assert_cmpint (n_param_values - 1, ==, 2);
+	param_values++;
+	item = g_variant_new_uint32 (g_value_get_uint (param_values));
+	g_variant_builder_add_value (builder, item);
+	param_values++;
+	arg_error = g_value_get_boxed (param_values);
+	if (arg_error) {
+		gchar *dbus_error_name = g_dbus_error_encode_gerror (arg_error);
+		item = g_variant_new_string (dbus_error_name ? dbus_error_name : "");
+		g_variant_builder_add_value (builder, item);
+		item = g_variant_new_string (arg_error->message);
+		g_variant_builder_add_value (builder, item);
+		g_free (dbus_error_name);
+	} else {
+		item = g_variant_new_string ("");
+		g_variant_builder_add_value (builder, item);
+		item = g_variant_new_string ("");
+		g_variant_builder_add_value (builder, item);
+	}
+	param_values++;
+	params = g_variant_builder_end (builder);
+	g_variant_builder_unref (builder);
+
+	g_dbus_connection_emit_signal (connection, NULL, path, iface_name, signal_name, params, NULL);
+
+	return TRUE;
+}
+
+gboolean
+e_gdbus_signal_emission_hook_async_boolean (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, const gchar *signal_name, const gchar *iface_name)
+{
+	GObject *object;
+	GDBusConnection *connection;
+	const gchar *path;
+	GVariant *params;
+	GVariant *item;
+	GVariantBuilder *builder;
+	GError *arg_error;
+
+	if (n_param_values < 1 || !G_VALUE_HOLDS (&param_values[0], G_TYPE_OBJECT))
+		return FALSE;
+
+	object = g_value_get_object (&param_values[0]);
+	path = g_object_get_data (object, "gdbus-codegen-path");
+	connection = g_object_get_data (object, "gdbus-codegen-connection");
+	if (connection == NULL || path == NULL)
+		return FALSE;
+
+	builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
+	g_assert_cmpint (n_param_values - 1, ==, 3);
+	param_values++;
+	item = g_variant_new_uint32 (g_value_get_uint (param_values));
+	g_variant_builder_add_value (builder, item);
+	param_values++;
+	arg_error = g_value_get_boxed (param_values);
+	if (arg_error) {
+		gchar *dbus_error_name = g_dbus_error_encode_gerror (arg_error);
+		item = g_variant_new_string (dbus_error_name ? dbus_error_name : "");
+		g_variant_builder_add_value (builder, item);
+		item = g_variant_new_string (arg_error->message);
+		g_variant_builder_add_value (builder, item);
+		g_free (dbus_error_name);
+	} else {
+		item = g_variant_new_string ("");
+		g_variant_builder_add_value (builder, item);
+		item = g_variant_new_string ("");
+		g_variant_builder_add_value (builder, item);
+	}
+	param_values++;
+	item = g_variant_new_boolean (g_value_get_boolean (param_values));
+	g_variant_builder_add_value (builder, item);
+	param_values++;
+	params = g_variant_builder_end (builder);
+	g_variant_builder_unref (builder);
+
+	g_dbus_connection_emit_signal (connection, NULL, path, iface_name, signal_name, params, NULL);
+
+	return TRUE;
+}
+
+gboolean
+e_gdbus_signal_emission_hook_async_string (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, const gchar *signal_name, const gchar *iface_name)
+{
+	GObject *object;
+	GDBusConnection *connection;
+	const gchar *path;
+	GVariant *params;
+	GVariant *item;
+	GVariantBuilder *builder;
+	GError *arg_error;
+
+	if (n_param_values < 1 || !G_VALUE_HOLDS (&param_values[0], G_TYPE_OBJECT))
+		return FALSE;
+
+	object = g_value_get_object (&param_values[0]);
+	path = g_object_get_data (object, "gdbus-codegen-path");
+	connection = g_object_get_data (object, "gdbus-codegen-connection");
+	if (connection == NULL || path == NULL)
+		return FALSE;
+
+	builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
+	g_assert_cmpint (n_param_values - 1, ==, 3);
+	param_values++;
+	item = g_variant_new_uint32 (g_value_get_uint (param_values));
+	g_variant_builder_add_value (builder, item);
+	param_values++;
+	arg_error = g_value_get_boxed (param_values);
+	if (arg_error) {
+		gchar *dbus_error_name = g_dbus_error_encode_gerror (arg_error);
+		item = g_variant_new_string (dbus_error_name ? dbus_error_name : "");
+		g_variant_builder_add_value (builder, item);
+		item = g_variant_new_string (arg_error->message);
+		g_variant_builder_add_value (builder, item);
+		g_free (dbus_error_name);
+	} else {
+		item = g_variant_new_string ("");
+		g_variant_builder_add_value (builder, item);
+		item = g_variant_new_string ("");
+		g_variant_builder_add_value (builder, item);
+	}
+	param_values++;
+	item = g_variant_new_string (g_value_get_string (param_values));
+	g_variant_builder_add_value (builder, item);
+	param_values++;
+	params = g_variant_builder_end (builder);
+	g_variant_builder_unref (builder);
+
+	g_dbus_connection_emit_signal (connection, NULL, path, iface_name, signal_name, params, NULL);
+
+	return TRUE;
+}
+
+gboolean
+e_gdbus_signal_emission_hook_async_strv (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, const gchar *signal_name, const gchar *iface_name)
+{
+	GObject *object;
+	GDBusConnection *connection;
+	const gchar *path;
+	GVariant *params;
+	GVariant *item;
+	GVariantBuilder *builder;
+	const GError *arg_error;
+	const gchar * const *arg_strv;
+
+	if (n_param_values < 1 || !G_VALUE_HOLDS (&param_values[0], G_TYPE_OBJECT))
+		return FALSE;
+
+	object = g_value_get_object (&param_values[0]);
+	path = g_object_get_data (object, "gdbus-codegen-path");
+	connection = g_object_get_data (object, "gdbus-codegen-connection");
+	if (connection == NULL || path == NULL)
+		return FALSE;
+
+	builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
+	g_assert_cmpint (n_param_values - 1, ==, 3);
+	param_values++;
+	item = g_variant_new_uint32 (g_value_get_uint (param_values));
+	g_variant_builder_add_value (builder, item);
+	param_values++;
+	arg_error = g_value_get_boxed (param_values);
+	if (arg_error) {
+		gchar *dbus_error_name = g_dbus_error_encode_gerror (arg_error);
+		item = g_variant_new_string (dbus_error_name ? dbus_error_name : "");
+		g_variant_builder_add_value (builder, item);
+		item = g_variant_new_string (arg_error->message);
+		g_variant_builder_add_value (builder, item);
+		g_free (dbus_error_name);
+	} else {
+		item = g_variant_new_string ("");
+		g_variant_builder_add_value (builder, item);
+		item = g_variant_new_string ("");
+		g_variant_builder_add_value (builder, item);
+	}
+	param_values++;
+	arg_strv = g_value_get_boxed (param_values);
+	item = g_variant_new_strv (arg_strv, -1);
+	g_variant_builder_add_value (builder, item);
+	param_values++;
+	params = g_variant_builder_end (builder);
+	g_variant_builder_unref (builder);
+
+	g_dbus_connection_emit_signal (connection, NULL, path, iface_name, signal_name, params, NULL);
+
+	return TRUE;
+}
+
+gboolean
+e_gdbus_signal_emission_hook_async_uint (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, const gchar *signal_name, const gchar *iface_name)
+{
+	GObject *object;
+	GDBusConnection *connection;
+	const gchar *path;
+	GVariant *params;
+	GVariant *item;
+	GVariantBuilder *builder;
+	GError *arg_error;
+
+	if (n_param_values < 1 || !G_VALUE_HOLDS (&param_values[0], G_TYPE_OBJECT))
+		return FALSE;
+
+	object = g_value_get_object (&param_values[0]);
+	path = g_object_get_data (object, "gdbus-codegen-path");
+	connection = g_object_get_data (object, "gdbus-codegen-connection");
+	if (connection == NULL || path == NULL)
+		return FALSE;
+
+	builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
+	g_assert_cmpint (n_param_values - 1, ==, 3);
+	param_values++;
+	item = g_variant_new_uint32 (g_value_get_uint (param_values));
+	g_variant_builder_add_value (builder, item);
+	param_values++;
+	arg_error = g_value_get_boxed (param_values);
+	if (arg_error) {
+		gchar *dbus_error_name = g_dbus_error_encode_gerror (arg_error);
+		item = g_variant_new_string (dbus_error_name ? dbus_error_name : "");
+		g_variant_builder_add_value (builder, item);
+		item = g_variant_new_string (arg_error->message);
+		g_variant_builder_add_value (builder, item);
+		g_free (dbus_error_name);
+	} else {
+		item = g_variant_new_string ("");
+		g_variant_builder_add_value (builder, item);
+		item = g_variant_new_string ("");
+		g_variant_builder_add_value (builder, item);
+	}
+	param_values++;
+	item = g_variant_new_uint32 (g_value_get_uint (param_values));
+	g_variant_builder_add_value (builder, item);
+	param_values++;
+	params = g_variant_builder_end (builder);
+	g_variant_builder_unref (builder);
+
+	g_dbus_connection_emit_signal (connection, NULL, path, iface_name, signal_name, params, NULL);
+
+	return TRUE;
+}
+
+void
+e_gdbus_proxy_emit_signal (GDBusProxy *proxy, GVariant *parameters, guint signal_id, guint signal_type)
+{
+	gboolean arg_boolean = FALSE;
+	const gchar *arg_const_string = NULL;
+	const gchar **arg_const_strv = NULL;
+	guint arg_uint = 0;
+
+	g_return_if_fail (proxy != NULL);
+
+	if ((signal_type & E_GDBUS_TYPE_IS_ASYNC) != 0) {
+		/* the signal is a done signal, thus opid and error name with error message are first two parameters */
+		guint arg_opid = 0;
+		const gchar *dbus_error_name = NULL, *dbus_error_message = NULL;
+		GError *arg_error = NULL;
+
+		signal_type = signal_type & (~E_GDBUS_TYPE_IS_ASYNC);
+		switch (signal_type) {
+		case E_GDBUS_TYPE_VOID:
+			g_variant_get (parameters, "(u&s&s)", &arg_opid, &dbus_error_name, &dbus_error_message);
+			break;
+		case E_GDBUS_TYPE_BOOLEAN:
+			g_variant_get (parameters, "(u&s&sb)", &arg_opid, &dbus_error_name, &dbus_error_message, &arg_boolean);
+			break;
+		case E_GDBUS_TYPE_STRING:
+			g_variant_get (parameters, "(u&s&s&s)", &arg_opid, &dbus_error_name, &dbus_error_message, &arg_const_string);
+			break;
+		case E_GDBUS_TYPE_STRV:
+			/* array is newly allocated, but items are gvariant's */
+			g_variant_get (parameters, "(u&s&s^a&s)", &arg_opid, &dbus_error_name, &dbus_error_message, &arg_const_strv);
+			break;
+		case E_GDBUS_TYPE_UINT:
+			g_variant_get (parameters, "(u&s&su)", &arg_opid, &dbus_error_name, &dbus_error_message, &arg_uint);
+			break;
+		default:
+			g_warning ("%s: Unknown E_GDBUS_TYPE %x", G_STRFUNC, signal_type);
+			return;
+		}
+
+		if (dbus_error_name && *dbus_error_name && dbus_error_message)
+			arg_error = g_dbus_error_new_for_dbus_error (dbus_error_name, dbus_error_message);
+
+		switch (signal_type) {
+		case E_GDBUS_TYPE_VOID:
+			g_signal_emit (proxy, signal_id, 0, arg_opid, arg_error);
+			break;
+		case E_GDBUS_TYPE_BOOLEAN:
+			g_signal_emit (proxy, signal_id, 0, arg_opid, arg_error, arg_boolean);
+			break;
+		case E_GDBUS_TYPE_STRING:
+			g_signal_emit (proxy, signal_id, 0, arg_opid, arg_error, arg_const_string);
+			break;
+		case E_GDBUS_TYPE_STRV:
+			g_signal_emit (proxy, signal_id, 0, arg_opid, arg_error, arg_const_strv);
+			g_free (arg_const_strv);
+			break;
+		case E_GDBUS_TYPE_UINT:
+			g_signal_emit (proxy, signal_id, 0, arg_opid, arg_error, arg_uint);
+			break;
+		default:
+			g_warning ("%s: Unknown E_GDBUS_TYPE %x", G_STRFUNC, signal_type);
+			break;
+		}
+
+		if (arg_error)
+			g_error_free (arg_error);
+	} else {
+		switch (signal_type) {
+		case E_GDBUS_TYPE_VOID:
+			g_signal_emit (proxy, signal_id, 0);
+			break;
+		case E_GDBUS_TYPE_BOOLEAN:
+			g_variant_get (parameters, "(b)", &arg_boolean);
+			g_signal_emit (proxy, signal_id, 0, arg_boolean);
+			break;
+		case E_GDBUS_TYPE_STRING:
+			g_variant_get (parameters, "(&s)", &arg_const_string);
+			g_signal_emit (proxy, signal_id, 0, arg_const_string);
+			break;
+		case E_GDBUS_TYPE_STRV:
+			/* array is newly allocated, but items are gvariant's */
+			g_variant_get (parameters, "(^a&s)", &arg_const_strv);
+			g_signal_emit (proxy, signal_id, 0, arg_const_strv);
+			g_free (arg_const_strv);
+			break;
+		case E_GDBUS_TYPE_UINT:
+			g_variant_get (parameters, "(u)", &arg_uint);
+			g_signal_emit (proxy, signal_id, 0, arg_uint);
+			break;
+		case E_GDBUS_TYPE_UINT | E_GDBUS_TYPE_STRING:
+			g_variant_get (parameters, "(u&s)", &arg_uint, &arg_const_string);
+			g_signal_emit (proxy, signal_id, 0, arg_uint, arg_const_string);
+			break;
+		default:
+			g_warning ("%s: Unknown E_GDBUS_TYPE %x", G_STRFUNC, signal_type);
+			break;
+		}
+	}
+}
+
+void
+e_gdbus_stub_handle_method_call (GObject *stub_object, GDBusMethodInvocation *invocation, GVariant *parameters, const gchar *method_name, guint method_id, guint method_type)
+{
+	gboolean handled = FALSE;
+	gboolean arg_boolean = FALSE;
+	const gchar *arg_const_string = NULL;
+	const gchar ** arg_const_strv = NULL;
+	guint arg_uint = 0;
+
+	g_return_if_fail (stub_object != NULL);
+	g_return_if_fail (method_name != NULL);
+
+	switch (method_type & (~E_GDBUS_TYPE_IS_ASYNC)) {
+	case E_GDBUS_TYPE_VOID:
+		g_signal_emit (stub_object, method_id, 0, invocation, &handled);
+		break;
+	case E_GDBUS_TYPE_BOOLEAN:
+		g_variant_get (parameters, "(b)", &arg_boolean);
+		g_signal_emit (stub_object, method_id, 0, invocation, arg_boolean, &handled);
+		break;
+	case E_GDBUS_TYPE_STRING:
+		g_variant_get (parameters, "(&s)", &arg_const_string);
+		g_signal_emit (stub_object, method_id, 0, invocation, arg_const_string, &handled);
+		break;
+	case E_GDBUS_TYPE_STRV:
+		/* array is newly allocated, but items are gvariant's */
+		g_variant_get (parameters, "(^a&s)", &arg_const_strv);
+		g_signal_emit (stub_object, method_id, 0, invocation, arg_const_strv, &handled);
+		g_free (arg_const_strv);
+		break;
+	case E_GDBUS_TYPE_UINT:
+		g_variant_get (parameters, "(u)", &arg_uint);
+		g_signal_emit (stub_object, method_id, 0, invocation, arg_uint, &handled);
+		break;
+	default:
+		g_warning ("%s: Unknown E_GDBUS_TYPE %x", G_STRFUNC, method_type);
+		break;
+	}
+
+	if (!handled)
+	      g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "Method `%s' is not implemented", method_name);
+}
+
+G_DEFINE_INTERFACE (EGdbusAsyncOpKeeper, e_gdbus_async_op_keeper, G_TYPE_OBJECT)
+
+static void
+e_gdbus_async_op_keeper_default_init (EGdbusAsyncOpKeeperInterface *iface)
+{
+}
+
+/* Created hash table of pending async operations. This can be freed
+   with g_hash_table_destroy() in dispose. Interface asks for this
+   ponter by call of e_gdbus_async_op_keeper_create_pending_ops().
+*/
+GHashTable *
+e_gdbus_async_op_keeper_create_pending_ops (EGdbusAsyncOpKeeper *object)
+{
+	g_return_val_if_fail (object != NULL, NULL);
+	g_return_val_if_fail (E_IS_GDBUS_ASYNC_OP_KEEPER (object), NULL);
+
+	return g_hash_table_new (g_direct_hash, g_direct_equal);
+}
+
+/* Returns hash table of pending async operations previously created
+   by e_gdbus_async_op_keeper_create_pending_ops().
+*/
+GHashTable *
+e_gdbus_async_op_keeper_get_pending_ops (EGdbusAsyncOpKeeper *object)
+{
+	EGdbusAsyncOpKeeperInterface *iface;
+
+	g_return_val_if_fail (E_IS_GDBUS_ASYNC_OP_KEEPER (object), 0);
+
+	iface = E_GDBUS_ASYNC_OP_KEEPER_GET_IFACE (object);
+	g_return_val_if_fail (iface->get_pending_ops != NULL, 0);
+
+	return iface->get_pending_ops (object);
+}
+
+/* synchronously cancels one operation - sends a request from client to the server */
+gboolean
+e_gdbus_async_op_keeper_cancel_op_sync (EGdbusAsyncOpKeeper *object, guint in_opid, GCancellable *cancellable, GError **error)
+{
+	EGdbusAsyncOpKeeperInterface *iface;
+
+	g_return_val_if_fail (E_IS_GDBUS_ASYNC_OP_KEEPER (object), FALSE);
+
+	iface = E_GDBUS_ASYNC_OP_KEEPER_GET_IFACE (object);
+	g_return_val_if_fail (iface->cancel_op_sync != NULL, FALSE);
+
+	return iface->cancel_op_sync (object, in_opid, cancellable, error);
+}
+
+/* Used to finish asynchronous GDBus call - this might be done in the callback
+   as soon as possible; method returns to a caller operation ID which was started */
+void
+e_gdbus_complete_async_method (gpointer object, GDBusMethodInvocation *invocation, guint opid)
+{
+	g_dbus_method_invocation_return_value (invocation, g_variant_new ("(u)", opid));
+}
+
+/* Used to finish synchronous GDBus call - this might be done in the callback
+   as soon as possible */
+void
+e_gdbus_complete_sync_method_void (gpointer object, GDBusMethodInvocation *invocation, const GError *error)
+{
+	if (error)
+		g_dbus_method_invocation_return_gerror (invocation, error);
+	else
+		g_dbus_method_invocation_return_value (invocation, NULL);
+}
+
+void
+e_gdbus_complete_sync_method_boolean (gpointer object, GDBusMethodInvocation *invocation, gboolean out_boolean, const GError *error)
+{
+	if (error)
+		g_dbus_method_invocation_return_gerror (invocation, error);
+	else
+		g_dbus_method_invocation_return_value (invocation, g_variant_new ("(b)", out_boolean));
+}
+
+void
+e_gdbus_complete_sync_method_string (gpointer object, GDBusMethodInvocation *invocation, const gchar *out_string, const GError *error)
+{
+	if (error)
+		g_dbus_method_invocation_return_gerror (invocation, error);
+	else
+		g_dbus_method_invocation_return_value (invocation, g_variant_new ("(s)", out_string));
+}
+
+void
+e_gdbus_complete_sync_method_strv (gpointer object, GDBusMethodInvocation *invocation, const gchar * const *out_strv, const GError *error)
+{
+	if (error)
+		g_dbus_method_invocation_return_gerror (invocation, error);
+	else
+		g_dbus_method_invocation_return_value (invocation, g_variant_new ("(^as)", out_strv));
+}
+
+void
+e_gdbus_complete_sync_method_uint (gpointer object, GDBusMethodInvocation *invocation, guint out_uint, const GError *error)
+{
+	if (error)
+		g_dbus_method_invocation_return_gerror (invocation, error);
+	else
+		g_dbus_method_invocation_return_value (invocation, g_variant_new ("(u)", out_uint));
+}
+
+typedef struct _AsyncOpData
+{
+	EGdbusAsyncOpKeeper *proxy;
+	guint opid;
+
+	GCancellable *cancellable;
+	gulong cancel_id;
+
+	gpointer async_source_tag;
+	GAsyncReadyCallback async_callback;
+	gpointer async_user_data;
+
+	guint result_type; /* any of E_GDBUS_TYPE_... except of E_GDBUS_TYPE_IS_ASYNC */
+	union {
+		gboolean out_boolean;
+		gchar *out_string;
+		gchar ** out_strv;
+		guint out_uint;
+	} result;
+} AsyncOpData;
+
+
+static void
+async_op_data_free (AsyncOpData *op_data)
+{
+	GHashTable *pending_ops;
+
+	g_return_if_fail (op_data != NULL);
+
+	if (op_data->cancellable) {
+		if (op_data->cancel_id)
+			g_cancellable_disconnect (op_data->cancellable, op_data->cancel_id);
+		g_object_unref (op_data->cancellable);
+	}
+
+	pending_ops = e_gdbus_async_op_keeper_get_pending_ops (E_GDBUS_ASYNC_OP_KEEPER (op_data->proxy));
+	if (pending_ops)
+		g_hash_table_remove (pending_ops, GUINT_TO_POINTER (op_data->opid));
+	g_object_unref (op_data->proxy);
+
+	switch (op_data->result_type) {
+	case E_GDBUS_TYPE_STRING:
+		if (op_data->result.out_string)
+			g_free (op_data->result.out_string);
+		break;
+	case E_GDBUS_TYPE_STRV:
+		if (op_data->result.out_strv)
+			g_strfreev (op_data->result.out_strv);
+		break;
+	}
+
+	g_free (op_data);
+
+	g_return_if_fail (pending_ops != NULL);
+}
+
+static void
+async_op_complete (AsyncOpData *op_data, const GError *error, gboolean in_idle)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_if_fail (op_data != NULL);
+
+	simple = g_simple_async_result_new (G_OBJECT (op_data->proxy), op_data->async_callback, op_data->async_user_data, op_data->async_source_tag);
+	g_simple_async_result_set_op_res_gpointer (simple, op_data, (GDestroyNotify) async_op_data_free);
+	if (error)
+		g_simple_async_result_set_from_error (simple, error);
+
+	if (in_idle)
+		g_simple_async_result_complete_in_idle (simple);
+	else
+		g_simple_async_result_complete (simple);
+
+	g_object_unref (simple);
+}
+
+static void
+gdbus_op_cancelled_cb (GCancellable *cancellable, AsyncOpData *op_data)
+{
+	GError *call_error = NULL;
+
+	g_return_if_fail (op_data != NULL);
+
+	if (!e_gdbus_async_op_keeper_cancel_op_sync (op_data->proxy, op_data->opid, NULL, &call_error)) {
+		/* only if failed, because otherwise will receive cancelled signal from the server */
+		GError *error = NULL;
+
+		g_return_if_fail (g_cancellable_set_error_if_cancelled (cancellable, &error));
+
+		async_op_complete (op_data, error, TRUE);
+		g_error_free (error);
+	}
+
+	if (call_error) {
+		g_debug ("%s: Failed to cancel operation: %s\n", G_STRFUNC, call_error->message);
+		g_error_free (call_error);
+	}
+}
+
+static void
+gdbus_async_call_opid_ready_cb (GObject *source_proxy, GAsyncResult *result, gpointer user_data)
+{
+	GVariant *_result;
+	GError *error = NULL;
+	AsyncOpData *op_data = user_data;
+
+	_result = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_proxy), result, &error);
+
+	if (_result != NULL && !error) {
+		EGdbusAsyncOpKeeper *op_keeper = E_GDBUS_ASYNC_OP_KEEPER (source_proxy);
+		GHashTable *pending_ops;
+		gboolean add_pending = TRUE;
+
+		g_return_if_fail (op_keeper != NULL);
+
+		pending_ops = e_gdbus_async_op_keeper_get_pending_ops (op_keeper);
+		g_return_if_fail (pending_ops != NULL);
+
+		g_variant_get (_result, "(u)", &op_data->opid);
+		g_variant_unref (_result);
+
+		if (op_data->cancellable && !g_cancellable_set_error_if_cancelled (op_data->cancellable, &error))
+			op_data->cancel_id = g_cancellable_connect (op_data->cancellable, G_CALLBACK (gdbus_op_cancelled_cb), op_data, NULL);
+		else
+			add_pending = op_data->cancellable == NULL;
+
+		/* add to pending ops, waiting for associated 'done' signal */
+		if (add_pending)
+			g_hash_table_insert (pending_ops, GUINT_TO_POINTER (op_data->opid), op_data);
+	} else if (_result) {
+		g_variant_unref (_result);
+	}
+
+	if (error) {
+		async_op_complete (op_data, error, FALSE);
+		g_error_free (error);
+	}
+}
+
+static gchar **
+copy_strv (const gchar * const *strv)
+{
+	GPtrArray *array;
+	gint ii;
+
+	array = g_ptr_array_sized_new (g_strv_length ((gchar **) strv) + 1);
+
+	for (ii = 0; strv[ii]; ii++) {
+		g_ptr_array_add (array, g_strdup (strv[ii]));
+	}
+
+	/* NULL-terminated */
+	g_ptr_array_add (array, NULL);
+
+	return (gchar **) g_ptr_array_free (array, FALSE);
+}
+
+static void
+gdbus_proxy_async_method_done (guint e_gdbus_type, gconstpointer out_value, EGdbusAsyncOpKeeper *object, guint arg_opid, const GError *error)
+{
+	AsyncOpData *op_data;
+	GHashTable *pending_ops;
+
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (E_IS_GDBUS_ASYNC_OP_KEEPER (object));
+
+	pending_ops = e_gdbus_async_op_keeper_get_pending_ops (object);
+	g_return_if_fail (pending_ops != NULL);
+
+	op_data = g_hash_table_lookup (pending_ops, GUINT_TO_POINTER (arg_opid));
+	if (!op_data) {
+		g_debug ("%s: Operation %d gone before got done signal for it", G_STRFUNC, arg_opid);
+		return;
+	}
+
+	if (out_value) {
+		op_data->result_type = e_gdbus_type;
+
+		switch (e_gdbus_type) {
+		case E_GDBUS_TYPE_VOID:
+			break;
+		case E_GDBUS_TYPE_BOOLEAN:
+			op_data->result.out_boolean = * ((const gboolean *)out_value);
+			break;
+		case E_GDBUS_TYPE_STRING:
+			op_data->result.out_string = g_strdup ((const gchar *) out_value);
+			break;
+		case E_GDBUS_TYPE_STRV:
+			op_data->result.out_strv = copy_strv ((const gchar * const *) out_value);
+			break;
+		case E_GDBUS_TYPE_UINT:
+			op_data->result.out_uint = * ((const guint *) out_value);
+			break;
+		default:
+			g_warning ("%s: Unknown E_GDBUS_TYPE %x", G_STRFUNC, e_gdbus_type);
+			break;
+		}
+	}
+
+	async_op_complete (op_data, error, TRUE);
+}
+
+void
+e_gdbus_proxy_async_method_done_void (EGdbusAsyncOpKeeper *proxy, guint arg_opid, const GError *error)
+{
+	gdbus_proxy_async_method_done (E_GDBUS_TYPE_VOID, NULL, proxy, arg_opid, error);
+}
+
+void
+e_gdbus_proxy_async_method_done_boolean (EGdbusAsyncOpKeeper *proxy, guint arg_opid, const GError *error, gboolean out_boolean)
+{
+	gdbus_proxy_async_method_done (E_GDBUS_TYPE_BOOLEAN, &out_boolean, proxy, arg_opid, error);
+}
+
+/* takes ownership of the out parameter */
+void
+e_gdbus_proxy_async_method_done_string (EGdbusAsyncOpKeeper *proxy, guint arg_opid, const GError *error, const gchar *out_string)
+{
+	gdbus_proxy_async_method_done (E_GDBUS_TYPE_STRING, out_string, proxy, arg_opid, error);
+}
+
+/* takes ownership of the out parameter */
+void
+e_gdbus_proxy_async_method_done_strv (EGdbusAsyncOpKeeper *proxy, guint arg_opid, const GError *error, const gchar * const *out_strv)
+{
+	gdbus_proxy_async_method_done (E_GDBUS_TYPE_STRV, out_strv, proxy, arg_opid, error);
+}
+
+void
+e_gdbus_proxy_async_method_done_uint (EGdbusAsyncOpKeeper *proxy, guint arg_opid, const GError *error, guint out_uint)
+{
+	gdbus_proxy_async_method_done (E_GDBUS_TYPE_UINT, &out_uint, proxy, arg_opid, error);
+}
+
+/* takes ownership of _params */
+static void
+gdbus_proxy_call_with_params (GVariant *_params, const gchar *method_name, gpointer source_tag, EGdbusAsyncOpKeeper *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	AsyncOpData *op_data;
+
+	op_data = g_new0 (AsyncOpData, 1);
+	op_data->proxy = g_object_ref (proxy);
+	op_data->opid = 0;
+	op_data->async_source_tag = source_tag;
+	op_data->async_callback = callback;
+	op_data->async_user_data = user_data;
+	op_data->cancellable = cancellable;
+	if (op_data->cancellable)
+		g_object_ref (op_data->cancellable);
+
+	g_dbus_proxy_call (G_DBUS_PROXY (proxy), method_name, _params, G_DBUS_CALL_FLAGS_NONE, e_data_server_util_get_dbus_call_timeout (), cancellable, gdbus_async_call_opid_ready_cb, op_data);
+}
+
+void
+e_gdbus_proxy_call_void (const gchar *method_name, gpointer source_tag, EGdbusAsyncOpKeeper *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	gdbus_proxy_call_with_params (NULL, method_name, source_tag, proxy, cancellable, callback, user_data);
+}
+
+void
+e_gdbus_proxy_call_boolean (const gchar *method_name, gpointer source_tag, EGdbusAsyncOpKeeper *proxy, gboolean in_boolean, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	GVariant *_params;
+
+	_params = g_variant_new ("(b)", in_boolean);
+
+	gdbus_proxy_call_with_params (_params, method_name, source_tag, proxy, cancellable, callback, user_data);
+}
+
+void
+e_gdbus_proxy_call_string (const gchar *method_name, gpointer source_tag, EGdbusAsyncOpKeeper *proxy, const gchar *in_string, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	GVariant *_params;
+
+	_params = g_variant_new ("(s)", in_string);
+
+	gdbus_proxy_call_with_params (_params, method_name, source_tag, proxy, cancellable, callback, user_data);
+}
+
+void
+e_gdbus_proxy_call_strv (const gchar *method_name, gpointer source_tag, EGdbusAsyncOpKeeper *proxy, const gchar * const *in_strv, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	GVariant *_params;
+
+	_params = g_variant_new ("(^as)", in_strv);
+
+	gdbus_proxy_call_with_params (_params, method_name, source_tag, proxy, cancellable, callback, user_data);
+}
+
+void
+e_gdbus_proxy_call_uint (const gchar *method_name, gpointer source_tag, EGdbusAsyncOpKeeper *proxy, guint in_uint, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	GVariant *_params;
+
+	_params = g_variant_new ("(u)", in_uint);
+
+	gdbus_proxy_call_with_params (_params, method_name, source_tag, proxy, cancellable, callback, user_data);
+}
+
+gboolean
+e_gdbus_proxy_finish_call_void (EGdbusAsyncOpKeeper *proxy, GAsyncResult *result, GError **error, gpointer source_tag)
+{
+	g_return_val_if_fail (proxy != NULL, FALSE);
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (proxy), source_tag), FALSE);
+
+	return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error);
+}
+
+gboolean
+e_gdbus_proxy_finish_call_boolean (EGdbusAsyncOpKeeper *proxy, GAsyncResult *result, gboolean *out_boolean, GError **error, gpointer source_tag)
+{
+	AsyncOpData *op_data;
+
+	g_return_val_if_fail (proxy != NULL, FALSE);
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (proxy), source_tag), FALSE);
+	g_return_val_if_fail (out_boolean != NULL, FALSE);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return FALSE;
+
+	op_data = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+	g_return_val_if_fail (op_data != NULL, FALSE);
+	g_return_val_if_fail (op_data->result_type == E_GDBUS_TYPE_BOOLEAN, FALSE);
+
+	*out_boolean = op_data->result.out_boolean;
+
+	return TRUE;
+}
+
+/* caller takes ownership and responsibility for freeing the out parameter */
+gboolean
+e_gdbus_proxy_finish_call_string (EGdbusAsyncOpKeeper *proxy, GAsyncResult *result, gchar **out_string, GError **error, gpointer source_tag)
+{
+	AsyncOpData *op_data;
+
+	g_return_val_if_fail (proxy != NULL, FALSE);
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (proxy), source_tag), FALSE);
+	g_return_val_if_fail (out_string != NULL, FALSE);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return FALSE;
+
+	op_data = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+	g_return_val_if_fail (op_data != NULL, FALSE);
+	g_return_val_if_fail (op_data->result_type == E_GDBUS_TYPE_STRING, FALSE);
+
+	*out_string = op_data->result.out_string;
+	op_data->result.out_string = NULL;
+
+	return TRUE;
+}
+
+/* caller takes ownership and responsibility for freeing the out parameter */
+gboolean
+e_gdbus_proxy_finish_call_strv (EGdbusAsyncOpKeeper *proxy, GAsyncResult *result, gchar ***out_strv, GError **error, gpointer source_tag)
+{
+	AsyncOpData *op_data;
+
+	g_return_val_if_fail (proxy != NULL, FALSE);
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (proxy), source_tag), FALSE);
+	g_return_val_if_fail (out_strv != NULL, FALSE);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return FALSE;
+
+	op_data = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+	g_return_val_if_fail (op_data != NULL, FALSE);
+	g_return_val_if_fail (op_data->result_type == E_GDBUS_TYPE_STRV, FALSE);
+
+	*out_strv = op_data->result.out_strv;
+	op_data->result.out_strv = NULL;
+
+	return TRUE;
+}
+
+gboolean
+e_gdbus_proxy_finish_call_uint (EGdbusAsyncOpKeeper *proxy, GAsyncResult *result, guint *out_uint, GError **error, gpointer source_tag)
+{
+	AsyncOpData *op_data;
+
+	g_return_val_if_fail (proxy != NULL, FALSE);
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (proxy), source_tag), FALSE);
+	g_return_val_if_fail (out_uint != NULL, FALSE);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return FALSE;
+
+	op_data = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+	g_return_val_if_fail (op_data != NULL, FALSE);
+	g_return_val_if_fail (op_data->result_type == E_GDBUS_TYPE_STRING, FALSE);
+
+	*out_uint = op_data->result.out_uint;
+
+	return TRUE;
+}
+
+typedef struct _SyncOpData
+{
+	EFlag *flag;
+	GError **error;
+
+	guint out_type; /* one of E_GDBUS_TYPE_... except of E_GDBUS_TYPE_IS_ASYNC */
+	union {
+		gboolean *out_boolean;
+		gchar **out_string;
+		gchar ***out_strv;
+		guint *out_uint;
+	} out_arg;
+
+	union {
+		EGdbusCallFinishVoid finish_void;
+		EGdbusCallFinishBoolean finish_boolean;
+		EGdbusCallFinishString finish_string;
+		EGdbusCallFinishStrv finish_strv;
+		EGdbusCallFinishUint finish_uint;
+	} finish_func;
+
+	gboolean finish_result;
+} SyncOpData;
+
+static void
+gdbus_proxy_sync_ready_cb (GObject *proxy, GAsyncResult *result, gpointer user_data)
+{
+	SyncOpData *sync_data = user_data;
+
+	g_return_if_fail (sync_data != NULL);
+	g_return_if_fail (sync_data->flag != NULL);
+
+	switch (sync_data->out_type) {
+	case E_GDBUS_TYPE_VOID:
+		g_return_if_fail (sync_data->finish_func.finish_void != NULL);
+		sync_data->finish_result = sync_data->finish_func.finish_void (G_DBUS_PROXY (proxy), result, sync_data->error);
+		break;
+	case E_GDBUS_TYPE_BOOLEAN:
+		g_return_if_fail (sync_data->finish_func.finish_boolean != NULL);
+		sync_data->finish_result = sync_data->finish_func.finish_boolean (G_DBUS_PROXY (proxy), result, sync_data->out_arg.out_boolean, sync_data->error);
+		break;
+	case E_GDBUS_TYPE_STRING:
+		g_return_if_fail (sync_data->finish_func.finish_string != NULL);
+		sync_data->finish_result = sync_data->finish_func.finish_string (G_DBUS_PROXY (proxy), result, sync_data->out_arg.out_string, sync_data->error);
+		break;
+	case E_GDBUS_TYPE_STRV:
+		g_return_if_fail (sync_data->finish_func.finish_strv != NULL);
+		sync_data->finish_result = sync_data->finish_func.finish_strv (G_DBUS_PROXY (proxy), result, sync_data->out_arg.out_strv, sync_data->error);
+		break;
+	case E_GDBUS_TYPE_UINT:
+		g_return_if_fail (sync_data->finish_func.finish_uint != NULL);
+		sync_data->finish_result = sync_data->finish_func.finish_uint (G_DBUS_PROXY (proxy), result, sync_data->out_arg.out_uint, sync_data->error);
+		break;
+	default:
+		g_warning ("%s: Unknown 'out' E_GDBUS_TYPE %x", G_STRFUNC, sync_data->out_type);
+		sync_data->finish_result = FALSE;
+	}
+
+	e_flag_set (sync_data->flag);
+}
+
+static gboolean
+gdbus_proxy_call_sync (GDBusProxy *proxy, GCancellable *cancellable, GError **error, gpointer start_func, gpointer finish_func, guint in_type, gconstpointer in_value, guint out_type, gpointer out_value)
+{
+	SyncOpData sync_data = { 0 };
+
+	g_return_val_if_fail (proxy != NULL, FALSE);
+	g_return_val_if_fail (start_func != NULL, FALSE);
+	g_return_val_if_fail (finish_func != NULL, FALSE);
+
+	switch (out_type) {
+	case E_GDBUS_TYPE_VOID:
+		sync_data.finish_func.finish_void = finish_func;
+		break;
+	case E_GDBUS_TYPE_BOOLEAN:
+		sync_data.out_arg.out_boolean = out_value;
+		sync_data.finish_func.finish_boolean = finish_func;
+		break;
+	case E_GDBUS_TYPE_STRING:
+		sync_data.out_arg.out_string = out_value;
+		sync_data.finish_func.finish_string = finish_func;
+		break;
+	case E_GDBUS_TYPE_STRV:
+		sync_data.out_arg.out_strv = out_value;
+		sync_data.finish_func.finish_strv = finish_func;
+		break;
+	case E_GDBUS_TYPE_UINT:
+		sync_data.out_arg.out_uint = out_value;
+		sync_data.finish_func.finish_uint = finish_func;
+		break;
+	default:
+		g_warning ("%s: Unknown 'out' E_GDBUS_TYPE %x", G_STRFUNC, out_type);
+		return FALSE;
+	}
+
+	sync_data.flag = e_flag_new ();
+	sync_data.error = error;
+	sync_data.out_type = out_type;
+
+	switch (in_type) {
+	case E_GDBUS_TYPE_VOID: {
+		EGdbusCallStartVoid start = start_func;
+		start (proxy, cancellable, gdbus_proxy_sync_ready_cb, &sync_data);
+	} break;
+	case E_GDBUS_TYPE_BOOLEAN: {
+		EGdbusCallStartBoolean start = start_func;
+		start (proxy, * ((gboolean *) in_value), cancellable, gdbus_proxy_sync_ready_cb, &sync_data);
+	} break;
+	case E_GDBUS_TYPE_STRING: {
+		EGdbusCallStartString start = start_func;
+		start (proxy, (const gchar *) in_value, cancellable, gdbus_proxy_sync_ready_cb, &sync_data);
+	} break;
+	case E_GDBUS_TYPE_STRV: {
+		EGdbusCallStartStrv start = start_func;
+		start (proxy, (const gchar * const *) in_value, cancellable, gdbus_proxy_sync_ready_cb, &sync_data);
+	} break;
+	case E_GDBUS_TYPE_UINT: {
+		EGdbusCallStartUint start = start_func;
+		start (proxy, * ((guint *) in_value), cancellable, gdbus_proxy_sync_ready_cb, &sync_data);
+	} break;
+	default:
+		g_warning ("%s: Unknown 'in' E_GDBUS_TYPE %x", G_STRFUNC, in_type);
+		e_flag_free (sync_data.flag);
+		return FALSE;
+	}
+
+	/* check if called from the main thread */
+	if (g_main_context_is_owner (g_main_context_default ())
+	    || g_main_context_default () == g_main_context_get_thread_default ()
+	    || !g_main_context_get_thread_default ()) {
+		/* Might not be the best thing here, but as the async operation
+		   is divided into two-steps process, invoking the method and
+		   waiting for its "done" signal, then if the sync method is called
+		   from the main thread, then there is probably no other option.
+		*/
+		while (!e_flag_is_set (sync_data.flag)) {
+			g_usleep (250000);
+			g_main_context_iteration (NULL, FALSE);
+		}
+	} else {
+		/* is called in a dedicated thread */
+		e_flag_wait (sync_data.flag);
+	}
+	e_flag_free (sync_data.flag);
+
+	return sync_data.finish_result;
+}
+
+gboolean
+e_gdbus_proxy_call_sync_void__void (GDBusProxy *proxy, GCancellable *cancellable, GError **error, EGdbusCallStartVoid start_func, EGdbusCallFinishVoid finish_func)
+{
+	g_return_val_if_fail (proxy != NULL, FALSE);
+	g_return_val_if_fail (start_func != NULL, FALSE);
+	g_return_val_if_fail (finish_func != NULL, FALSE);
+
+	return gdbus_proxy_call_sync (proxy, cancellable, error, start_func, finish_func, E_GDBUS_TYPE_VOID, NULL, E_GDBUS_TYPE_VOID, NULL);
+}
+
+gboolean
+e_gdbus_proxy_call_sync_void__boolean (GDBusProxy *proxy, gboolean *out_boolean, GCancellable *cancellable, GError **error, EGdbusCallStartVoid start_func, EGdbusCallFinishBoolean finish_func)
+{
+	g_return_val_if_fail (proxy != NULL, FALSE);
+	g_return_val_if_fail (start_func != NULL, FALSE);
+	g_return_val_if_fail (finish_func != NULL, FALSE);
+	g_return_val_if_fail (out_boolean != NULL, FALSE);
+
+	return gdbus_proxy_call_sync (proxy, cancellable, error, start_func, finish_func, E_GDBUS_TYPE_VOID, NULL, E_GDBUS_TYPE_BOOLEAN, out_boolean);
+}
+
+gboolean
+e_gdbus_proxy_call_sync_void__string (GDBusProxy *proxy, gchar **out_string, GCancellable *cancellable, GError **error, EGdbusCallStartVoid start_func, EGdbusCallFinishString finish_func)
+{
+	g_return_val_if_fail (proxy != NULL, FALSE);
+	g_return_val_if_fail (start_func != NULL, FALSE);
+	g_return_val_if_fail (finish_func != NULL, FALSE);
+	g_return_val_if_fail (out_string != NULL, FALSE);
+
+	return gdbus_proxy_call_sync (proxy, cancellable, error, start_func, finish_func, E_GDBUS_TYPE_VOID, NULL, E_GDBUS_TYPE_STRING, out_string);
+}
+
+gboolean
+e_gdbus_proxy_call_sync_void__strv (GDBusProxy *proxy, gchar ***out_strv, GCancellable *cancellable, GError **error, EGdbusCallStartVoid start_func, EGdbusCallFinishStrv finish_func)
+{
+	g_return_val_if_fail (proxy != NULL, FALSE);
+	g_return_val_if_fail (start_func != NULL, FALSE);
+	g_return_val_if_fail (finish_func != NULL, FALSE);
+	g_return_val_if_fail (out_strv != NULL, FALSE);
+
+	return gdbus_proxy_call_sync (proxy, cancellable, error, start_func, finish_func, E_GDBUS_TYPE_VOID, NULL, E_GDBUS_TYPE_STRV, out_strv);
+}
+
+gboolean
+e_gdbus_proxy_call_sync_void__uint (GDBusProxy *proxy, guint *out_uint, GCancellable *cancellable, GError **error, EGdbusCallStartVoid start_func, EGdbusCallFinishUint finish_func)
+{
+	g_return_val_if_fail (proxy != NULL, FALSE);
+	g_return_val_if_fail (start_func != NULL, FALSE);
+	g_return_val_if_fail (finish_func != NULL, FALSE);
+	g_return_val_if_fail (out_uint != NULL, FALSE);
+
+	return gdbus_proxy_call_sync (proxy, cancellable, error, start_func, finish_func, E_GDBUS_TYPE_VOID, NULL, E_GDBUS_TYPE_UINT, out_uint);
+}
+
+gboolean
+e_gdbus_proxy_call_sync_boolean__void (GDBusProxy *proxy, gboolean in_boolean, GCancellable *cancellable, GError **error, EGdbusCallStartBoolean start_func, EGdbusCallFinishVoid finish_func)
+{
+	g_return_val_if_fail (proxy != NULL, FALSE);
+	g_return_val_if_fail (start_func != NULL, FALSE);
+	g_return_val_if_fail (finish_func != NULL, FALSE);
+
+	return gdbus_proxy_call_sync (proxy, cancellable, error, start_func, finish_func, E_GDBUS_TYPE_BOOLEAN, &in_boolean, E_GDBUS_TYPE_VOID, NULL);
+}
+
+gboolean
+e_gdbus_proxy_call_sync_string__void (GDBusProxy *proxy, const gchar *in_string, GCancellable *cancellable, GError **error, EGdbusCallStartString start_func, EGdbusCallFinishVoid finish_func)
+{
+	g_return_val_if_fail (proxy != NULL, FALSE);
+	g_return_val_if_fail (start_func != NULL, FALSE);
+	g_return_val_if_fail (finish_func != NULL, FALSE);
+	g_return_val_if_fail (in_string != NULL, FALSE);
+
+	return gdbus_proxy_call_sync (proxy, cancellable, error, start_func, finish_func, E_GDBUS_TYPE_STRING, in_string, E_GDBUS_TYPE_VOID, NULL);
+}
+
+gboolean
+e_gdbus_proxy_call_sync_strv__void (GDBusProxy *proxy, const gchar * const *in_strv, GCancellable *cancellable, GError **error, EGdbusCallStartStrv start_func, EGdbusCallFinishVoid finish_func)
+{
+	g_return_val_if_fail (proxy != NULL, FALSE);
+	g_return_val_if_fail (start_func != NULL, FALSE);
+	g_return_val_if_fail (finish_func != NULL, FALSE);
+	g_return_val_if_fail (in_strv != NULL, FALSE);
+
+	return gdbus_proxy_call_sync (proxy, cancellable, error, start_func, finish_func, E_GDBUS_TYPE_STRV, in_strv, E_GDBUS_TYPE_VOID, NULL);
+}
+
+gboolean
+e_gdbus_proxy_call_sync_uint__void (GDBusProxy *proxy, guint in_uint, GCancellable *cancellable, GError **error, EGdbusCallStartUint start_func, EGdbusCallFinishVoid finish_func)
+{
+	g_return_val_if_fail (proxy != NULL, FALSE);
+	g_return_val_if_fail (start_func != NULL, FALSE);
+	g_return_val_if_fail (finish_func != NULL, FALSE);
+
+	return gdbus_proxy_call_sync (proxy, cancellable, error, start_func, finish_func, E_GDBUS_TYPE_UINT, &in_uint, E_GDBUS_TYPE_VOID, NULL);
+}
+
+gboolean
+e_gdbus_proxy_call_sync_string__string (GDBusProxy *proxy, const gchar *in_string, gchar **out_string, GCancellable *cancellable, GError **error, EGdbusCallStartString start_func, EGdbusCallFinishString finish_func)
+{
+	g_return_val_if_fail (proxy != NULL, FALSE);
+	g_return_val_if_fail (start_func != NULL, FALSE);
+	g_return_val_if_fail (finish_func != NULL, FALSE);
+	g_return_val_if_fail (in_string != NULL, FALSE);
+	g_return_val_if_fail (out_string != NULL, FALSE);
+
+	return gdbus_proxy_call_sync (proxy, cancellable, error, start_func, finish_func, E_GDBUS_TYPE_STRING, in_string, E_GDBUS_TYPE_STRING, out_string);
+}
+
+gboolean
+e_gdbus_proxy_call_sync_string__strv (GDBusProxy *proxy, const gchar *in_string, gchar ***out_strv, GCancellable *cancellable, GError **error, EGdbusCallStartString start_func, EGdbusCallFinishStrv finish_func)
+{
+	g_return_val_if_fail (proxy != NULL, FALSE);
+	g_return_val_if_fail (start_func != NULL, FALSE);
+	g_return_val_if_fail (finish_func != NULL, FALSE);
+	g_return_val_if_fail (in_string != NULL, FALSE);
+	g_return_val_if_fail (out_strv != NULL, FALSE);
+
+	return gdbus_proxy_call_sync (proxy, cancellable, error, start_func, finish_func, E_GDBUS_TYPE_STRING, in_string, E_GDBUS_TYPE_STRV, out_strv);
+}
+
+gboolean
+e_gdbus_proxy_call_sync_strv__string (GDBusProxy *proxy, const gchar * const *in_strv, gchar **out_string, GCancellable *cancellable, GError **error, EGdbusCallStartStrv start_func, EGdbusCallFinishString finish_func)
+{
+	g_return_val_if_fail (proxy != NULL, FALSE);
+	g_return_val_if_fail (start_func != NULL, FALSE);
+	g_return_val_if_fail (finish_func != NULL, FALSE);
+	g_return_val_if_fail (in_strv != NULL, FALSE);
+	g_return_val_if_fail (out_string != NULL, FALSE);
+
+	return gdbus_proxy_call_sync (proxy, cancellable, error, start_func, finish_func, E_GDBUS_TYPE_STRV, in_strv, E_GDBUS_TYPE_STRING, out_string);
+}
+
+gboolean
+e_gdbus_proxy_call_sync_strv__strv (GDBusProxy *proxy, const gchar * const *in_strv, gchar ***out_strv, GCancellable *cancellable, GError **error, EGdbusCallStartStrv start_func, EGdbusCallFinishStrv finish_func)
+{
+	g_return_val_if_fail (proxy != NULL, FALSE);
+	g_return_val_if_fail (start_func != NULL, FALSE);
+	g_return_val_if_fail (finish_func != NULL, FALSE);
+	g_return_val_if_fail (in_strv != NULL, FALSE);
+	g_return_val_if_fail (out_strv != NULL, FALSE);
+
+	return gdbus_proxy_call_sync (proxy, cancellable, error, start_func, finish_func, E_GDBUS_TYPE_STRV, in_strv, E_GDBUS_TYPE_STRV, out_strv);
+}
+
+static void
+proxy_method_call (const gchar *method_name, guint param_type, gconstpointer param_value, GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	GVariant *params = NULL;
+	GVariant *item;
+	GVariantBuilder *builder = NULL;
+
+	g_return_if_fail (method_name != NULL);
+	g_return_if_fail (proxy != NULL);
+	g_return_if_fail (G_IS_DBUS_PROXY (proxy));
+	if (param_type != E_GDBUS_TYPE_VOID)
+		g_return_if_fail (param_value != NULL);
+
+	switch (param_type) {
+	case E_GDBUS_TYPE_VOID:
+		break;
+	case E_GDBUS_TYPE_BOOLEAN:
+		builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
+		item = g_variant_new_boolean (* ((const gboolean *) param_value));
+		g_variant_builder_add_value (builder, item);
+		break;
+	case E_GDBUS_TYPE_STRING:
+		builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
+		item = g_variant_new_string ((const gchar *) param_value);
+		g_variant_builder_add_value (builder, item);
+		break;
+	case E_GDBUS_TYPE_STRV:
+		builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
+		item = g_variant_new_strv ((const gchar * const *) param_value, -1);
+		g_variant_builder_add_value (builder, item);
+		break;
+	case E_GDBUS_TYPE_UINT:
+		builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
+		item = g_variant_new_uint32 (* ((const guint *) param_value));
+		g_variant_builder_add_value (builder, item);
+		break;
+	default:
+		g_warning ("%s: Unknown 'param' E_GDBUS_TYPE %x", G_STRFUNC, param_type);
+		return;
+	}
+
+	if (builder != NULL) {
+		params = g_variant_builder_end (builder);
+		g_variant_builder_unref (builder);
+	}
+
+	g_dbus_proxy_call (G_DBUS_PROXY (proxy), method_name, params, G_DBUS_CALL_FLAGS_NONE, e_data_server_util_get_dbus_call_timeout (), cancellable, callback, user_data);	
+}
+
+void
+e_gdbus_proxy_method_call_void (const gchar *method_name, GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	proxy_method_call (method_name, E_GDBUS_TYPE_VOID, NULL, proxy, cancellable, callback, user_data);
+}
+
+void
+e_gdbus_proxy_method_call_boolean (const gchar *method_name, GDBusProxy *proxy, gboolean in_boolean, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	proxy_method_call (method_name, E_GDBUS_TYPE_BOOLEAN, &in_boolean, proxy, cancellable, callback, user_data);
+}
+
+void
+e_gdbus_proxy_method_call_string (const gchar *method_name, GDBusProxy *proxy, const gchar *in_string, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	proxy_method_call (method_name, E_GDBUS_TYPE_STRING, in_string, proxy, cancellable, callback, user_data);
+}
+
+void
+e_gdbus_proxy_method_call_strv (const gchar *method_name, GDBusProxy *proxy, const gchar * const *in_strv, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	proxy_method_call (method_name, E_GDBUS_TYPE_STRV, in_strv, proxy, cancellable, callback, user_data);
+}
+
+void
+e_gdbus_proxy_method_call_uint (const gchar *method_name, GDBusProxy *proxy, guint in_uint, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
+{
+	proxy_method_call (method_name, E_GDBUS_TYPE_VOID, &in_uint, proxy, cancellable, callback, user_data);
+}
+
+static gboolean
+process_result (const gchar *caller_func_name, guint out_type, gpointer out_value, GVariant *_result)
+{
+	if (out_type != E_GDBUS_TYPE_VOID)
+		g_return_val_if_fail (out_value != NULL, FALSE);
+
+	if (_result == NULL)
+		return FALSE;
+
+	switch (out_type) {
+	case E_GDBUS_TYPE_VOID:
+		break;
+	case E_GDBUS_TYPE_BOOLEAN:
+		g_variant_get (_result, "(b)", (gboolean *) out_value);
+		break;
+	case E_GDBUS_TYPE_STRING:
+		g_variant_get (_result, "(s)", (gchar **) out_value);
+		break;
+	case E_GDBUS_TYPE_STRV:
+		g_variant_get (_result, "(^as)", (gchar ***) out_value);
+		break;
+	case E_GDBUS_TYPE_UINT:
+		g_variant_get (_result, "(u)", (guint *) out_value);
+		break;
+	default:
+		g_warning ("%s: Unknown 'out' E_GDBUS_TYPE %x", caller_func_name ? caller_func_name : G_STRFUNC, out_type);
+		break;
+	}
+
+	g_variant_unref (_result);
+
+	return TRUE;
+}
+
+static gboolean
+proxy_method_call_finish (guint out_type, gpointer out_param, GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	g_return_val_if_fail (proxy != NULL, FALSE);
+	g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), FALSE);
+	if (out_type != E_GDBUS_TYPE_VOID)
+		g_return_val_if_fail (out_param != NULL, FALSE);
+
+	return process_result (G_STRFUNC, out_type, out_param, g_dbus_proxy_call_finish (proxy, result, error));
+}
+
+gboolean
+e_gdbus_proxy_method_call_finish_void (GDBusProxy *proxy, GAsyncResult *result, GError **error)
+{
+	return proxy_method_call_finish (E_GDBUS_TYPE_VOID, NULL, proxy, result, error);
+}
+
+gboolean
+e_gdbus_proxy_method_call_finish_boolean (GDBusProxy *proxy, GAsyncResult *result, gboolean *out_boolean, GError **error)
+{
+	return proxy_method_call_finish (E_GDBUS_TYPE_BOOLEAN, out_boolean, proxy, result, error);
+}
+
+gboolean
+e_gdbus_proxy_method_call_finish_string (GDBusProxy *proxy, GAsyncResult *result, gchar **out_string, GError **error)
+{
+	return proxy_method_call_finish (E_GDBUS_TYPE_STRING, out_string, proxy, result, error);
+}
+
+gboolean
+e_gdbus_proxy_method_call_finish_strv (GDBusProxy *proxy, GAsyncResult *result, gchar ***out_strv, GError **error)
+{
+	return proxy_method_call_finish (E_GDBUS_TYPE_STRV, out_strv, proxy, result, error);
+}
+
+gboolean
+e_gdbus_proxy_method_call_finish_uint (GDBusProxy *proxy, GAsyncResult *result, guint *out_uint, GError **error)
+{
+	return proxy_method_call_finish (E_GDBUS_TYPE_UINT, out_uint, proxy, result, error);
+}
+
+static gboolean
+proxy_method_call_sync (const gchar *method_name, guint in_type, gconstpointer in_value, guint out_type, gpointer out_value, GDBusProxy *proxy, GCancellable *cancellable, GError **error)
+{
+	GVariant *params = NULL;
+	GVariant *item;
+	GVariantBuilder *builder = NULL;
+
+	g_return_val_if_fail (method_name != NULL, FALSE);
+	g_return_val_if_fail (proxy != NULL, FALSE);
+	g_return_val_if_fail (G_IS_DBUS_PROXY (proxy), FALSE);
+	if (in_type != E_GDBUS_TYPE_VOID)
+		g_return_val_if_fail (in_value != NULL, FALSE);
+	if (out_type != E_GDBUS_TYPE_VOID)
+		g_return_val_if_fail (out_value != NULL, FALSE);
+
+	switch (in_type) {
+	case E_GDBUS_TYPE_VOID:
+		break;
+	case E_GDBUS_TYPE_BOOLEAN:
+		builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
+		item = g_variant_new_boolean (* ((const gboolean *) in_value));
+		g_variant_builder_add_value (builder, item);
+		break;
+	case E_GDBUS_TYPE_STRING:
+		builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
+		item = g_variant_new_string ((const gchar *) in_value);
+		g_variant_builder_add_value (builder, item);
+		break;
+	case E_GDBUS_TYPE_STRV:
+		builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
+		item = g_variant_new_strv ((const gchar * const *) in_value, -1);
+		g_variant_builder_add_value (builder, item);
+		break;
+	case E_GDBUS_TYPE_UINT:
+		builder = g_variant_builder_new (G_VARIANT_TYPE_TUPLE);
+		item = g_variant_new_uint32 (* ((const guint *) in_value));
+		g_variant_builder_add_value (builder, item);
+		break;
+	default:
+		g_warning ("%s: Unknown 'in' E_GDBUS_TYPE %x", G_STRFUNC, in_type);
+		return FALSE;
+	}
+
+	if (builder != NULL) {
+		params = g_variant_builder_end (builder);
+		g_variant_builder_unref (builder);
+	}
+
+	return process_result (G_STRFUNC, out_type, out_value, g_dbus_proxy_call_sync (G_DBUS_PROXY (proxy), method_name, params, G_DBUS_CALL_FLAGS_NONE, e_data_server_util_get_dbus_call_timeout (), cancellable, error));
+}
+
+gboolean
+e_gdbus_proxy_method_call_sync_void__void (const gchar *method_name, GDBusProxy *proxy, GCancellable *cancellable, GError **error)
+{
+	return proxy_method_call_sync (method_name, E_GDBUS_TYPE_VOID, NULL, E_GDBUS_TYPE_VOID, NULL, proxy, cancellable, error);
+}
+
+gboolean
+e_gdbus_proxy_method_call_sync_boolean__void (const gchar *method_name, GDBusProxy *proxy, gboolean in_boolean, GCancellable *cancellable, GError **error)
+{
+	return proxy_method_call_sync (method_name, E_GDBUS_TYPE_BOOLEAN, &in_boolean, E_GDBUS_TYPE_VOID, NULL, proxy, cancellable, error);
+}
+
+gboolean
+e_gdbus_proxy_method_call_sync_string__void (const gchar *method_name, GDBusProxy *proxy, const gchar *in_string, GCancellable *cancellable, GError **error)
+{
+	return proxy_method_call_sync (method_name, E_GDBUS_TYPE_STRING, in_string, E_GDBUS_TYPE_VOID, NULL, proxy, cancellable, error);
+}
+
+gboolean
+e_gdbus_proxy_method_call_sync_strv__void (const gchar *method_name, GDBusProxy *proxy, const gchar * const *in_strv, GCancellable *cancellable, GError **error)
+{
+	return proxy_method_call_sync (method_name, E_GDBUS_TYPE_STRV, in_strv, E_GDBUS_TYPE_VOID, NULL, proxy, cancellable, error);
+}
+
+gboolean
+e_gdbus_proxy_method_call_sync_uint__void (const gchar *method_name, GDBusProxy *proxy, guint in_uint, GCancellable *cancellable, GError **error)
+{
+	return proxy_method_call_sync (method_name, E_GDBUS_TYPE_UINT, &in_uint, E_GDBUS_TYPE_VOID, NULL, proxy, cancellable, error);
+}
+
+gboolean
+e_gdbus_proxy_method_call_sync_string__string (const gchar *method_name, GDBusProxy *proxy, const gchar *in_string, gchar **out_string, GCancellable *cancellable, GError **error)
+{
+	return proxy_method_call_sync (method_name, E_GDBUS_TYPE_STRING, in_string, E_GDBUS_TYPE_STRING, out_string, proxy, cancellable, error);
+}
+
+gboolean
+e_gdbus_proxy_method_call_sync_strv__string (const gchar *method_name, GDBusProxy *proxy, const gchar * const *in_strv, gchar **out_string, GCancellable *cancellable, GError **error)
+{
+	return proxy_method_call_sync (method_name, E_GDBUS_TYPE_STRV, in_strv, E_GDBUS_TYPE_STRING, out_string, proxy, cancellable, error);
+}
+
+/* free returned pointer with g_strfreev() */
+gchar **
+e_gdbus_templates_encode_error (const GError *in_error)
+{
+	gchar **strv;
+
+	strv = g_new0 (gchar *, 3);
+
+	if (!in_error) {
+		strv[0] = g_strdup ("");
+		strv[1] = g_strdup ("");
+	} else {
+		gchar *dbus_error_name = g_dbus_error_encode_gerror (in_error);
+
+		strv[0] = e_util_utf8_make_valid (dbus_error_name ? dbus_error_name : "");
+		strv[1] = e_util_utf8_make_valid (in_error->message);
+
+		g_free (dbus_error_name);
+	}
+
+	return strv;
+}
+
+/* free *out_error with g_error_free(), if not NULL */
+gboolean
+e_gdbus_templates_decode_error (const gchar * const *in_strv, GError **out_error)
+{
+	const gchar *error_name, *error_message;
+
+	g_return_val_if_fail (out_error != NULL, FALSE);
+
+	*out_error = NULL;
+
+	g_return_val_if_fail (in_strv != NULL, FALSE);
+	g_return_val_if_fail (in_strv[0] != NULL, FALSE);
+	g_return_val_if_fail (in_strv[1] != NULL, FALSE);
+	g_return_val_if_fail (in_strv[2] == NULL, FALSE);
+
+	error_name = in_strv[0];
+	error_message = in_strv[1];
+
+	if (error_name && *error_name && error_message)
+		*out_error = g_dbus_error_new_for_dbus_error (error_name, error_message);
+
+	return TRUE;
+}
diff --git a/libedataserver/e-gdbus-templates.h b/libedataserver/e-gdbus-templates.h
new file mode 100644
index 0000000..ce32798
--- /dev/null
+++ b/libedataserver/e-gdbus-templates.h
@@ -0,0 +1,750 @@
+/*
+ * e-gdbus-templates.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 2011 Red Hat, Inc. (www.redhat.com)
+ *
+ */
+
+#ifndef E_GDBUS_TEMPLATES_H
+#define E_GDBUS_TEMPLATES_H
+
+#include <gio/gio.h>
+#include <libedataserver/e-gdbus-marshallers.h>
+
+G_BEGIN_DECLS
+
+#define E_TYPE_GDBUS_ASYNC_OP_KEEPER		(e_gdbus_async_op_keeper_get_type ())
+#define E_GDBUS_ASYNC_OP_KEEPER(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), E_TYPE_GDBUS_ASYNC_OP_KEEPER, EGdbusAsyncOpKeeper))
+#define E_IS_GDBUS_ASYNC_OP_KEEPER(o)		(G_TYPE_CHECK_INSTANCE_TYPE ((o), E_TYPE_GDBUS_ASYNC_OP_KEEPER))
+#define E_GDBUS_ASYNC_OP_KEEPER_GET_IFACE(o)	(G_TYPE_INSTANCE_GET_INTERFACE((o), E_TYPE_GDBUS_ASYNC_OP_KEEPER, EGdbusAsyncOpKeeperInterface))
+
+typedef struct _EGdbusAsyncOpKeeper EGdbusAsyncOpKeeper; /* Dummy typedef */
+typedef struct _EGdbusAsyncOpKeeperInterface EGdbusAsyncOpKeeperInterface;
+
+struct _EGdbusAsyncOpKeeperInterface
+{
+	GTypeInterface parent_iface;
+
+	GHashTable *	(* get_pending_ops)	(EGdbusAsyncOpKeeper *object);
+	gboolean	(* cancel_op_sync)	(EGdbusAsyncOpKeeper *object, guint in_opid, GCancellable *cancellable, GError **error);
+};
+
+GType e_gdbus_async_op_keeper_get_type (void) G_GNUC_CONST;
+
+GHashTable *	e_gdbus_async_op_keeper_create_pending_ops	(EGdbusAsyncOpKeeper *object);
+GHashTable *	e_gdbus_async_op_keeper_get_pending_ops		(EGdbusAsyncOpKeeper *object);
+gboolean	e_gdbus_async_op_keeper_cancel_op_sync		(EGdbusAsyncOpKeeper *object, guint in_opid, GCancellable *cancellable, GError **error);
+
+enum {
+	E_GDBUS_TYPE_IS_ASYNC	= 1 << 0, /* if set, then OPID and GError precedes to actual parameter */
+	E_GDBUS_TYPE_VOID	= 1 << 1,
+	E_GDBUS_TYPE_BOOLEAN	= 1 << 2,
+	E_GDBUS_TYPE_STRING	= 1 << 3,
+	E_GDBUS_TYPE_STRV	= 1 << 4,
+	E_GDBUS_TYPE_UINT	= 1 << 5
+};
+
+/* _where is a target component name, like ' ## _where ## ' or 'cal'
+   _mname is method name, like 'open'
+   _mtype is method type, like 'method_in'
+   _param_name is parameter name, like 'only_if_exists'
+   _param_type is parameter type, as string, like "s"
+   all except _param_type are identificators, not strings
+*/
+#define E_DECLARE_GDBUS_ARG(_where, _mname, _mtype, _param_name, _param_type)				\
+	static const GDBusArgInfo e_gdbus_ ## _where ## _ ## _mtype ## _mname ## _param_name =		\
+	{												\
+		-1,											\
+		(gchar *) # _param_name,								\
+		(gchar *) _param_type,									\
+		(GDBusAnnotationInfo **) NULL,								\
+	};
+
+#define E_DECLARE_GDBUS_NOTIFY_SIGNAL_0(_where, _sname)							\
+	static const GDBusSignalInfo e_gdbus_ ## _where ## _signal_ ## _sname =				\
+	{												\
+		-1,											\
+		(gchar *) # _sname,									\
+		(GDBusArgInfo **) NULL,									\
+		(GDBusAnnotationInfo **) NULL,								\
+	};
+
+#define E_DECLARE_GDBUS_NOTIFY_SIGNAL_1(_where, _sname, _p1_name, _p1_type)				\
+	E_DECLARE_GDBUS_ARG (_where, _sname, signal, _p1_name, _p1_type)				\
+													\
+	static const GDBusArgInfo * const e_gdbus_ ## _where ## _signal_arg_pointers_ ## _sname[] =	\
+	{												\
+		&e_gdbus_ ## _where ## _signal ## _sname ## _p1_name,					\
+		NULL											\
+	};												\
+													\
+	static const GDBusSignalInfo e_gdbus_ ## _where ## _signal_ ## _sname =				\
+	{												\
+		-1,											\
+		(gchar *) # _sname,									\
+		(GDBusArgInfo **) &e_gdbus_ ## _where ## _signal_arg_pointers_ ## _sname,		\
+		(GDBusAnnotationInfo **) NULL,								\
+	};
+
+#define E_DECLARE_GDBUS_NOTIFY_SIGNAL_2(_where, _sname, _p1_name, _p1_type, _p2_name, _p2_type)		\
+	E_DECLARE_GDBUS_ARG (_where, _sname, signal, _p1_name, _p1_type)				\
+	E_DECLARE_GDBUS_ARG (_where, _sname, signal, _p2_name, _p2_type)				\
+													\
+	static const GDBusArgInfo * const e_gdbus_ ## _where ## _signal_arg_pointers_ ## _sname[] =	\
+	{												\
+		&e_gdbus_ ## _where ## _signal ## _sname ## _p1_name,					\
+		&e_gdbus_ ## _where ## _signal ## _sname ## _p2_name,					\
+		NULL											\
+	};												\
+													\
+	static const GDBusSignalInfo e_gdbus_ ## _where ## _signal_ ## _sname =				\
+	{												\
+		-1,											\
+		(gchar *) # _sname,									\
+		(GDBusArgInfo **) &e_gdbus_ ## _where ## _signal_arg_pointers_ ## _sname,		\
+		(GDBusAnnotationInfo **) NULL,								\
+	};
+
+#define E_DECLARE_GDBUS_ASYNC_DONE_SIGNAL_0(_where, _sname)						\
+	E_DECLARE_GDBUS_ARG (_where, _sname, signal, opid, "u")						\
+	E_DECLARE_GDBUS_ARG (_where, _sname, signal, dbus_error_name, "s")				\
+	E_DECLARE_GDBUS_ARG (_where, _sname, signal, dbus_error_message, "s")				\
+													\
+	static const GDBusArgInfo * const e_gdbus_ ## _where ## _signal_arg_pointers_ ## _sname[] =	\
+	{												\
+		&e_gdbus_ ## _where ## _signal ## _sname ## opid,					\
+		&e_gdbus_ ## _where ## _signal ## _sname ## dbus_error_name,				\
+		&e_gdbus_ ## _where ## _signal ## _sname ## dbus_error_message,				\
+		NULL											\
+	};												\
+													\
+	static const GDBusSignalInfo e_gdbus_ ## _where ## _signal_ ## _sname =				\
+	{												\
+		-1,											\
+		(gchar *) # _sname,									\
+		(GDBusArgInfo **) &e_gdbus_ ## _where ## _signal_arg_pointers_ ## _sname,		\
+		(GDBusAnnotationInfo **) NULL,								\
+	};
+
+#define E_DECLARE_GDBUS_ASYNC_DONE_SIGNAL_1(_where, _sname, _p1_name, _p1_type)				\
+	E_DECLARE_GDBUS_ARG (_where, _sname, signal, opid, "u")						\
+	E_DECLARE_GDBUS_ARG (_where, _sname, signal, dbus_error_name, "s")				\
+	E_DECLARE_GDBUS_ARG (_where, _sname, signal, dbus_error_message, "s")				\
+	E_DECLARE_GDBUS_ARG (_where, _sname, signal, _p1_name, _p1_type)				\
+													\
+	static const GDBusArgInfo * const e_gdbus_ ## _where ## _signal_arg_pointers_ ## _sname[] =	\
+	{												\
+		&e_gdbus_ ## _where ## _signal ## _sname ## opid,					\
+		&e_gdbus_ ## _where ## _signal ## _sname ## dbus_error_name,				\
+		&e_gdbus_ ## _where ## _signal ## _sname ## dbus_error_message,				\
+		&e_gdbus_ ## _where ## _signal ## _sname ## _p1_name,					\
+		NULL											\
+	};												\
+													\
+	static const GDBusSignalInfo e_gdbus_ ## _where ## _signal_ ## _sname =				\
+	{												\
+		-1,											\
+		(gchar *) # _sname,									\
+		(GDBusArgInfo **) &e_gdbus_ ## _where ## _signal_arg_pointers_ ## _sname,		\
+		(GDBusAnnotationInfo **) NULL,								\
+	};
+
+#define E_DECLARE_GDBUS_SYNC_METHOD_0(_where, _mname)							\
+	static const GDBusMethodInfo e_gdbus_ ## _where ## _method_ ## _mname =				\
+	{												\
+		-1,											\
+		(gchar *) # _mname,									\
+		(GDBusArgInfo **) NULL,									\
+		(GDBusArgInfo **) NULL,									\
+		(GDBusAnnotationInfo **) NULL,								\
+	};
+
+#define E_DECLARE_GDBUS_SYNC_METHOD_1(_where, _mname, _p1_name, _p1_type)				\
+	E_DECLARE_GDBUS_ARG (_where, _mname, method_in, _p1_name, _p1_type)				\
+													\
+	static const GDBusArgInfo * const e_gdbus_ ## _where ## _method_in_arg_pointers_ ## _mname[] =	\
+	{												\
+		&e_gdbus_ ## _where ## _method_in ## _mname ## _p1_name,				\
+		NULL											\
+	};												\
+													\
+	static const GDBusMethodInfo e_gdbus_ ## _where ## _method_ ## _mname =				\
+	{												\
+		-1,											\
+		(gchar *) # _mname,									\
+		(GDBusArgInfo **) &e_gdbus_ ## _where ## _method_in_arg_pointers_ ## _mname,		\
+		(GDBusArgInfo **) NULL,									\
+		(GDBusAnnotationInfo **) NULL,								\
+	};
+
+#define E_DECLARE_GDBUS_SYNC_METHOD_0_WITH_RETURN(_where, _mname, _r1_name, _r1_type)			\
+	E_DECLARE_GDBUS_ARG (_where, _mname, method_out, _r1_name, _r1_type)				\
+													\
+	static const GDBusArgInfo * const e_gdbus_ ## _where ## _method_out_arg_pointers_ ## _mname[] =	\
+	{												\
+		&e_gdbus_ ## _where ## _method_out ## _mname ## _r1_name,				\
+		NULL											\
+	};												\
+													\
+	static const GDBusMethodInfo e_gdbus_ ## _where ## _method_ ## _mname =				\
+	{												\
+		-1,											\
+		(gchar *) # _mname,									\
+		(GDBusArgInfo **) NULL,									\
+		(GDBusArgInfo **) &e_gdbus_ ## _where ## _method_out_arg_pointers_ ## _mname,		\
+		(GDBusAnnotationInfo **) NULL,								\
+	};
+
+#define E_DECLARE_GDBUS_SYNC_METHOD_1_WITH_RETURN(_where, _mname, _p1_name, _p1_type, _r1_name, _r1_type)\
+	E_DECLARE_GDBUS_ARG (_where, _mname, method_in, _p1_name, _p1_type)				\
+	E_DECLARE_GDBUS_ARG (_where, _mname, method_out, _r1_name, _r1_type)				\
+													\
+	static const GDBusArgInfo * const e_gdbus_ ## _where ## _method_in_arg_pointers_ ## _mname[] =	\
+	{												\
+		&e_gdbus_ ## _where ## _method_in ## _mname ## _p1_name,				\
+		NULL											\
+	};												\
+													\
+	static const GDBusArgInfo * const e_gdbus_ ## _where ## _method_out_arg_pointers_ ## _mname[] =	\
+	{												\
+		&e_gdbus_ ## _where ## _method_out ## _mname ## _r1_name,				\
+		NULL											\
+	};												\
+													\
+	static const GDBusMethodInfo e_gdbus_ ## _where ## _method_ ## _mname =				\
+	{												\
+		-1,											\
+		(gchar *) # _mname,									\
+		(GDBusArgInfo **) &e_gdbus_ ## _where ## _method_in_arg_pointers_ ## _mname,		\
+		(GDBusArgInfo **) &e_gdbus_ ## _where ## _method_out_arg_pointers_ ## _mname,		\
+		(GDBusAnnotationInfo **) NULL,								\
+	};
+
+#define E_DECLARE_GDBUS_ASYNC_METHOD_0(_where, _mname)							\
+	E_DECLARE_GDBUS_ASYNC_DONE_SIGNAL_0 (_where, _mname ## _done)					\
+	E_DECLARE_GDBUS_ARG (_where, _mname, method_out, opid, "u")					\
+													\
+	static const GDBusArgInfo * const e_gdbus_ ## _where ## _method_out_arg_pointers_ ## _mname[] =	\
+	{												\
+		&e_gdbus_ ## _where ## _method_out ## _mname ## opid,					\
+		NULL											\
+	};												\
+													\
+	static const GDBusMethodInfo e_gdbus_ ## _where ## _method_ ## _mname =				\
+	{												\
+		-1,											\
+		(gchar *) # _mname,									\
+		(GDBusArgInfo **) NULL,									\
+		(GDBusArgInfo **) &e_gdbus_ ## _where ## _method_out_arg_pointers_ ## _mname,		\
+		(GDBusAnnotationInfo **) NULL,								\
+	};
+
+#define E_DECLARE_GDBUS_ASYNC_METHOD_1(_where, _mname, _p1_name, _p1_type)				\
+	E_DECLARE_GDBUS_ASYNC_DONE_SIGNAL_0 (_where, _mname ## _done)					\
+	E_DECLARE_GDBUS_ARG (_where, _mname, method_in, _p1_name, _p1_type)				\
+	E_DECLARE_GDBUS_ARG (_where, _mname, method_out, opid, "u")					\
+													\
+	static const GDBusArgInfo * const e_gdbus_ ## _where ## _method_in_arg_pointers_ ## _mname[] =	\
+	{												\
+		&e_gdbus_ ## _where ## _method_in ## _mname ## _p1_name,				\
+		NULL											\
+	};												\
+													\
+	static const GDBusArgInfo * const e_gdbus_ ## _where ## _method_out_arg_pointers_ ## _mname[] =	\
+	{												\
+		&e_gdbus_ ## _where ## _method_out ## _mname ## opid,					\
+		NULL											\
+	};												\
+													\
+	static const GDBusMethodInfo e_gdbus_ ## _where ## _method_ ## _mname =				\
+	{												\
+		-1,											\
+		(gchar *) # _mname,									\
+		(GDBusArgInfo **) &e_gdbus_ ## _where ## _method_in_arg_pointers_ ## _mname,		\
+		(GDBusArgInfo **) &e_gdbus_ ## _where ## _method_out_arg_pointers_ ## _mname,		\
+		(GDBusAnnotationInfo **) NULL,								\
+	};
+
+#define E_DECLARE_GDBUS_ASYNC_METHOD_0_WITH_RETURN(_where, _mname, _r1_name, _r1_type)			\
+	E_DECLARE_GDBUS_ASYNC_DONE_SIGNAL_1 (_where, _mname ## _done, _r1_name, _r1_type)		\
+	E_DECLARE_GDBUS_ARG (_where, _mname, method_out, opid, "u")					\
+													\
+	static const GDBusArgInfo * const e_gdbus_ ## _where ## _method_out_arg_pointers_ ## _mname[] =	\
+	{												\
+		&e_gdbus_ ## _where ## _method_out ## _mname ## opid,					\
+		NULL											\
+	};												\
+													\
+	static const GDBusMethodInfo e_gdbus_ ## _where ## _method_ ## _mname =				\
+	{												\
+		-1,											\
+		(gchar *) # _mname,									\
+		(GDBusArgInfo **) NULL,									\
+		(GDBusArgInfo **) &e_gdbus_ ## _where ## _method_out_arg_pointers_ ## _mname,		\
+		(GDBusAnnotationInfo **) NULL,								\
+	};
+
+#define E_DECLARE_GDBUS_ASYNC_METHOD_1_WITH_RETURN(_where, _mname, _p1_name, _p1_type, _r1_name, _r1_type)\
+	E_DECLARE_GDBUS_ASYNC_DONE_SIGNAL_1 (_where, _mname ## _done, _r1_name, _r1_type)		\
+	E_DECLARE_GDBUS_ARG (_where, _mname, method_in, _p1_name, _p1_type)				\
+	E_DECLARE_GDBUS_ARG (_where, _mname, method_out, opid, "u")					\
+													\
+	static const GDBusArgInfo * const e_gdbus_ ## _where ## _method_in_arg_pointers_ ## _mname[] =	\
+	{												\
+		&e_gdbus_ ## _where ## _method_in ## _mname ## _p1_name,				\
+		NULL											\
+	};												\
+													\
+	static const GDBusArgInfo * const e_gdbus_ ## _where ## _method_out_arg_pointers_ ## _mname[] =	\
+	{												\
+		&e_gdbus_ ## _where ## _method_out ## _mname ## opid,					\
+		NULL											\
+	};												\
+													\
+	static const GDBusMethodInfo e_gdbus_ ## _where ## _method_ ## _mname =				\
+	{												\
+		-1,											\
+		(gchar *) # _mname,									\
+		(GDBusArgInfo **) &e_gdbus_ ## _where ## _method_in_arg_pointers_ ## _mname,		\
+		(GDBusArgInfo **) &e_gdbus_ ## _where ## _method_out_arg_pointers_ ## _mname,		\
+		(GDBusAnnotationInfo **) NULL,								\
+	};
+
+#define E_DECLARED_GDBUS_SIGNAL_INFO_NAME(_where, _sname) e_gdbus_ ## _where ## _signal_ ## _sname
+#define E_DECLARED_GDBUS_METHOD_INFO_NAME(_where, _mname) e_gdbus_ ## _where ## _method_ ## _mname
+
+/* this requires signal_emission_hook_cb_ ## _sig_name hook defined,
+   which can be created with one of E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_... macros */
+#define E_INIT_GDBUS_SIGNAL_VOID(_iface_struct, _dbus_sig_name_str, _sig_name_var, _sig_id)					\
+	signals[_sig_id] = g_signal_new (# _sig_name_var,									\
+			G_TYPE_FROM_INTERFACE (iface),										\
+			G_SIGNAL_RUN_LAST,											\
+			G_STRUCT_OFFSET (_iface_struct, _sig_name_var),								\
+			NULL,													\
+			NULL,													\
+			g_cclosure_marshal_VOID__VOID,										\
+			G_TYPE_NONE,												\
+			0);													\
+																\
+	g_signal_add_emission_hook (signals[_sig_id], 0, signal_emission_hook_cb_ ## _sig_name_var, (gpointer) _dbus_sig_name_str, NULL);\
+	g_hash_table_insert (_signal_name_to_id, (gpointer) _dbus_sig_name_str, GUINT_TO_POINTER (_sig_id));			\
+	g_hash_table_insert (_signal_name_to_type, (gpointer) _dbus_sig_name_str, GUINT_TO_POINTER (E_GDBUS_TYPE_VOID));
+
+#define E_INIT_GDBUS_SIGNAL_TMPL_TYPED(_mtype, _gtype, _iface_struct, _dbus_sig_name_str, _sig_name_var, _sig_id)		\
+	signals[_sig_id] = g_signal_new (# _sig_name_var,									\
+			G_TYPE_FROM_INTERFACE (iface),										\
+			G_SIGNAL_RUN_LAST,											\
+			G_STRUCT_OFFSET (_iface_struct, _sig_name_var),								\
+			NULL,													\
+			NULL,													\
+			g_cclosure_marshal_VOID__ ## _mtype,									\
+			G_TYPE_NONE,												\
+			1,													\
+			G_TYPE_ ## _gtype);											\
+																\
+	g_signal_add_emission_hook (signals[_sig_id], 0, signal_emission_hook_cb_ ## _sig_name_var, (gpointer) _dbus_sig_name_str, NULL);\
+	g_hash_table_insert (_signal_name_to_id, (gpointer) _dbus_sig_name_str, GUINT_TO_POINTER (_sig_id));			\
+	g_hash_table_insert (_signal_name_to_type, (gpointer) _dbus_sig_name_str, GUINT_TO_POINTER (E_GDBUS_TYPE_ ## _gtype));
+
+#define E_INIT_GDBUS_SIGNAL_BOOLEAN(_iface_struct, _dbus_sig_name_str, _sig_name_var, _sig_id)					\
+	E_INIT_GDBUS_SIGNAL_TMPL_TYPED (BOOLEAN, BOOLEAN, _iface_struct, _dbus_sig_name_str, _sig_name_var, _sig_id)
+
+#define E_INIT_GDBUS_SIGNAL_STRING(_iface_struct, _dbus_sig_name_str, _sig_name_var, _sig_id)					\
+	E_INIT_GDBUS_SIGNAL_TMPL_TYPED (STRING, STRING, _iface_struct, _dbus_sig_name_str, _sig_name_var, _sig_id)
+
+#define E_INIT_GDBUS_SIGNAL_STRV(_iface_struct, _dbus_sig_name_str, _sig_name_var, _sig_id)					\
+	E_INIT_GDBUS_SIGNAL_TMPL_TYPED (BOXED, STRV, _iface_struct, _dbus_sig_name_str, _sig_name_var, _sig_id)
+
+#define E_INIT_GDBUS_SIGNAL_UINT(_iface_struct, _dbus_sig_name_str, _sig_name_var, _sig_id)					\
+	E_INIT_GDBUS_SIGNAL_TMPL_TYPED (UINT, UINT, _iface_struct, _dbus_sig_name_str, _sig_name_var, _sig_id)
+
+#define E_INIT_GDBUS_SIGNAL_UINT_STRING(_iface_struct, _dbus_sig_name_str, _sig_name_var, _sig_id)				\
+	signals[_sig_id] = g_signal_new (# _sig_name_var,									\
+			G_TYPE_FROM_INTERFACE (iface),										\
+			G_SIGNAL_RUN_LAST,											\
+			G_STRUCT_OFFSET (_iface_struct, _sig_name_var),								\
+			NULL,													\
+			NULL,													\
+			e_gdbus_marshallers_VOID__UINT_STRING,									\
+			G_TYPE_NONE,												\
+			2,													\
+			G_TYPE_UINT, G_TYPE_STRING);										\
+																\
+	g_signal_add_emission_hook (signals[_sig_id], 0, signal_emission_hook_cb_ ## _sig_name_var, (gpointer) _dbus_sig_name_str, NULL);\
+	g_hash_table_insert (_signal_name_to_id, (gpointer) _dbus_sig_name_str, GUINT_TO_POINTER (_sig_id));			\
+	g_hash_table_insert (_signal_name_to_type, (gpointer) _dbus_sig_name_str, GUINT_TO_POINTER (E_GDBUS_TYPE_UINT | E_GDBUS_TYPE_STRING));
+
+#define E_INIT_GDBUS_METHOD_DONE_VOID(_iface_struct, _sig_name_var, _done_sig_id)						\
+	signals[_done_sig_id] = g_signal_new (# _sig_name_var "_done",								\
+			G_TYPE_FROM_INTERFACE (iface),										\
+			G_SIGNAL_RUN_LAST,											\
+			G_STRUCT_OFFSET (_iface_struct, _sig_name_var ## _done),						\
+			NULL,													\
+			NULL,													\
+			e_gdbus_marshallers_VOID__UINT_BOXED,									\
+			G_TYPE_NONE,												\
+			2,													\
+			G_TYPE_UINT, G_TYPE_ERROR);										\
+	g_signal_add_emission_hook (signals[_done_sig_id], 0,									\
+			signal_emission_hook_cb_ ## _sig_name_var ## _done, (gpointer) # _sig_name_var "_done", NULL);		\
+	g_hash_table_insert (_signal_name_to_id, (gpointer) # _sig_name_var "_done", GUINT_TO_POINTER (_done_sig_id));		\
+	g_hash_table_insert (_signal_name_to_type, (gpointer) # _sig_name_var "_done", GUINT_TO_POINTER (E_GDBUS_TYPE_IS_ASYNC | E_GDBUS_TYPE_VOID));
+
+#define E_INIT_GDBUS_METHOD_DONE_ASYNC_TMPL_TYPED(_mtype, _gtype, _iface_struct, _sig_name_var, _done_sig_id)			\
+	signals[_done_sig_id] = g_signal_new (# _sig_name_var "_done",								\
+			G_TYPE_FROM_INTERFACE (iface),										\
+			G_SIGNAL_RUN_LAST,											\
+			G_STRUCT_OFFSET (_iface_struct, _sig_name_var ## _done),						\
+			NULL,													\
+			NULL,													\
+			e_gdbus_marshallers_VOID__UINT_BOXED_ ## _mtype,							\
+			G_TYPE_NONE,												\
+			3,													\
+			G_TYPE_UINT, G_TYPE_ERROR, G_TYPE_ ## _gtype);								\
+	g_signal_add_emission_hook (signals[_done_sig_id], 0,									\
+			signal_emission_hook_cb_ ## _sig_name_var ## _done, (gpointer) # _sig_name_var "_done", NULL);		\
+	g_hash_table_insert (_signal_name_to_id, (gpointer) # _sig_name_var "_done", GUINT_TO_POINTER (_done_sig_id));		\
+	g_hash_table_insert (_signal_name_to_type, (gpointer) # _sig_name_var "_done", GUINT_TO_POINTER (E_GDBUS_TYPE_IS_ASYNC | E_GDBUS_TYPE_ ## _gtype));
+
+#define E_INIT_GDBUS_METHOD_DONE_BOOLEAN(_iface_struct, _sig_name_var, _done_sig_id)						\
+	E_INIT_GDBUS_METHOD_DONE_ASYNC_TMPL_TYPED (BOOLEAN, BOOLEAN, _iface_struct, _sig_name_var, _done_sig_id)
+
+#define E_INIT_GDBUS_METHOD_DONE_STRING(_iface_struct, _sig_name_var, _done_sig_id)						\
+	E_INIT_GDBUS_METHOD_DONE_ASYNC_TMPL_TYPED (STRING, STRING, _iface_struct, _sig_name_var, _done_sig_id)
+
+#define E_INIT_GDBUS_METHOD_DONE_STRV(_iface_struct, _sig_name_var, _done_sig_id)						\
+	E_INIT_GDBUS_METHOD_DONE_ASYNC_TMPL_TYPED (BOXED, STRV, _iface_struct, _sig_name_var, _done_sig_id)
+
+#define E_INIT_GDBUS_METHOD_DONE_UINT(_iface_struct, _sig_name_var, _done_sig_id)						\
+	E_INIT_GDBUS_METHOD_DONE_ASYNC_TMPL_TYPED (UINT, UINT, _iface_struct, _sig_name_var, _done_sig_id)
+
+/* do not use this directly, there is missing _method_name_to_type insertion */
+#define E_INIT_GDBUS_METHOD_CALL_TMPL_VOID(_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)			\
+	signals[_method_sig_id] = g_signal_new ("handle-" # _sig_name_var,							\
+			G_TYPE_FROM_INTERFACE (iface),										\
+			G_SIGNAL_RUN_LAST,											\
+			G_STRUCT_OFFSET (_iface_struct, handle_ ## _sig_name_var),						\
+			NULL, NULL,												\
+			e_gdbus_marshallers_BOOLEAN__OBJECT,									\
+			G_TYPE_BOOLEAN,												\
+			1,													\
+			G_TYPE_DBUS_METHOD_INVOCATION);										\
+	g_hash_table_insert (_method_name_to_id, (gpointer) _dbus_sig_name_str, GUINT_TO_POINTER (_method_sig_id));
+
+/* do not use this directly, there is missing _method_name_to_type insertion */
+#define E_INIT_GDBUS_METHOD_CALL_TMPL_TYPED(_mtype, _gtype, _iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)	\
+	signals[_method_sig_id] = g_signal_new ("handle-" # _sig_name_var,							\
+			G_TYPE_FROM_INTERFACE (iface),										\
+			G_SIGNAL_RUN_LAST,											\
+			G_STRUCT_OFFSET (_iface_struct, handle_ ## _sig_name_var),						\
+			NULL, NULL,												\
+			e_gdbus_marshallers_BOOLEAN__OBJECT_ ## _mtype,								\
+			G_TYPE_BOOLEAN,												\
+			2,													\
+			G_TYPE_DBUS_METHOD_INVOCATION,										\
+			G_TYPE_ ## _gtype);											\
+	g_hash_table_insert (_method_name_to_id, (gpointer) _dbus_sig_name_str, GUINT_TO_POINTER (_method_sig_id));		\
+
+#define E_INIT_GDBUS_METHOD_CALL_ASYNC_TMPL_TYPED(_mtype, _gtype, _iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)	\
+	E_INIT_GDBUS_METHOD_CALL_TMPL_TYPED (_mtype, _gtype, _iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)	\
+	g_hash_table_insert (_method_name_to_type, (gpointer) _dbus_sig_name_str, GUINT_TO_POINTER (E_GDBUS_TYPE_ ## _gtype | E_GDBUS_TYPE_IS_ASYNC));
+
+#define E_INIT_GDBUS_METHOD_VOID(_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)				\
+	E_INIT_GDBUS_METHOD_CALL_TMPL_VOID(_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)			\
+	g_hash_table_insert (_method_name_to_type, (gpointer) _dbus_sig_name_str, GUINT_TO_POINTER (E_GDBUS_TYPE_VOID));
+
+#define E_INIT_GDBUS_METHOD_BOOLEAN(_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)				\
+	E_INIT_GDBUS_METHOD_CALL_TMPL_TYPED (BOOLEAN, BOOLEAN, _iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)\
+	g_hash_table_insert (_method_name_to_type, (gpointer) _dbus_sig_name_str, GUINT_TO_POINTER (E_GDBUS_TYPE_BOOLEAN));
+
+#define E_INIT_GDBUS_METHOD_STRING(_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)				\
+	E_INIT_GDBUS_METHOD_CALL_TMPL_TYPED (STRING, STRING, _iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)	\
+	g_hash_table_insert (_method_name_to_type, (gpointer) _dbus_sig_name_str, GUINT_TO_POINTER (E_GDBUS_TYPE_STRING));
+
+#define E_INIT_GDBUS_METHOD_STRV(_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)				\
+	E_INIT_GDBUS_METHOD_CALL_TMPL_TYPED (BOXED, STRV, _iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)	\
+	g_hash_table_insert (_method_name_to_type, (gpointer) _dbus_sig_name_str, GUINT_TO_POINTER (E_GDBUS_TYPE_STRV));
+
+#define E_INIT_GDBUS_METHOD_UINT(_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)				\
+	E_INIT_GDBUS_METHOD_CALL_TMPL_TYPED (UINT, UINT, _iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)	\
+	g_hash_table_insert (_method_name_to_type, (gpointer) _dbus_sig_name_str, GUINT_TO_POINTER (E_GDBUS_TYPE_UINT));
+
+#define E_INIT_GDBUS_METHOD_CALL_VOID(_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)				\
+	E_INIT_GDBUS_METHOD_CALL_TMPL_VOID(_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)			\
+	g_hash_table_insert (_method_name_to_type, (gpointer) _dbus_sig_name_str, GUINT_TO_POINTER (E_GDBUS_TYPE_VOID | E_GDBUS_TYPE_IS_ASYNC));
+
+#define E_INIT_GDBUS_METHOD_CALL_BOOLEAN(_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)			\
+	E_INIT_GDBUS_METHOD_CALL_ASYNC_TMPL_TYPED (BOOLEAN, BOOLEAN, _iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)
+
+#define E_INIT_GDBUS_METHOD_CALL_STRING(_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)			\
+	E_INIT_GDBUS_METHOD_CALL_ASYNC_TMPL_TYPED (STRING, STRING, _iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)
+
+#define E_INIT_GDBUS_METHOD_CALL_STRV(_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)				\
+	E_INIT_GDBUS_METHOD_CALL_ASYNC_TMPL_TYPED (BOXED, STRV, _iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)
+
+#define E_INIT_GDBUS_METHOD_CALL_UINT(_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)				\
+	E_INIT_GDBUS_METHOD_CALL_ASYNC_TMPL_TYPED (UINT, UINT, _iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)
+
+#define E_INIT_GDBUS_METHOD_ASYNC_VOID__VOID(_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id, _done_sig_id)	\
+	E_INIT_GDBUS_METHOD_CALL_VOID (_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)			\
+	E_INIT_GDBUS_METHOD_DONE_VOID (_iface_struct, _sig_name_var, _done_sig_id)
+
+#define E_INIT_GDBUS_METHOD_ASYNC_VOID__STRING(_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id, _done_sig_id)	\
+	E_INIT_GDBUS_METHOD_CALL_VOID   (_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)			\
+	E_INIT_GDBUS_METHOD_DONE_STRING (_iface_struct, _sig_name_var, _done_sig_id)
+
+#define E_INIT_GDBUS_METHOD_ASYNC_VOID__STRV(_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id, _done_sig_id)	\
+	E_INIT_GDBUS_METHOD_CALL_VOID (_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)			\
+	E_INIT_GDBUS_METHOD_DONE_STRV (_iface_struct, _sig_name_var, _done_sig_id)
+
+#define E_INIT_GDBUS_METHOD_ASYNC_BOOLEAN__VOID(_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id, _done_sig_id)	\
+	E_INIT_GDBUS_METHOD_CALL_BOOLEAN (_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)			\
+	E_INIT_GDBUS_METHOD_DONE_VOID    (_iface_struct, _sig_name_var, _done_sig_id)
+
+#define E_INIT_GDBUS_METHOD_ASYNC_UINT__VOID(_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id, _done_sig_id)	\
+	E_INIT_GDBUS_METHOD_CALL_UINT (_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)			\
+	E_INIT_GDBUS_METHOD_DONE_VOID (_iface_struct, _sig_name_var, _done_sig_id)
+
+#define E_INIT_GDBUS_METHOD_ASYNC_STRING__VOID(_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id, _done_sig_id)	\
+	E_INIT_GDBUS_METHOD_CALL_STRING (_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)			\
+	E_INIT_GDBUS_METHOD_DONE_VOID   (_iface_struct, _sig_name_var, _done_sig_id)
+
+#define E_INIT_GDBUS_METHOD_ASYNC_STRV__VOID(_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id, _done_sig_id)	\
+	E_INIT_GDBUS_METHOD_CALL_STRV (_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)			\
+	E_INIT_GDBUS_METHOD_DONE_VOID (_iface_struct, _sig_name_var, _done_sig_id)
+
+#define E_INIT_GDBUS_METHOD_ASYNC_STRING__STRING(_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id, _done_sig_id)\
+	E_INIT_GDBUS_METHOD_CALL_STRING (_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)			\
+	E_INIT_GDBUS_METHOD_DONE_STRING (_iface_struct, _sig_name_var, _done_sig_id)
+
+#define E_INIT_GDBUS_METHOD_ASYNC_STRING__STRV(_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id, _done_sig_id)	\
+	E_INIT_GDBUS_METHOD_CALL_STRING (_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)			\
+	E_INIT_GDBUS_METHOD_DONE_STRV   (_iface_struct, _sig_name_var, _done_sig_id)
+
+#define E_INIT_GDBUS_METHOD_ASYNC_STRV__STRING(_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id, _done_sig_id)	\
+	E_INIT_GDBUS_METHOD_CALL_STRV (_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)			\
+	E_INIT_GDBUS_METHOD_DONE_STRING (_iface_struct, _sig_name_var, _done_sig_id)
+
+#define E_INIT_GDBUS_METHOD_ASYNC_STRV__STRV(_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id, _done_sig_id)	\
+	E_INIT_GDBUS_METHOD_CALL_STRV (_iface_struct, _dbus_sig_name_str, _sig_name_var, _method_sig_id)			\
+	E_INIT_GDBUS_METHOD_DONE_STRV (_iface_struct, _sig_name_var, _done_sig_id)
+
+#define E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_VOID(_iface_name, _sig_name)										\
+	static gboolean																	\
+	signal_emission_hook_cb_ ## _sig_name (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, gpointer user_data)	\
+	{																		\
+		return e_gdbus_signal_emission_hook_void (ihint, n_param_values, param_values, user_data, _iface_name);					\
+	}
+
+#define E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_BOOLEAN(_iface_name, _sig_name)										\
+	static gboolean																	\
+	signal_emission_hook_cb_ ## _sig_name (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, gpointer user_data)	\
+	{																		\
+		return e_gdbus_signal_emission_hook_boolean (ihint, n_param_values, param_values, user_data, _iface_name);				\
+	}
+
+#define E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_STRING(_iface_name, _sig_name)										\
+	static gboolean																	\
+	signal_emission_hook_cb_ ## _sig_name (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, gpointer user_data)	\
+	{																		\
+		return e_gdbus_signal_emission_hook_string (ihint, n_param_values, param_values, user_data, _iface_name);				\
+	}
+
+#define E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_STRV(_iface_name, _sig_name)										\
+	static gboolean																	\
+	signal_emission_hook_cb_ ## _sig_name (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, gpointer user_data)	\
+	{																		\
+		return e_gdbus_signal_emission_hook_strv (ihint, n_param_values, param_values, user_data, _iface_name);					\
+	}
+
+#define E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_UINT(_iface_name, _sig_name)										\
+	static gboolean																	\
+	signal_emission_hook_cb_ ## _sig_name (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, gpointer user_data)	\
+	{																		\
+		return e_gdbus_signal_emission_hook_uint (ihint, n_param_values, param_values, user_data, _iface_name);					\
+	}
+
+#define E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_UINT_STRING(_iface_name, _sig_name)										\
+	static gboolean																	\
+	signal_emission_hook_cb_ ## _sig_name (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, gpointer user_data)	\
+	{																		\
+		return e_gdbus_signal_emission_hook_uint_string (ihint, n_param_values, param_values, user_data, _iface_name);					\
+	}
+
+#define E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_ASYNC_VOID(_iface_name, _sig_name)										\
+	static gboolean																	\
+	signal_emission_hook_cb_ ## _sig_name (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, gpointer user_data)	\
+	{																		\
+		return e_gdbus_signal_emission_hook_async_void (ihint, n_param_values, param_values, user_data, _iface_name);				\
+	}
+
+#define E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_ASYNC_BOOLEAN(_iface_name, _sig_name)									\
+	static gboolean																	\
+	signal_emission_hook_cb_ ## _sig_name (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, gpointer user_data)	\
+	{																		\
+		return e_gdbus_signal_emission_hook_async_boolean (ihint, n_param_values, param_values, user_data, _iface_name);			\
+	}
+
+#define E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_ASYNC_STRING(_iface_name, _sig_name)									\
+	static gboolean																	\
+	signal_emission_hook_cb_ ## _sig_name (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, gpointer user_data)	\
+	{																		\
+		return e_gdbus_signal_emission_hook_async_string (ihint, n_param_values, param_values, user_data, _iface_name);				\
+	}
+
+#define E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_ASYNC_STRV(_iface_name, _sig_name)										\
+	static gboolean																	\
+	signal_emission_hook_cb_ ## _sig_name (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, gpointer user_data)	\
+	{																		\
+		return e_gdbus_signal_emission_hook_async_strv (ihint, n_param_values, param_values, user_data, _iface_name);				\
+	}
+
+#define E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_ASYNC_UINT(_iface_name, _sig_name)										\
+	static gboolean																	\
+	signal_emission_hook_cb_ ## _sig_name (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, gpointer user_data)	\
+	{																		\
+		return e_gdbus_signal_emission_hook_async_uint (ihint, n_param_values, param_values, user_data, _iface_name);				\
+	}
+
+#define E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_VOID(_iface_name, _sig_name)									\
+	E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_ASYNC_VOID (_iface_name, _sig_name ## _done)
+
+#define E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_BOOLEAN(_iface_name, _sig_name)									\
+	E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_ASYNC_BOOLEAN (_iface_name, _sig_name ## _done)
+
+#define E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_STRING(_iface_name, _sig_name)									\
+	E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_ASYNC_STRING (_iface_name, _sig_name ## _done)
+
+#define E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_STRV(_iface_name, _sig_name)									\
+	E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_ASYNC_STRV (_iface_name, _sig_name ## _done)
+
+#define E_DECLARE_GDBUS_METHOD_DONE_EMISSION_HOOK_ASYNC_UINT(_iface_name, _sig_name)									\
+	E_DECLARE_GDBUS_SIGNAL_EMISSION_HOOK_ASYNC_UINT (_iface_name, _sig_name ## _done)
+
+#define E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_VOID(_sig_name)												\
+	g_signal_connect (proxy, # _sig_name "_done", G_CALLBACK (e_gdbus_proxy_async_method_done_void), NULL);
+
+#define E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_BOOLEAN(_sig_name)												\
+	g_signal_connect (proxy, # _sig_name "_done", G_CALLBACK (e_gdbus_proxy_async_method_done_boolean), NULL);
+
+#define E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_STRING(_sig_name)												\
+	g_signal_connect (proxy, # _sig_name "_done", G_CALLBACK (e_gdbus_proxy_async_method_done_string), NULL);
+
+#define E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_STRV(_sig_name)												\
+	g_signal_connect (proxy, # _sig_name "_done", G_CALLBACK (e_gdbus_proxy_async_method_done_strv), NULL);
+
+#define E_GDBUS_CONNECT_METHOD_DONE_SIGNAL_UINT(_sig_name)												\
+	g_signal_connect (proxy, # _sig_name "_done", G_CALLBACK (e_gdbus_proxy_async_method_done_uint), NULL);
+
+void e_gdbus_proxy_emit_signal (GDBusProxy *proxy, GVariant *parameters, guint signal_id, guint signal_type);
+void e_gdbus_stub_handle_method_call (GObject *stub_object, GDBusMethodInvocation *invocation, GVariant *parameters, const gchar *method_name, guint method_id, guint method_type);
+
+gboolean e_gdbus_signal_emission_hook_void          (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, const gchar *signal_name, const gchar *iface_name);
+gboolean e_gdbus_signal_emission_hook_boolean       (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, const gchar *signal_name, const gchar *iface_name);
+gboolean e_gdbus_signal_emission_hook_string        (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, const gchar *signal_name, const gchar *iface_name);
+gboolean e_gdbus_signal_emission_hook_strv          (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, const gchar *signal_name, const gchar *iface_name);
+gboolean e_gdbus_signal_emission_hook_uint          (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, const gchar *signal_name, const gchar *iface_name);
+gboolean e_gdbus_signal_emission_hook_uint_string   (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, const gchar *signal_name, const gchar *iface_name);
+
+gboolean e_gdbus_signal_emission_hook_async_void    (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, const gchar *signal_name, const gchar *iface_name);
+gboolean e_gdbus_signal_emission_hook_async_boolean (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, const gchar *signal_name, const gchar *iface_name);
+gboolean e_gdbus_signal_emission_hook_async_string  (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, const gchar *signal_name, const gchar *iface_name);
+gboolean e_gdbus_signal_emission_hook_async_strv    (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, const gchar *signal_name, const gchar *iface_name);
+gboolean e_gdbus_signal_emission_hook_async_uint    (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, const gchar *signal_name, const gchar *iface_name);
+
+/* GDBus calls method completion functions; after the 'async' method is expected associated done signal */
+void e_gdbus_complete_async_method (gpointer object, GDBusMethodInvocation *invocation, guint opid);
+void e_gdbus_complete_sync_method_void		(gpointer object, GDBusMethodInvocation *invocation, const GError *error);
+void e_gdbus_complete_sync_method_boolean	(gpointer object, GDBusMethodInvocation *invocation, gboolean out_boolean, const GError *error);
+void e_gdbus_complete_sync_method_string	(gpointer object, GDBusMethodInvocation *invocation, const gchar *out_string, const GError *error);
+void e_gdbus_complete_sync_method_strv		(gpointer object, GDBusMethodInvocation *invocation, const gchar * const *out_strv, const GError *error);
+void e_gdbus_complete_sync_method_uint		(gpointer object, GDBusMethodInvocation *invocation, guint out_uint, const GError *error);
+
+/* callbacks on done signal handlers in the client proxy, which implements EGdbusAsyncOpKeeper interface;
+   functions take ownership of out parameters and are responsible for their freeing */
+void e_gdbus_proxy_async_method_done_void	(EGdbusAsyncOpKeeper *proxy, guint arg_opid, const GError *error);
+void e_gdbus_proxy_async_method_done_boolean	(EGdbusAsyncOpKeeper *proxy, guint arg_opid, const GError *error, gboolean out_boolean);
+void e_gdbus_proxy_async_method_done_string	(EGdbusAsyncOpKeeper *proxy, guint arg_opid, const GError *error, const gchar *out_string);
+void e_gdbus_proxy_async_method_done_strv	(EGdbusAsyncOpKeeper *proxy, guint arg_opid, const GError *error, const gchar * const *out_strv);
+void e_gdbus_proxy_async_method_done_uint	(EGdbusAsyncOpKeeper *proxy, guint arg_opid, const GError *error, guint out_uint);
+
+void e_gdbus_proxy_call_void	(const gchar *method_name, gpointer source_tag, EGdbusAsyncOpKeeper *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+void e_gdbus_proxy_call_boolean	(const gchar *method_name, gpointer source_tag, EGdbusAsyncOpKeeper *proxy, gboolean in_boolean, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+void e_gdbus_proxy_call_string	(const gchar *method_name, gpointer source_tag, EGdbusAsyncOpKeeper *proxy, const gchar *in_string, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+void e_gdbus_proxy_call_strv	(const gchar *method_name, gpointer source_tag, EGdbusAsyncOpKeeper *proxy, const gchar * const *in_strv, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+void e_gdbus_proxy_call_uint	(const gchar *method_name, gpointer source_tag, EGdbusAsyncOpKeeper *proxy, guint in_uint, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+
+gboolean e_gdbus_proxy_finish_call_void    (EGdbusAsyncOpKeeper *proxy, GAsyncResult *result, GError **error, gpointer source_tag);
+gboolean e_gdbus_proxy_finish_call_boolean (EGdbusAsyncOpKeeper *proxy, GAsyncResult *result, gboolean *out_boolean, GError **error, gpointer source_tag);
+gboolean e_gdbus_proxy_finish_call_string  (EGdbusAsyncOpKeeper *proxy, GAsyncResult *result, gchar **out_string, GError **error, gpointer source_tag);
+gboolean e_gdbus_proxy_finish_call_strv    (EGdbusAsyncOpKeeper *proxy, GAsyncResult *result, gchar ***out_strv, GError **error, gpointer source_tag);
+gboolean e_gdbus_proxy_finish_call_uint    (EGdbusAsyncOpKeeper *proxy, GAsyncResult *result, guint *out_uint, GError **error, gpointer source_tag);
+
+typedef void (* EGdbusCallStartVoid)	(GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+typedef void (* EGdbusCallStartBoolean)	(GDBusProxy *proxy, gboolean in_boolean, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+typedef void (* EGdbusCallStartString)	(GDBusProxy *proxy, const gchar *in_string, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+typedef void (* EGdbusCallStartStrv)	(GDBusProxy *proxy, const gchar * const *in_strv, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+typedef void (* EGdbusCallStartUint)	(GDBusProxy *proxy, guint in_uint, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+
+typedef gboolean (* EGdbusCallFinishVoid)	(GDBusProxy *proxy, GAsyncResult *result, GError **error);
+typedef gboolean (* EGdbusCallFinishBoolean)	(GDBusProxy *proxy, GAsyncResult *result, gboolean *out_boolean, GError **error);
+typedef gboolean (* EGdbusCallFinishString)	(GDBusProxy *proxy, GAsyncResult *result, gchar **out_string, GError **error);
+typedef gboolean (* EGdbusCallFinishStrv)	(GDBusProxy *proxy, GAsyncResult *result, gchar ***out_strv, GError **error);
+typedef gboolean (* EGdbusCallFinishUint)	(GDBusProxy *proxy, GAsyncResult *result, guint *out_uint, GError **error);
+
+/* this is for methods which are dividied into invocation and done signal */
+gboolean e_gdbus_proxy_call_sync_void__void	(GDBusProxy *proxy, GCancellable *cancellable, GError **error, EGdbusCallStartVoid start_func, EGdbusCallFinishVoid finish_func);
+gboolean e_gdbus_proxy_call_sync_void__boolean	(GDBusProxy *proxy, gboolean *out_boolean, GCancellable *cancellable, GError **error, EGdbusCallStartVoid start_func, EGdbusCallFinishBoolean finish_func);
+gboolean e_gdbus_proxy_call_sync_void__string	(GDBusProxy *proxy, gchar **out_string, GCancellable *cancellable, GError **error, EGdbusCallStartVoid start_func, EGdbusCallFinishString finish_func);
+gboolean e_gdbus_proxy_call_sync_void__strv	(GDBusProxy *proxy, gchar ***out_strv, GCancellable *cancellable, GError **error, EGdbusCallStartVoid start_func, EGdbusCallFinishStrv finish_func);
+gboolean e_gdbus_proxy_call_sync_void__uint	(GDBusProxy *proxy, guint *out_uint, GCancellable *cancellable, GError **error, EGdbusCallStartVoid start_func, EGdbusCallFinishUint finish_func);
+gboolean e_gdbus_proxy_call_sync_boolean__void	(GDBusProxy *proxy, gboolean in_boolean, GCancellable *cancellable, GError **error, EGdbusCallStartBoolean start_func, EGdbusCallFinishVoid finish_func);
+gboolean e_gdbus_proxy_call_sync_string__void	(GDBusProxy *proxy, const gchar *in_string, GCancellable *cancellable, GError **error, EGdbusCallStartString start_func, EGdbusCallFinishVoid finish_func);
+gboolean e_gdbus_proxy_call_sync_strv__void	(GDBusProxy *proxy, const gchar * const *in_strv, GCancellable *cancellable, GError **error, EGdbusCallStartStrv start_func, EGdbusCallFinishVoid finish_func);
+gboolean e_gdbus_proxy_call_sync_uint__void	(GDBusProxy *proxy, guint in_uint, GCancellable *cancellable, GError **error, EGdbusCallStartUint start_func, EGdbusCallFinishVoid finish_func);
+gboolean e_gdbus_proxy_call_sync_string__string	(GDBusProxy *proxy, const gchar *in_string, gchar **out_string, GCancellable *cancellable, GError **error, EGdbusCallStartString start_func, EGdbusCallFinishString finish_func);
+gboolean e_gdbus_proxy_call_sync_string__strv	(GDBusProxy *proxy, const gchar *in_string, gchar ***out_strv, GCancellable *cancellable, GError **error, EGdbusCallStartString start_func, EGdbusCallFinishStrv finish_func);
+gboolean e_gdbus_proxy_call_sync_strv__string	(GDBusProxy *proxy, const gchar * const *in_strv, gchar **out_string, GCancellable *cancellable, GError **error, EGdbusCallStartStrv start_func, EGdbusCallFinishString finish_func);
+gboolean e_gdbus_proxy_call_sync_strv__strv	(GDBusProxy *proxy, const gchar * const *in_strv, gchar ***out_strv, GCancellable *cancellable, GError **error, EGdbusCallStartStrv start_func, EGdbusCallFinishStrv finish_func);
+
+/* this is for "synchronous" methods, those without done signal */
+void	 e_gdbus_proxy_method_call_void			(const gchar *method_name, GDBusProxy *proxy, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+void	 e_gdbus_proxy_method_call_boolean		(const gchar *method_name, GDBusProxy *proxy, gboolean in_boolean, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+void	 e_gdbus_proxy_method_call_string		(const gchar *method_name, GDBusProxy *proxy, const gchar *in_string, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+void	 e_gdbus_proxy_method_call_strv			(const gchar *method_name, GDBusProxy *proxy, const gchar * const *in_strv, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+void	 e_gdbus_proxy_method_call_uint			(const gchar *method_name, GDBusProxy *proxy, guint in_uint, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data);
+
+gboolean e_gdbus_proxy_method_call_finish_void		(GDBusProxy *proxy, GAsyncResult *result, GError **error);
+gboolean e_gdbus_proxy_method_call_finish_boolean	(GDBusProxy *proxy, GAsyncResult *result, gboolean *out_boolean, GError **error);
+gboolean e_gdbus_proxy_method_call_finish_string	(GDBusProxy *proxy, GAsyncResult *result, gchar **out_string, GError **error);
+gboolean e_gdbus_proxy_method_call_finish_strv		(GDBusProxy *proxy, GAsyncResult *result, gchar ***out_strv, GError **error);
+gboolean e_gdbus_proxy_method_call_finish_uint		(GDBusProxy *proxy, GAsyncResult *result, guint *out_uint, GError **error);
+
+gboolean e_gdbus_proxy_method_call_sync_void__void	(const gchar *method_name, GDBusProxy *proxy, GCancellable *cancellable, GError **error);
+gboolean e_gdbus_proxy_method_call_sync_boolean__void	(const gchar *method_name, GDBusProxy *proxy, gboolean in_boolean, GCancellable *cancellable, GError **error);
+gboolean e_gdbus_proxy_method_call_sync_string__void	(const gchar *method_name, GDBusProxy *proxy, const gchar *in_string, GCancellable *cancellable, GError **error);
+gboolean e_gdbus_proxy_method_call_sync_strv__void	(const gchar *method_name, GDBusProxy *proxy, const gchar * const *in_strv, GCancellable *cancellable, GError **error);
+gboolean e_gdbus_proxy_method_call_sync_uint__void	(const gchar *method_name, GDBusProxy *proxy, guint in_uint, GCancellable *cancellable, GError **error);
+gboolean e_gdbus_proxy_method_call_sync_string__string	(const gchar *method_name, GDBusProxy *proxy, const gchar *in_string, gchar **out_string, GCancellable *cancellable, GError **error);
+gboolean e_gdbus_proxy_method_call_sync_strv__string	(const gchar *method_name, GDBusProxy *proxy, const gchar * const *in_strv, gchar **out_string, GCancellable *cancellable, GError **error);
+
+gchar ** e_gdbus_templates_encode_error	(const GError *in_error);
+gboolean e_gdbus_templates_decode_error	(const gchar * const *in_strv, GError **out_error);
+
+G_END_DECLS
+
+#endif /* E_GDBUS_TEMPLATES_H */
diff --git a/libedataserver/e-operation-pool.c b/libedataserver/e-operation-pool.c
new file mode 100644
index 0000000..edef4d6
--- /dev/null
+++ b/libedataserver/e-operation-pool.c
@@ -0,0 +1,136 @@
+/*
+ * e-operation-pool.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 2011 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#include <glib.h>
+
+#include "e-operation-pool.h"
+
+struct _EOperationPool {
+	GThreadPool *pool;
+
+	GMutex *ops_lock;
+	GHashTable *ops;
+	guint32 last_opid;
+};
+
+EOperationPool *
+e_operation_pool_new (guint max_threads, GFunc thread_func, gpointer user_data)
+{
+	EOperationPool *pool;
+	GThreadPool *thread_pool;
+	GError *error = NULL;
+
+	g_return_val_if_fail (thread_func != NULL, NULL);
+
+	thread_pool = g_thread_pool_new (thread_func, user_data, max_threads, FALSE, &error);
+	if (error) {
+		g_warning ("%s: Failed to create thread pool: %s", G_STRFUNC, error->message);
+		g_error_free (error);
+		return NULL;
+	}
+
+	pool = g_new0 (EOperationPool, 1);
+	pool->pool = thread_pool;
+	pool->ops_lock = g_mutex_new ();
+	pool->ops = g_hash_table_new (g_direct_hash, g_direct_equal);
+	pool->last_opid = 0;
+
+	/* Kill threads which don't do anything for 10 seconds */
+	g_thread_pool_set_max_idle_time (10 * 1000);
+
+	return pool;
+}
+
+void
+e_operation_pool_free (EOperationPool *pool)
+{
+	g_return_if_fail (pool != NULL);
+
+	g_thread_pool_free (pool->pool, FALSE, FALSE);
+	g_mutex_free (pool->ops_lock);
+	g_hash_table_destroy (pool->ops);
+	g_free (pool);
+}
+
+/* Reserves new operation ID, which is returned. This operation ID may
+   be released by e_operation_pool_release_opid() when the operation
+   is finished.
+*/
+guint32
+e_operation_pool_reserve_opid (EOperationPool *pool)
+{
+	guint32 opid;
+
+	g_return_val_if_fail (pool != NULL, 0);
+	g_return_val_if_fail (pool->ops != NULL, 0);
+	g_return_val_if_fail (pool->ops_lock != NULL, 0);
+
+	g_mutex_lock (pool->ops_lock);
+
+	pool->last_opid++;
+	if (!pool->last_opid)
+		pool->last_opid = 1;
+
+	while (pool->last_opid && g_hash_table_lookup (pool->ops, GUINT_TO_POINTER (pool->last_opid)))
+		pool->last_opid++;
+
+	opid = pool->last_opid;
+	if (opid)
+		g_hash_table_insert (pool->ops, GUINT_TO_POINTER (opid), GUINT_TO_POINTER (1));
+
+	g_mutex_unlock (pool->ops_lock);
+
+	g_return_val_if_fail (opid != 0, 0);
+
+	return opid;
+}
+
+/* Releases operation ID previously reserved by e_operation_pool_reserve_opid(). */
+void
+e_operation_pool_release_opid (EOperationPool *pool, guint32 opid)
+{
+	g_return_if_fail (pool != NULL);
+	g_return_if_fail (pool->ops != NULL);
+	g_return_if_fail (pool->ops_lock != NULL);
+
+	g_mutex_lock (pool->ops_lock);
+	g_hash_table_remove (pool->ops, GUINT_TO_POINTER (opid));
+	g_mutex_unlock (pool->ops_lock);
+}
+
+/* Pushes operation to be processed. 'opdata' is passed to the function
+   provided in e_operation_pool_new().
+*/
+void
+e_operation_pool_push (EOperationPool *pool, gpointer opdata)
+{
+	GError *error = NULL;
+
+	g_return_if_fail (pool != NULL);
+	g_return_if_fail (pool->pool != NULL);
+
+	g_thread_pool_push (pool->pool, opdata, &error);
+
+	if (error) {
+		g_warning ("%s: Failed to push to thread pool: %s", G_STRFUNC, error->message);
+		g_error_free (error);
+	}
+}
diff --git a/libedataserver/e-operation-pool.h b/libedataserver/e-operation-pool.h
new file mode 100644
index 0000000..f3f481c
--- /dev/null
+++ b/libedataserver/e-operation-pool.h
@@ -0,0 +1,36 @@
+/*
+ * e-operation-pool.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 2011 Novell, Inc. (www.novell.com)
+ *
+ */
+
+#ifndef E_OPERATION_POOL_H
+#define E_OPERATION_POOL_H
+
+#include <glib.h>
+#include <gio/gio.h>
+
+typedef struct _EOperationPool EOperationPool;
+
+EOperationPool *e_operation_pool_new (guint max_threads, GFunc thread_func, gpointer user_data);
+void		e_operation_pool_free (EOperationPool *pool);
+guint32		e_operation_pool_reserve_opid (EOperationPool *pool);
+void		e_operation_pool_release_opid (EOperationPool *pool, guint32 opid);
+void		e_operation_pool_push (EOperationPool *pool, gpointer data);
+
+#endif /* E_OPERATION_POOL_H */
diff --git a/libedataserverui/Makefile.am b/libedataserverui/Makefile.am
index af00b8a..478b790 100644
--- a/libedataserverui/Makefile.am
+++ b/libedataserverui/Makefile.am
@@ -7,11 +7,14 @@ CPPFLAGS = \
 	-I$(top_srcdir)				\
 	-I$(top_srcdir)/addressbook		\
 	-I$(top_builddir)/addressbook		\
+	-I$(top_srcdir)/calendar		\
+	-I$(top_builddir)/calendar		\
 	-DG_LOG_DOMAIN=\"e-data-server-ui\"	\
 	-DE_DATA_SERVER_UI_UIDIR=\""$(uidir)"\"	\
 	$(E_DATA_SERVER_UI_CFLAGS)		\
 	$(GNOME_KEYRING_CFLAGS)			\
-	$(CAMEL_CFLAGS)
+	$(CAMEL_CFLAGS)				\
+	$(SOUP_CFLAGS)
 
 lib_LTLIBRARIES = libedataserverui-3.0.la
 
@@ -23,6 +26,7 @@ libedataserveruiinclude_HEADERS =	\
 	e-category-editor.h		\
 	e-destination-store.h		\
 	e-book-auth-util.h		\
+	e-client-utils.h		\
 	e-contact-store.h		\
 	e-name-selector.h		\
 	e-name-selector-dialog.h	\
@@ -53,6 +57,7 @@ libedataserverui_3_0_la_SOURCES =	\
 	e-category-editor.c		\
 	e-destination-store.c		\
 	e-book-auth-util.c		\
+	e-client-utils.c		\
 	e-contact-store.c		\
 	e-name-selector.c		\
 	e-name-selector-dialog.c	\
@@ -70,11 +75,13 @@ libedataserverui_3_0_la_CPPFLAGS = $(CPPFLAGS)
 
 libedataserverui_3_0_la_LIBADD = 				\
 	$(top_builddir)/addressbook/libebook/libebook-1.2.la	\
+	$(top_builddir)/calendar/libecal/libecal-1.2.la		\
 	$(top_builddir)/libedataserver/libedataserver-1.2.la	\
 	$(top_builddir)/camel/libcamel-1.2.la			\
 	$(E_DATA_SERVER_UI_LIBS)				\
 	$(GNOME_KEYRING_LIBS)					\
-	$(CAMEL_LIBS)
+	$(CAMEL_LIBS)						\
+	$(SOUP_LIBS)
 
 libedataserverui_3_0_la_LDFLAGS = \
 	-version-info $(LIBEDATASERVERUI_CURRENT):$(LIBEDATASERVERUI_REVISION):$(LIBEDATASERVERUI_AGE) $(NO_UNDEFINED)
diff --git a/libedataserverui/e-client-utils.c b/libedataserverui/e-client-utils.c
new file mode 100644
index 0000000..032ee5e
--- /dev/null
+++ b/libedataserverui/e-client-utils.c
@@ -0,0 +1,773 @@
+/*
+ * e-client-utils.c
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 2011 Red Hat, Inc. (www.redhat.com)
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+#include <gtk/gtk.h>
+#include <libsoup/soup.h>
+
+#include <libedataserver/e-client.h>
+#include "libedataserver/e-client-private.h"
+#include <libebook/e-book-client.h>
+#include <libecal/e-cal-client.h>
+
+#include "e-passwords.h"
+#include "e-client-utils.h"
+
+/**
+ * e_client_utils_new:
+ *
+ * Proxy function for e_book_client_utils_new() and e_cal_client_utils_new().
+ **/
+EClient	*
+e_client_utils_new (ESource *source, EClientSourceType source_type, GError **error)
+{
+	EClient *res = NULL;
+
+	g_return_val_if_fail (source != NULL, NULL);
+	g_return_val_if_fail (E_IS_SOURCE (source), NULL);
+
+	switch (source_type) {
+	case E_CLIENT_SOURCE_TYPE_CONTACTS:
+		res = E_CLIENT (e_book_client_new (source, error));
+		break;
+	case E_CLIENT_SOURCE_TYPE_EVENTS:
+		res = E_CLIENT (e_cal_client_new (source, E_CAL_CLIENT_SOURCE_TYPE_EVENTS, error));
+		break;
+	case E_CLIENT_SOURCE_TYPE_MEMOS:
+		res = E_CLIENT (e_cal_client_new (source, E_CAL_CLIENT_SOURCE_TYPE_MEMOS, error));
+		break;
+	case E_CLIENT_SOURCE_TYPE_TASKS:
+		res = E_CLIENT (e_cal_client_new (source, E_CAL_CLIENT_SOURCE_TYPE_TASKS, error));
+		break;
+	default:
+		g_return_val_if_reached (NULL);
+		break;
+	}
+
+	return res;
+}
+
+/**
+ * e_client_utils_new_from_uri:
+ *
+ * Proxy function for e_book_client_utils_new_from_uri() and e_cal_client_utils_new_from_uri().
+ **/
+EClient *
+e_client_utils_new_from_uri (const gchar *uri, EClientSourceType source_type, GError **error)
+{
+	EClient *res = NULL;
+
+	g_return_val_if_fail (uri != NULL, NULL);
+
+	switch (source_type) {
+	case E_CLIENT_SOURCE_TYPE_CONTACTS:
+		res = E_CLIENT (e_book_client_new_from_uri (uri, error));
+		break;
+	case E_CLIENT_SOURCE_TYPE_EVENTS:
+		res = E_CLIENT (e_cal_client_new_from_uri (uri, E_CAL_CLIENT_SOURCE_TYPE_EVENTS, error));
+		break;
+	case E_CLIENT_SOURCE_TYPE_MEMOS:
+		res = E_CLIENT (e_cal_client_new_from_uri (uri, E_CAL_CLIENT_SOURCE_TYPE_MEMOS, error));
+		break;
+	case E_CLIENT_SOURCE_TYPE_TASKS:
+		res = E_CLIENT (e_cal_client_new_from_uri (uri, E_CAL_CLIENT_SOURCE_TYPE_TASKS, error));
+		break;
+	default:
+		g_return_val_if_reached (NULL);
+		break;
+	}
+
+	return res;
+}
+
+/**
+ * e_client_utils_new_system:
+ *
+ * Proxy function for e_book_client_utils_new_system() and e_cal_client_utils_new_system().
+ **/
+EClient *
+e_client_utils_new_system (EClientSourceType source_type, GError **error)
+{
+	EClient *res = NULL;
+
+	switch (source_type) {
+	case E_CLIENT_SOURCE_TYPE_CONTACTS:
+		res = E_CLIENT (e_book_client_new_system (error));
+		break;
+	case E_CLIENT_SOURCE_TYPE_EVENTS:
+		res = E_CLIENT (e_cal_client_new_system (E_CAL_CLIENT_SOURCE_TYPE_EVENTS, error));
+		break;
+	case E_CLIENT_SOURCE_TYPE_MEMOS:
+		res = E_CLIENT (e_cal_client_new_system (E_CAL_CLIENT_SOURCE_TYPE_MEMOS, error));
+		break;
+	case E_CLIENT_SOURCE_TYPE_TASKS:
+		res = E_CLIENT (e_cal_client_new_system (E_CAL_CLIENT_SOURCE_TYPE_TASKS, error));
+		break;
+	default:
+		g_return_val_if_reached (NULL);
+		break;
+	}
+
+	return res;
+}
+
+/**
+ * e_client_utils_new_default:
+ *
+ * Proxy function for e_book_client_utils_new_default() and e_cal_client_utils_new_default().
+ **/
+EClient *
+e_client_utils_new_default (EClientSourceType source_type, GError **error)
+{
+	EClient *res = NULL;
+
+	switch (source_type) {
+	case E_CLIENT_SOURCE_TYPE_CONTACTS:
+		res = E_CLIENT (e_book_client_new_default (error));
+		break;
+	case E_CLIENT_SOURCE_TYPE_EVENTS:
+		res = E_CLIENT (e_cal_client_new_default (E_CAL_CLIENT_SOURCE_TYPE_EVENTS, error));
+		break;
+	case E_CLIENT_SOURCE_TYPE_MEMOS:
+		res = E_CLIENT (e_cal_client_new_default (E_CAL_CLIENT_SOURCE_TYPE_MEMOS, error));
+		break;
+	case E_CLIENT_SOURCE_TYPE_TASKS:
+		res = E_CLIENT (e_cal_client_new_default (E_CAL_CLIENT_SOURCE_TYPE_TASKS, error));
+		break;
+	default:
+		g_return_val_if_reached (NULL);
+		break;
+	}
+
+	return res;
+}
+
+/**
+ * e_client_utils_set_default:
+ *
+ * Proxy function for e_book_client_utils_set_default() and e_book_client_utils_set_default().
+ **/
+gboolean
+e_client_utils_set_default (EClient *client, EClientSourceType source_type, GError **error)
+{
+	gboolean res = FALSE;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
+
+	switch (source_type) {
+	case E_CLIENT_SOURCE_TYPE_CONTACTS:
+		g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
+		res = e_book_client_set_default (E_BOOK_CLIENT (client), error);
+		break;
+	case E_CLIENT_SOURCE_TYPE_EVENTS:
+	case E_CLIENT_SOURCE_TYPE_MEMOS:
+	case E_CLIENT_SOURCE_TYPE_TASKS:
+		g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+		res = e_cal_client_set_default (E_CAL_CLIENT (client), error);
+		break;
+	default:
+		g_return_val_if_reached (FALSE);
+		break;
+	}
+
+	return res;
+}
+
+/**
+ * e_client_utils_set_default_source:
+ *
+ * Proxy function for e_book_client_utils_set_default_source() and e_cal_client_utils_set_default_source().
+ **/
+gboolean
+e_client_utils_set_default_source (ESource *source, EClientSourceType source_type, GError **error)
+{
+	gboolean res = FALSE;
+
+	g_return_val_if_fail (source != NULL, FALSE);
+	g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+
+	switch (source_type) {
+	case E_CLIENT_SOURCE_TYPE_CONTACTS:
+		res = e_book_client_set_default_source (source, error);
+		break;
+	case E_CLIENT_SOURCE_TYPE_EVENTS:
+		res = e_cal_client_set_default_source (source, E_CAL_CLIENT_SOURCE_TYPE_EVENTS, error);
+		break;
+	case E_CLIENT_SOURCE_TYPE_MEMOS:
+		res = e_cal_client_set_default_source (source, E_CAL_CLIENT_SOURCE_TYPE_MEMOS, error);
+		break;
+	case E_CLIENT_SOURCE_TYPE_TASKS:
+		res = e_cal_client_set_default_source (source, E_CAL_CLIENT_SOURCE_TYPE_TASKS, error);
+		break;
+	default:
+		g_return_val_if_reached (FALSE);
+		break;
+	}
+
+	return res;
+}
+
+/**
+ * e_client_utils_get_sources:
+ *
+ * Proxy function for e_book_client_utils_get_sources() and e_cal_client_utils_get_sources().
+ **/
+gboolean
+e_client_utils_get_sources (ESourceList **sources, EClientSourceType source_type, GError **error)
+{
+	gboolean res = FALSE;
+
+	g_return_val_if_fail (sources != NULL, FALSE);
+
+	switch (source_type) {
+	case E_CLIENT_SOURCE_TYPE_CONTACTS:
+		res = e_book_client_get_sources (sources, error);
+		break;
+	case E_CLIENT_SOURCE_TYPE_EVENTS:
+		res = e_cal_client_get_sources (sources, E_CAL_CLIENT_SOURCE_TYPE_EVENTS, error);
+		break;
+	case E_CLIENT_SOURCE_TYPE_MEMOS:
+		res = e_cal_client_get_sources (sources, E_CAL_CLIENT_SOURCE_TYPE_MEMOS, error);
+		break;
+	case E_CLIENT_SOURCE_TYPE_TASKS:
+		res = e_cal_client_get_sources (sources, E_CAL_CLIENT_SOURCE_TYPE_TASKS, error);
+		break;
+	default:
+		g_return_val_if_reached (FALSE);
+		break;
+	}
+
+	return res;
+}
+
+typedef struct _EClientUtilsAsyncOpData
+{
+	EClientUtilsAuthenticateHandler auth_handler;
+	gpointer auth_handler_user_data;
+	GAsyncReadyCallback async_cb;
+	gpointer async_cb_user_data;
+	GCancellable *cancellable;
+	EClient *client;
+	ECredentials *used_credentials;
+	gboolean open_finished;
+	GError *opened_cb_error;
+} EClientUtilsAsyncOpData;
+
+static void
+free_client_utils_async_op_data (EClientUtilsAsyncOpData *async_data)
+{
+	g_return_if_fail (async_data != NULL);
+	g_return_if_fail (async_data->cancellable != NULL);
+	g_return_if_fail (async_data->client != NULL);
+
+	g_signal_handlers_disconnect_matched (async_data->cancellable, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, async_data);
+	g_signal_handlers_disconnect_matched (async_data->client, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, async_data);
+
+	if (async_data->used_credentials)
+		e_credentials_free (async_data->used_credentials);
+	if (async_data->opened_cb_error)
+		g_error_free (async_data->opened_cb_error);
+	g_object_unref (async_data->cancellable);
+	g_object_unref (async_data->client);
+	g_free (async_data);
+}
+
+static gboolean
+complete_async_op_in_idle_cb (gpointer user_data)
+{
+	GSimpleAsyncResult *simple = user_data;
+	gint run_main_depth;
+
+	g_return_val_if_fail (simple != NULL, FALSE);
+
+	run_main_depth = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (simple), "run-main-depth"));
+	if (run_main_depth < 1)
+		run_main_depth = 1;
+
+	/* do not receive in higher level than was initially run */
+	if (g_main_depth () > run_main_depth) {
+		return TRUE;
+	}
+
+	g_simple_async_result_complete (simple);
+	g_object_unref (simple);
+
+	return FALSE;
+}
+
+#define return_async_error_if_fail(expr, async_cb, async_cb_user_data, source_tag) G_STMT_START {	\
+	if (G_LIKELY ((expr))) { } else {								\
+		GError *error;										\
+													\
+		error = g_error_new (E_CLIENT_ERROR, E_CLIENT_ERROR_INVALID_ARG,			\
+				"%s: assertion '%s' failed", G_STRFUNC, #expr);				\
+													\
+		return_async_error (error, async_cb, async_cb_user_data, source_tag);			\
+		g_error_free (error);									\
+		return;											\
+	}												\
+	} G_STMT_END
+
+static void
+return_async_error (const GError *error, GAsyncReadyCallback async_cb, gpointer async_cb_user_data, gpointer source_tag)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_if_fail (error != NULL);
+	g_return_if_fail (source_tag != NULL);
+
+	simple = g_simple_async_result_new (NULL, async_cb, async_cb_user_data, source_tag);
+	g_simple_async_result_set_from_error (simple, error);
+
+	g_object_set_data (G_OBJECT (simple), "run-main-depth", GINT_TO_POINTER (g_main_depth ()));
+	g_idle_add (complete_async_op_in_idle_cb, simple);
+}
+
+static void
+client_utils_open_new_done (EClientUtilsAsyncOpData *async_data)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_if_fail (async_data != NULL);
+	g_return_if_fail (async_data->client != NULL);
+
+	/* keep the initial auth_handler connected directly, thus it will be able
+	   to answer any later authentication requests, for reconnection, for example
+	*/
+	if (async_data->auth_handler)
+		g_signal_connect (async_data->client, "authenticate", G_CALLBACK (async_data->auth_handler), async_data->auth_handler_user_data);
+
+	simple = g_simple_async_result_new (NULL, async_data->async_cb, async_data->async_cb_user_data, e_client_utils_open_new);
+	g_simple_async_result_set_op_res_gpointer (simple, g_object_ref (async_data->client), g_object_unref);
+
+	g_object_set_data (G_OBJECT (simple), "run-main-depth", GINT_TO_POINTER (g_main_depth ()));
+	g_idle_add (complete_async_op_in_idle_cb, simple);
+
+	free_client_utils_async_op_data (async_data);
+}
+
+static void
+client_utils_open_new_cancelled_cb (GCancellable *cancellable, EClientUtilsAsyncOpData *async_data)
+{
+	GError *error = NULL;
+
+	g_return_if_fail (cancellable != NULL);
+	g_return_if_fail (async_data != NULL);
+	g_return_if_fail (async_data->cancellable == cancellable);
+	g_return_if_fail (g_cancellable_set_error_if_cancelled (cancellable, &error));
+
+	return_async_error (error, async_data->async_cb, async_data->async_cb_user_data, e_client_utils_open_new);
+	free_client_utils_async_op_data (async_data);
+	g_error_free (error);
+}
+
+static void
+finish_or_retry_open (EClientUtilsAsyncOpData *async_data, const GError *error)
+{
+	g_return_if_fail (async_data != NULL);
+
+	if (async_data->auth_handler && error && g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_AUTHENTICATION_FAILED)) {
+		if (async_data->used_credentials) {
+			const gchar *auth_domain, *prompt_key;
+
+			auth_domain = e_credentials_peek (async_data->used_credentials, E_CREDENTIALS_KEY_AUTH_DOMAIN);
+			prompt_key = e_credentials_peek (async_data->used_credentials, E_CREDENTIALS_KEY_PROMPT_KEY);
+
+			/* make sure the old password is forgotten when authentication failed */
+			if (auth_domain && prompt_key)
+				e_passwords_forget_password (auth_domain, prompt_key);
+
+			e_credentials_set (async_data->used_credentials, E_CREDENTIALS_KEY_PROMPT_REASON, error->message);
+		}
+
+		e_client_process_authentication (async_data->client, async_data->used_credentials);
+	} else if (error) {
+		return_async_error (error, async_data->async_cb, async_data->async_cb_user_data, e_client_utils_open_new);
+		free_client_utils_async_op_data (async_data);
+	} else {
+		client_utils_open_new_done (async_data);
+	}
+}
+
+static void
+client_utils_opened_cb (EClient *client, const GError *error, EClientUtilsAsyncOpData *async_data)
+{
+	g_return_if_fail (client != NULL);
+	g_return_if_fail (async_data != NULL);
+	g_return_if_fail (client == async_data->client);
+
+	if (!async_data->open_finished) {
+		/* there can happen that the "opened" signal is received
+		   before the e_client_open() is finished, thus keep detailed
+		   error for later use, if any */
+		if (error)
+			async_data->opened_cb_error = g_error_copy (error);
+	} else {
+		finish_or_retry_open (async_data, error);
+	}
+}
+
+static void
+client_utils_open_new_async_cb (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	EClientUtilsAsyncOpData *async_data = user_data;
+	GError *error = NULL;
+
+	g_return_if_fail (source_object != NULL);
+	g_return_if_fail (result != NULL);
+	g_return_if_fail (async_data != NULL);
+	g_return_if_fail (async_data->async_cb != NULL);
+	g_return_if_fail (async_data->client == E_CLIENT (source_object));
+
+	async_data->open_finished = TRUE;
+
+	if (!e_client_open_finish (E_CLIENT (source_object), result, &error)
+	    || g_cancellable_set_error_if_cancelled (async_data->cancellable, &error)) {
+		finish_or_retry_open (async_data, error);
+		g_error_free (error);
+		return;
+	}
+
+	if (async_data->opened_cb_error) {
+		finish_or_retry_open (async_data, async_data->opened_cb_error);
+		return;
+	}
+
+	if (e_client_is_opened (async_data->client)) {
+		client_utils_open_new_done (async_data);
+		return;
+	}
+
+	/* wait for 'opened' signal, which is received in client_utils_opened_cb */
+	g_signal_connect (async_data->cancellable, "cancelled", G_CALLBACK (client_utils_open_new_cancelled_cb), async_data);
+}
+
+static gboolean
+client_utils_open_new_auth_cb (EClient *client, ECredentials *credentials, gpointer user_data)
+{
+	EClientUtilsAsyncOpData *async_data = user_data;
+	gboolean handled;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (async_data != NULL, FALSE);
+	g_return_val_if_fail (async_data->auth_handler != NULL, FALSE);
+
+	if (async_data->used_credentials) {
+		const gchar *reason = e_credentials_peek (async_data->used_credentials, E_CREDENTIALS_KEY_PROMPT_REASON);
+
+		if (reason) {
+			e_credentials_set (credentials, E_CREDENTIALS_KEY_PROMPT_TEXT, NULL);
+			e_credentials_set (credentials, E_CREDENTIALS_KEY_PROMPT_REASON, reason);
+		}
+	}
+
+	handled = async_data->auth_handler (client, credentials, async_data->auth_handler_user_data);
+
+	if (handled && credentials) {
+		if (async_data->used_credentials) {
+			gchar *prompt_flags_str;
+			guint prompt_flags = 0;
+
+			e_credentials_free (async_data->used_credentials);
+
+			prompt_flags_str = e_credentials_get (credentials, E_CREDENTIALS_KEY_PROMPT_FLAGS);
+			if (prompt_flags_str) {
+				prompt_flags = e_credentials_util_string_to_prompt_flags (prompt_flags_str);
+				g_free (prompt_flags_str);
+			} else {
+				prompt_flags = E_CREDENTIALS_PROMPT_FLAG_REMEMBER_FOREVER
+					     | E_CREDENTIALS_PROMPT_FLAG_SECRET
+					     | E_CREDENTIALS_PROMPT_FLAG_ONLINE;
+			}
+
+			prompt_flags |= E_CREDENTIALS_PROMPT_FLAG_REPROMPT;
+
+			prompt_flags_str = e_credentials_util_prompt_flags_to_string (prompt_flags);
+			e_credentials_set (credentials, E_CREDENTIALS_KEY_PROMPT_FLAGS, prompt_flags_str);
+			g_free (prompt_flags_str);
+		}
+
+		async_data->used_credentials = e_credentials_new_clone (credentials);
+	}
+
+	return handled;
+}
+
+/**
+ * e_client_utils_open_new:
+ * @source: an #ESource to be opened
+ * @source_type: an #EClientSourceType of the @source
+ * @only_if_exists: if %TRUE, fail if this client doesn't already exist, otherwise create it first
+ * @auth_handler: authentication handler, to be used; the e_client_utils_authenticate_handler() is usually sufficient
+ * @auth_handler_user_data: user data for @auth_handler function
+ * @cancellable: a #GCancellable; can be %NULL
+ * @async_cb: callback to call when a result is ready
+ * @async_cb_user_data: user data for the @async_cb
+ *
+ * Begins asynchronous opening of a new #EClient corresponding
+ * to the @source of type @source_type. The resulting #EClient
+ * is fully opened and authenticated client, ready to be used.
+ * This call is finished by e_client_utils_open_new_finish()
+ * from the @async_cb.
+ *
+ * Note: the @auth_handler, and its @auth_handler_user_data,
+ * should be valid through whole live of returned #EClient.
+ *
+ * Since: 3.2
+ **/
+void
+e_client_utils_open_new (ESource *source, EClientSourceType source_type, gboolean only_if_exists,
+			 EClientUtilsAuthenticateHandler auth_handler, gpointer auth_handler_user_data,
+			 GCancellable *cancellable, GAsyncReadyCallback async_cb, gpointer async_cb_user_data)
+{
+	EClient *client;
+	GError *error = NULL;
+	EClientUtilsAsyncOpData *async_data;
+
+	g_return_if_fail (async_cb != NULL);
+	return_async_error_if_fail (source != NULL, async_cb, async_cb_user_data, e_client_utils_open_new);
+	return_async_error_if_fail (E_IS_SOURCE (source), async_cb, async_cb_user_data, e_client_utils_open_new);
+
+	client = e_client_utils_new (source, source_type, &error);
+	if (!client) {
+		return_async_error (error, async_cb, async_cb_user_data, e_client_utils_open_new);
+		g_error_free (error);
+		return;
+	}
+
+	async_data = g_new0 (EClientUtilsAsyncOpData, 1);
+	async_data->auth_handler = auth_handler;
+	async_data->auth_handler_user_data = auth_handler_user_data;
+	async_data->async_cb = async_cb;
+	async_data->async_cb_user_data = async_cb_user_data;
+	async_data->client = client;
+	async_data->open_finished = FALSE;
+	if (cancellable)
+		async_data->cancellable = g_object_ref (cancellable);
+	else
+		async_data->cancellable = g_cancellable_new ();
+
+	if (auth_handler)
+		g_signal_connect (client, "authenticate", G_CALLBACK (client_utils_open_new_auth_cb), async_data);
+
+
+	/* wait till backend notifies about its opened state */
+	g_signal_connect (client, "opened", G_CALLBACK (client_utils_opened_cb), async_data);
+
+	e_client_open (client, only_if_exists, async_data->cancellable, client_utils_open_new_async_cb, async_data);
+}
+
+/**
+ * e_client_utils_open_new_finish:
+ * @result: a #GAsyncResult
+ * @client: (out): Return value for an #EClient.
+ * @error: (out): a #GError to set an error, if any
+ *
+ * Finishes previous call of e_client_utils_open_new() and
+ * sets @client to a fully opened and authenticated #EClient.
+ * This @client, if not NULL, should be freed with g_object_unref().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.2
+ **/
+gboolean
+e_client_utils_open_new_finish (GAsyncResult *result, EClient **client, GError **error)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (result != NULL, FALSE);
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL, e_client_utils_open_new), FALSE);
+
+	*client = NULL;
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	if (g_simple_async_result_propagate_error (simple, error))
+		return FALSE;
+
+	*client = g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
+
+	return *client != NULL;
+}
+
+/* This function is suitable as a handler for EClient::authenticate signal.
+   It takes care of all the password prompt and such and returns TRUE if
+   credentials (password) were provided. Thus just connect it to that signal
+   and it'll take care of everything else.
+*/
+gboolean
+e_client_utils_authenticate_handler (EClient *client, ECredentials *credentials, gpointer unused_user_data)
+{
+	ESource *source;
+	gboolean is_book, is_cal, res, remember_password = FALSE;
+
+	g_return_val_if_fail (client != NULL, FALSE);
+	g_return_val_if_fail (credentials != NULL, FALSE);
+
+	is_book = E_IS_BOOK_CLIENT (client);
+	is_cal = !is_book && E_IS_CAL_CLIENT (client);
+	g_return_val_if_fail (is_book || is_cal, FALSE);
+
+	source = e_client_get_source (client);
+	g_return_val_if_fail (source != NULL, FALSE);
+
+	if (!e_credentials_has_key (credentials, E_CREDENTIALS_KEY_USERNAME)) {
+		e_credentials_set (credentials, E_CREDENTIALS_KEY_USERNAME, e_source_get_property (source, "username"));
+
+		/* no username set on the source - deny authentication request until
+		   username will be also enterable with e-passwords */
+		if (!e_credentials_has_key (credentials, E_CREDENTIALS_KEY_USERNAME))
+			return FALSE;
+	}
+
+	if (!e_credentials_has_key (credentials, E_CREDENTIALS_KEY_AUTH_DOMAIN))
+		e_credentials_set (credentials, E_CREDENTIALS_KEY_AUTH_DOMAIN, is_book ? E_CREDENTIALS_AUTH_DOMAIN_ADDRESSBOOK : E_CREDENTIALS_AUTH_DOMAIN_CALENDAR);
+
+	if (!e_credentials_has_key (credentials, E_CREDENTIALS_KEY_PROMPT_TEXT)) {
+		gchar *prompt, *reason;
+		gchar *username_markup, *source_name_markup;
+
+		reason = e_credentials_get (credentials, E_CREDENTIALS_KEY_PROMPT_REASON);
+		username_markup = g_markup_printf_escaped ("<b>%s</b>", e_credentials_peek (credentials, E_CREDENTIALS_KEY_USERNAME));
+		source_name_markup = g_markup_printf_escaped ("<b>%s</b>", e_source_peek_name (source));
+
+
+		if (reason && *reason)
+			prompt = g_strdup_printf (_("Enter password for %s (user %s)\nReason: %s"), source_name_markup, username_markup, reason);
+		else
+			prompt = g_strdup_printf (_("Enter password for %s (user %s)"), source_name_markup, username_markup);
+
+		e_credentials_set (credentials, E_CREDENTIALS_KEY_PROMPT_TEXT, prompt);
+
+		g_free (username_markup);
+		g_free (source_name_markup);
+		g_free (reason);
+		g_free (prompt);
+	}
+
+	if (!e_credentials_has_key (credentials, E_CREDENTIALS_KEY_PROMPT_KEY)) {
+		SoupURI *suri;
+		gchar *uri_str;
+
+		suri = soup_uri_new (e_client_get_uri (client));
+		g_return_val_if_fail (suri != NULL, FALSE);
+
+		soup_uri_set_user (suri, e_credentials_peek (credentials, E_CREDENTIALS_KEY_USERNAME));
+		soup_uri_set_password (suri, NULL);
+		soup_uri_set_fragment (suri, NULL);
+
+		uri_str = soup_uri_to_string (suri, FALSE);
+
+		e_credentials_set (credentials, E_CREDENTIALS_KEY_PROMPT_KEY, uri_str);
+
+		g_free (uri_str);
+		soup_uri_free (suri);
+	}
+
+	remember_password = g_strcmp0 (e_source_get_property (source, "remember_password"), "true") == 0;
+
+	res = e_credentials_authenticate_helper (credentials, NULL, &remember_password);
+
+	if (res)
+		e_source_set_property (source, "remember_password", remember_password ? "true" : NULL);
+
+	e_credentials_clear_peek (credentials);
+
+	return res;
+}
+
+/* Asks for a password based on the provided credentials information.
+   Credentials should have set following keys:
+      E_CREDENTIALS_KEY_USERNAME
+      E_CREDENTIALS_KEY_AUTH_DOMAIN
+      E_CREDENTIALS_KEY_PROMPT_TEXT
+      E_CREDENTIALS_KEY_PROMPT_KEY
+   all other keys are optional. If also E_CREDENTIALS_KEY_PASSWORD key is provided,
+   then it implies a reprompt.
+
+   When this returns TRUE, then the structure contains E_CREDENTIALS_KEY_PASSWORD set
+   as entered by a user.
+*/
+gboolean
+e_credentials_authenticate_helper (ECredentials *credentials, GtkWindow *parent, gboolean *remember_password)
+{
+	gboolean res, fake_remember_password = FALSE;
+	guint prompt_flags;
+	gchar *password = NULL;
+	const gchar *title, *auth_domain, *prompt_key;
+
+	g_return_val_if_fail (credentials != NULL, FALSE);
+	g_return_val_if_fail (e_credentials_has_key (credentials, E_CREDENTIALS_KEY_USERNAME), FALSE);
+	g_return_val_if_fail (e_credentials_has_key (credentials, E_CREDENTIALS_KEY_AUTH_DOMAIN), FALSE);
+	g_return_val_if_fail (e_credentials_has_key (credentials, E_CREDENTIALS_KEY_PROMPT_TEXT), FALSE);
+	g_return_val_if_fail (e_credentials_has_key (credentials, E_CREDENTIALS_KEY_PROMPT_KEY), FALSE);
+
+	if (e_credentials_has_key (credentials, E_CREDENTIALS_KEY_PROMPT_FLAGS)) {
+		prompt_flags = e_credentials_util_string_to_prompt_flags (e_credentials_peek (credentials, E_CREDENTIALS_KEY_PROMPT_FLAGS));
+	} else {
+		prompt_flags = E_CREDENTIALS_PROMPT_FLAG_REMEMBER_FOREVER
+			     | E_CREDENTIALS_PROMPT_FLAG_SECRET
+			     | E_CREDENTIALS_PROMPT_FLAG_ONLINE;
+	}
+
+	if (!remember_password) {
+		prompt_flags |= E_CREDENTIALS_PROMPT_FLAG_DISABLE_REMEMBER;
+		remember_password = &fake_remember_password;
+	}
+
+	if (e_credentials_has_key (credentials, E_CREDENTIALS_KEY_PASSWORD))
+		prompt_flags |= E_CREDENTIALS_PROMPT_FLAG_REPROMPT;
+
+	if (e_credentials_has_key (credentials, E_CREDENTIALS_KEY_PROMPT_TITLE))
+		title = e_credentials_peek (credentials, E_CREDENTIALS_KEY_PROMPT_TITLE);
+	else if (prompt_flags & E_CREDENTIALS_PROMPT_FLAG_PASSPHRASE)
+		title = _("Enter Passphrase");
+	else
+		title = _("Enter Password");
+
+	auth_domain = e_credentials_peek (credentials, E_CREDENTIALS_KEY_AUTH_DOMAIN);
+	prompt_key = e_credentials_peek (credentials, E_CREDENTIALS_KEY_PROMPT_KEY);
+
+	if (!(prompt_flags & E_CREDENTIALS_PROMPT_FLAG_REPROMPT))
+		password = e_passwords_get_password (auth_domain, prompt_key);
+
+	if (!password)
+		password = e_passwords_ask_password (title, auth_domain, prompt_key,
+				e_credentials_peek (credentials, E_CREDENTIALS_KEY_PROMPT_TEXT),
+				prompt_flags, remember_password, parent);
+
+	res = password != NULL;
+
+	if (res)
+		e_credentials_set (credentials, E_CREDENTIALS_KEY_PASSWORD, password);
+
+	e_credentials_util_safe_free_string (password);
+	e_credentials_clear_peek (credentials);
+
+	return res;
+}
diff --git a/libedataserverui/e-client-utils.h b/libedataserverui/e-client-utils.h
new file mode 100644
index 0000000..b6a189f
--- /dev/null
+++ b/libedataserverui/e-client-utils.h
@@ -0,0 +1,61 @@
+/*
+ * e-client-utils.h
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) version 3.
+ *
+ * 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with the program; if not, see <http://www.gnu.org/licenses/>
+ *
+ *
+ * Copyright (C) 2011 Red Hat, Inc. (www.redhat.com)
+ *
+ */
+
+#ifndef E_CLIENT_UTILS_H
+#define E_CLIENT_UTILS_H
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
+#include <libedataserver/e-client.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+	E_CLIENT_SOURCE_TYPE_CONTACTS,
+	E_CLIENT_SOURCE_TYPE_EVENTS,
+	E_CLIENT_SOURCE_TYPE_MEMOS,
+	E_CLIENT_SOURCE_TYPE_TASKS,
+	E_CLIENT_SOURCE_TYPE_LAST
+} EClientSourceType;
+
+typedef gboolean (* EClientUtilsAuthenticateHandler) (EClient *client, ECredentials *credentials, gpointer user_data);
+
+EClient	*	e_client_utils_new			(ESource *source, EClientSourceType source_type, GError **error);
+EClient *	e_client_utils_new_from_uri		(const gchar *uri, EClientSourceType source_type, GError **error);
+EClient *	e_client_utils_new_system		(EClientSourceType source_type, GError **error);
+EClient *	e_client_utils_new_default		(EClientSourceType source_type, GError **error);
+
+gboolean	e_client_utils_set_default		(EClient *client, EClientSourceType source_type, GError **error);
+gboolean	e_client_utils_set_default_source	(ESource *source, EClientSourceType source_type, GError **error);
+gboolean	e_client_utils_get_sources		(ESourceList **sources, EClientSourceType source_type, GError **error);
+
+void		e_client_utils_open_new			(ESource *source, EClientSourceType source_type, gboolean only_if_exists,
+							 EClientUtilsAuthenticateHandler auth_handler, gpointer auth_handler_user_data,
+							 GCancellable *cancellable, GAsyncReadyCallback async_cb, gpointer async_cb_user_data);
+gboolean	e_client_utils_open_new_finish		(GAsyncResult *result, EClient **client, GError **error);
+
+gboolean	e_client_utils_authenticate_handler	(EClient *client, ECredentials *credentials, gpointer unused_user_data);
+gboolean	e_credentials_authenticate_helper	(ECredentials *credentials, GtkWindow *parent, gboolean *remember_password);
+
+G_END_DECLS
+
+#endif /* E_CLIENT_UTILS_H */
diff --git a/po/POTFILES.in b/po/POTFILES.in
index e1e39a0..e96df5b 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -8,8 +8,11 @@ addressbook/backends/ldap/e-book-backend-ldap.c
 addressbook/backends/vcf/e-book-backend-vcf.c
 addressbook/backends/webdav/e-book-backend-webdav.c
 addressbook/libebook/e-book.c
+addressbook/libebook/e-book-client.c
+addressbook/libebook/e-book-client-view.c
 addressbook/libebook/e-contact.c
 addressbook/libebook/e-destination.c
+addressbook/libedata-book/e-book-backend.c
 addressbook/libedata-book/e-data-book-factory.c
 addressbook/libedata-book/e-data-book.c
 calendar/backends/caldav/e-cal-backend-caldav.c
@@ -19,12 +22,15 @@ calendar/backends/groupwise/e-cal-backend-groupwise-utils.c
 calendar/backends/groupwise/e-cal-backend-groupwise.c
 calendar/backends/http/e-cal-backend-http.c
 calendar/backends/weather/e-cal-backend-weather.c
+calendar/libecal/e-cal-client.c
+calendar/libecal/e-cal-client-view.c
 calendar/libecal/e-cal-component.c
 calendar/libecal/e-cal-recur.c
 calendar/libecal/e-cal-util.c
 calendar/libecal/e-cal.c
 calendar/libedata-cal/e-cal-backend-sexp.c
 calendar/libedata-cal/e-cal-backend-util.c
+calendar/libedata-cal/e-cal-backend.c
 calendar/libedata-cal/e-data-cal.c
 calendar/libedata-cal/e-data-cal-factory.c
 camel/camel-address.c
@@ -184,11 +190,13 @@ camel/providers/sendmail/camel-sendmail-transport.c
 camel/providers/smtp/camel-smtp-provider.c
 camel/providers/smtp/camel-smtp-transport.c
 libedataserver/e-categories.c
+libedataserver/e-client.c
 libedataserver/e-time-utils.c
 libedataserverui/e-book-auth-util.c
 libedataserverui/e-categories-dialog.c
 libedataserverui/e-category-completion.c
 libedataserverui/e-cell-renderer-color.c
+libedataserverui/e-client-utils.c
 libedataserverui/e-name-selector-dialog.c
 libedataserverui/e-name-selector-entry.c
 libedataserverui/e-name-selector-list.c
diff --git a/tests/libebook/Makefile.am b/tests/libebook/Makefile.am
index 90a1e60..ac23d45 100644
--- a/tests/libebook/Makefile.am
+++ b/tests/libebook/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = vcard
+SUBDIRS = vcard client
 
 noinst_LTLIBRARIES = libebook-test-utils.la
 libebook_test_utils_la_SOURCES = ebook-test-utils.c ebook-test-utils.h
diff --git a/tests/libebook/client/Makefile.am b/tests/libebook/client/Makefile.am
new file mode 100644
index 0000000..9f1b832
--- /dev/null
+++ b/tests/libebook/client/Makefile.am
@@ -0,0 +1,98 @@
+noinst_LTLIBRARIES = libclient-test-utils.la
+
+libclient_test_utils_la_SOURCES = client-test-utils.c client-test-utils.h
+
+libclient_test_utils_la_CPPFLAGS =				\
+	$(AM_CPPFLAGS)						\
+	-I$(top_srcdir)						\
+	-I$(top_builddir)					\
+	-I$(top_srcdir)/addressbook				\
+	-I$(top_builddir)/addressbook				\
+	-DSRCDIR=\""$(srcdir)"\"				\
+	$(EVOLUTION_ADDRESSBOOK_CFLAGS)				\
+	$(NULL)
+
+libclient_test_utils_la_LIBADD = 				\
+	$(top_builddir)/addressbook/libebook/libebook-1.2.la	\
+	$(EVOLUTION_ADDRESSBOOK_LIBS)				\
+	$(NULL)
+
+# Should be kept ordered approximately from least to most difficult/complex
+TESTS =								\
+	test-client-remove					\
+	test-client-examine					\
+	test-client-refresh					\
+	test-client-add-contact					\
+	test-client-get-contact					\
+	test-client-get-view					\
+	test-client-modify-contact				\
+	test-client-remove-contact				\
+	test-client-remove-contact-by-uid			\
+	test-client-remove-contacts				\
+	test-client-stress-factory--serial			\
+	test-client-stress-factory--fifo			\
+	test-client-stress-factory--single-book			\
+	$(NULL)
+
+noinst_PROGRAMS =						\
+	$(TESTS)						\
+	test-client						\
+	test-client-async					\
+	test-client-nonexistent-id				\
+	test-client-search					\
+	test-client-self					\
+	test-client-stress-views				\
+	$(NULL)
+
+TEST_CPPFLAGS =							\
+	$(libclient_test_utils_la_CPPFLAGS)			\
+	$(EVOLUTION_ADDRESSBOOK_CPPFLAGS)			\
+	$(NULL)
+
+TEST_LIBS =							\
+	$(libclient_test_utils_la_LIBS)				\
+	libclient-test-utils.la					\
+	$(top_builddir)/addressbook/libebook/libebook-1.2.la	\
+	$(EVOLUTION_ADDRESSBOOK_LIBS)				\
+	$(NULL)
+
+test_client_LDADD=$(TEST_LIBS)
+test_client_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_async_LDADD=$(TEST_LIBS)
+test_client_async_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_add_contact_LDADD=$(TEST_LIBS)
+test_client_add_contact_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_examine_LDADD=$(TEST_LIBS)
+test_client_examine_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_get_contact_LDADD=$(TEST_LIBS)
+test_client_get_contact_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_get_view_LDADD=$(TEST_LIBS)
+test_client_get_view_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_modify_contact_LDADD=$(TEST_LIBS)
+test_client_modify_contact_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_refresh_LDADD=$(TEST_LIBS)
+test_client_refresh_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_remove_LDADD=$(TEST_LIBS)
+test_client_remove_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_remove_contact_LDADD=$(TEST_LIBS)
+test_client_remove_contact_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_remove_contact_by_uid_LDADD=$(TEST_LIBS)
+test_client_remove_contact_by_uid_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_remove_contacts_LDADD=$(TEST_LIBS)
+test_client_remove_contacts_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_stress_factory__fifo_LDADD=$(TEST_LIBS)
+test_client_stress_factory__fifo_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_stress_factory__serial_LDADD=$(TEST_LIBS)
+test_client_stress_factory__serial_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_stress_factory__single_book_LDADD=$(TEST_LIBS)
+test_client_stress_factory__single_book_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_nonexistent_id_LDADD=$(TEST_LIBS)
+test_client_nonexistent_id_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_search_LDADD=$(TEST_LIBS)
+test_client_search_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_self_LDADD=$(TEST_LIBS)
+test_client_self_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_stress_views_LDADD=$(TEST_LIBS)
+test_client_stress_views_CPPFLAGS=$(TEST_CPPFLAGS)
+
+-include $(top_srcdir)/git.mk
diff --git a/tests/libebook/client/client-test-utils.c b/tests/libebook/client/client-test-utils.c
new file mode 100644
index 0000000..13acd6a
--- /dev/null
+++ b/tests/libebook/client/client-test-utils.c
@@ -0,0 +1,433 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <stdio.h>
+
+#include "client-test-utils.h"
+
+void
+report_error (const gchar *operation, GError **error)
+{
+	g_return_if_fail (operation != NULL);
+
+	g_printerr ("Failed to %s: %s\n", operation, (error && *error) ? (*error)->message : "Unknown error");
+
+	g_clear_error (error);
+}
+
+void
+print_email (EContact *contact)
+{
+	const gchar *file_as = e_contact_get_const (contact, E_CONTACT_FILE_AS);
+	const gchar *name_or_org = e_contact_get_const (contact, E_CONTACT_NAME_OR_ORG);
+	GList *emails, *e;
+
+	g_print ("   Contact: %s\n", file_as);
+	g_print ("   Name or org: %s\n", name_or_org);
+	g_print ("   Email addresses:\n");
+	emails = e_contact_get (contact, E_CONTACT_EMAIL);
+	for (e = emails; e; e = e->next) {
+		g_print ("\t%s\n",  (gchar *)e->data);
+	}
+	g_list_foreach (emails, (GFunc)g_free, NULL);
+	g_list_free (emails);
+
+	g_print ("\n");
+}
+
+EBookClient *
+open_system_book (gboolean only_if_exists)
+{
+	EBookClient *book_client;
+	GError *error = NULL;
+
+	main_initialize ();
+
+	book_client = e_book_client_new_system (&error);
+	if (error) {
+		report_error ("create system addressbook", &error);
+		return NULL;
+	}
+
+	if (!e_client_open_sync (E_CLIENT (book_client), only_if_exists, NULL, &error)) {
+		g_object_unref (book_client);
+		report_error ("open client sync", &error);
+		return NULL;
+	}
+
+	return book_client;
+}
+
+void
+main_initialize (void)
+{
+	static gboolean initialized = FALSE;
+
+	if (initialized)
+		return;
+
+	g_type_init ();
+	g_thread_init (NULL);
+
+	initialized = TRUE;
+}
+
+struct IdleData {
+	GThreadFunc func;
+	gpointer data;
+	gboolean run_in_thread; /* FALSE to run in idle callback */
+};
+
+static gboolean
+idle_cb (gpointer data)
+{
+	struct IdleData *idle = data;
+
+	g_return_val_if_fail (idle != NULL, FALSE);
+	g_return_val_if_fail (idle->func != NULL, FALSE);
+
+	if (idle->run_in_thread) {
+		GError *error = NULL;
+
+		g_thread_create (idle->func, idle->data, FALSE, &error);
+
+		if (error) {
+			report_error ("create thread", &error);
+			stop_main_loop (1);
+		}
+	} else {
+		idle->func (idle->data);
+	}
+
+	g_free (idle);
+
+	return FALSE;
+}
+
+static GMainLoop *loop = NULL;
+static gint main_stop_result = 0;
+
+static void
+do_start (GThreadFunc func, gpointer data)
+{
+	main_initialize ();
+
+	g_return_if_fail (loop == NULL);
+
+	loop = g_main_loop_new (NULL, FALSE);
+
+	if (func)
+		func (data);
+
+	g_main_loop_run (loop);
+
+	g_main_loop_unref (loop);
+	loop = NULL;
+}
+
+/* Starts new main-loop, but just before that calls 'func'.
+   Main-loop is kept running, and this function blocks, 
+   until call of stop_main_loop().
+*/
+void
+start_main_loop (GThreadFunc func, gpointer data)
+{
+	g_return_if_fail (loop == NULL);
+
+	do_start (func, data);
+}
+
+/* Starts new main-loop and then invokes func in a new thread.
+   Main-loop is kept running, and this function blocks, 
+   until call of stop_main_loop().
+*/
+void
+start_in_thread_with_main_loop (GThreadFunc func, gpointer data)
+{
+	struct IdleData *idle;
+
+	g_return_if_fail (func != NULL);
+	g_return_if_fail (loop == NULL);
+
+	main_initialize ();
+
+	idle = g_new0 (struct IdleData, 1);
+	idle->func = func;
+	idle->data = data;
+	idle->run_in_thread = TRUE;
+
+	g_idle_add (idle_cb, idle);
+
+	do_start (NULL, NULL);
+}
+
+/* Starts new main-loop and then invokes func in an idle callback.
+   Main-loop is kept running, and this function blocks, 
+   until call of stop_main_loop().
+*/
+void
+start_in_idle_with_main_loop (GThreadFunc func, gpointer data)
+{
+	struct IdleData *idle;
+
+	g_return_if_fail (func != NULL);
+	g_return_if_fail (loop == NULL);
+
+	main_initialize ();
+
+	idle = g_new0 (struct IdleData, 1);
+	idle->func = func;
+	idle->data = data;
+	idle->run_in_thread = FALSE;
+
+	g_idle_add (idle_cb, idle);
+
+	do_start (NULL, NULL);
+}
+
+/* Stops main-loop previously run by start_main_loop,
+   start_in_thread_with_main_loop or start_in_idle_with_main_loop.
+*/
+void
+stop_main_loop (gint stop_result)
+{
+	g_return_if_fail (loop != NULL);
+
+	main_stop_result = stop_result;
+	g_main_loop_quit (loop);
+}
+
+/* returns value used in stop_main_loop() */
+gint
+get_main_loop_stop_result (void)
+{
+	return main_stop_result;
+}
+
+void
+foreach_configured_source (void (*func) (ESource *source))
+{
+	gpointer foreach_async_data;
+	ESource *source = NULL;
+
+	g_return_if_fail (func != NULL);
+
+	main_initialize ();
+
+	foreach_async_data = foreach_configured_source_async_start (&source);
+	if (!foreach_async_data)
+		return;
+
+	do {
+		func (source);
+	} while (foreach_configured_source_async_next (&foreach_async_data, &source));
+}
+
+struct ForeachConfiguredData
+{
+	ESourceList *source_list;
+	GSList *current_group;
+	GSList *current_source;
+};
+
+gpointer
+foreach_configured_source_async_start (ESource **source)
+{
+	struct ForeachConfiguredData *async_data;
+	ESourceList *source_list = NULL;
+	GError *error = NULL;
+
+	g_return_val_if_fail (source != NULL, NULL);
+
+	main_initialize ();
+
+	if (!e_book_client_get_sources (&source_list, &error)) {
+		report_error ("get addressbooks", &error);
+		return NULL;
+	}
+
+	g_return_val_if_fail (source_list != NULL, NULL);
+
+	async_data = g_new0 (struct ForeachConfiguredData, 1);
+	async_data->source_list = source_list;
+	async_data->current_group = e_source_list_peek_groups (source_list);
+	if (!async_data->current_group) {
+		gpointer ad = async_data;
+
+		foreach_configured_source_async_next (&ad, source);
+		return ad;
+	}
+
+	async_data->current_source = e_source_group_peek_sources (async_data->current_group->data);
+	if (!async_data->current_source) {
+		gpointer ad = async_data;
+
+		if (foreach_configured_source_async_next (&ad, source))
+			return ad;
+
+		return NULL;
+	}
+
+	*source = async_data->current_source->data;
+
+	return async_data;
+}
+
+gboolean
+foreach_configured_source_async_next (gpointer *foreach_async_data, ESource **source)
+{
+	struct ForeachConfiguredData *async_data;
+
+	g_return_val_if_fail (foreach_async_data != NULL, FALSE);
+	g_return_val_if_fail (source != NULL, FALSE);
+
+	async_data = *foreach_async_data;
+	g_return_val_if_fail (async_data != NULL, FALSE);
+	g_return_val_if_fail (async_data->source_list != NULL, FALSE);
+	g_return_val_if_fail (async_data->current_group != NULL, FALSE);
+
+	if (async_data->current_source)
+		async_data->current_source = async_data->current_source->next;
+	if (async_data->current_source) {
+		*source = async_data->current_source->data;
+		return TRUE;
+	}
+
+	do {
+		async_data->current_group = async_data->current_group->next;
+		if (async_data->current_group)
+			async_data->current_source = e_source_group_peek_sources (async_data->current_group->data);
+	} while (async_data->current_group && !async_data->current_source);
+
+	if (async_data->current_source) {
+		*source = async_data->current_source->data;
+		return TRUE;
+	}
+
+	g_object_unref (async_data->source_list);
+	g_free (async_data);
+
+	*foreach_async_data = NULL;
+
+	return FALSE;
+}
+
+EBookClient *
+new_temp_client (gchar **uri)
+{
+	EBookClient *book_client;
+	ESource *source;
+	gchar *abs_uri, *filename;
+	gint handle;
+	GError *error = NULL;
+
+	filename = g_build_filename (g_get_tmp_dir (), "e-book-client-test-XXXXXX/", NULL);
+	handle = g_mkstemp (filename);
+
+	if (handle != -1)
+		close (handle);
+
+	g_return_val_if_fail (g_mkdir_with_parents (filename, 0700) == 0, NULL);
+
+	abs_uri = g_strconcat ("local://", filename, NULL);
+	g_free (filename);
+
+	source = e_source_new_with_absolute_uri ("Test book", abs_uri);
+	if (uri)
+		*uri = abs_uri;
+	else
+		g_free (abs_uri);
+
+	g_return_val_if_fail (source != NULL, NULL);
+
+	book_client = e_book_client_new (source, &error);
+	g_object_unref (source);
+
+	if (error)
+		report_error ("new temp client", &error);
+
+	return book_client;
+}
+
+gchar *
+new_vcard_from_test_case (const gchar *case_name)
+{
+	gchar *filename;
+	gchar *case_filename;
+	GFile* file;
+	GError *error = NULL;
+	gchar *vcard;
+
+        case_filename = g_strdup_printf ("%s.vcf", case_name);
+	filename = g_build_filename (SRCDIR, "..", "data", "vcards", case_filename, NULL);
+	file = g_file_new_for_path (filename);
+	if (!g_file_load_contents (file, NULL, &vcard, NULL, NULL, &error)) {
+                g_warning ("failed to read test contact file '%s': %s",
+				filename, error->message);
+		exit (1);
+	}
+
+	g_free (case_filename);
+	g_free (filename);
+	g_object_unref (file);
+
+	return vcard;
+}
+
+static gboolean
+contacts_are_equal_shallow (EContact *a, EContact *b)
+{
+	const gchar *uid_a, *uid_b;
+
+        /* Avoid warnings if one or more are NULL, to make this function
+         * "NULL-friendly" */
+	if (!a && !b)
+		return TRUE;
+
+	if (!E_IS_CONTACT (a) || !E_IS_CONTACT (b))
+		return FALSE;
+
+	uid_a = e_contact_get_const (a, E_CONTACT_UID);
+	uid_b = e_contact_get_const (b, E_CONTACT_UID);
+
+	return g_strcmp0 (uid_a, uid_b) == 0;
+}
+
+gboolean
+add_contact_from_test_case_verify (EBookClient *book_client, const gchar *case_name, EContact **contact)
+{
+	gchar *vcard;
+	EContact *contact_orig;
+	EContact *contact_final;
+	gchar *uid;
+	GError *error = NULL;
+
+	vcard = new_vcard_from_test_case (case_name);
+	contact_orig = e_contact_new_from_vcard (vcard);
+	g_free (vcard);
+	if (!e_book_client_add_contact_sync (book_client, contact_orig, &uid, NULL, &error)) {
+		report_error ("add contact sync", &error);
+		g_object_unref (contact_orig);
+		return FALSE;
+	}
+
+	e_contact_set (contact_orig, E_CONTACT_UID, uid);
+
+	if (!e_book_client_get_contact_sync (book_client, uid, &contact_final, NULL, &error)) {
+		report_error ("get contact sync", &error);
+		g_object_unref (contact_orig);
+		g_free (uid);
+		return FALSE;
+	}
+
+        /* verify the contact was added "successfully" (not thorough) */
+	g_assert (contacts_are_equal_shallow (contact_orig, contact_final));
+
+	if (contact)
+                *contact = contact_final;
+	else
+		g_object_unref (contact_final);
+	g_object_unref (contact_orig);
+	g_free (uid);
+
+	return TRUE;
+}
diff --git a/tests/libebook/client/client-test-utils.h b/tests/libebook/client/client-test-utils.h
new file mode 100644
index 0000000..5d33d95
--- /dev/null
+++ b/tests/libebook/client/client-test-utils.h
@@ -0,0 +1,27 @@
+#ifndef CLIENT_TEST_UTILS_H
+#define CLIENT_TEST_UTILS_H
+
+#include <glib.h>
+#include <libebook/e-book-client.h>
+#include <libebook/e-contact.h>
+
+void report_error (const gchar *operation, GError **error);
+void print_email (EContact *contact);
+EBookClient *open_system_book (gboolean only_if_exists);
+
+void main_initialize (void);
+void start_main_loop (GThreadFunc func, gpointer data);
+void start_in_thread_with_main_loop (GThreadFunc func, gpointer data);
+void start_in_idle_with_main_loop (GThreadFunc func, gpointer data);
+void stop_main_loop (gint stop_result);
+gint get_main_loop_stop_result (void);
+
+void foreach_configured_source (void (*func) (ESource *source));
+gpointer foreach_configured_source_async_start (ESource **source);
+gboolean foreach_configured_source_async_next (gpointer *foreach_async_data, ESource **source);
+
+EBookClient *new_temp_client (gchar **uri);
+gboolean add_contact_from_test_case_verify (EBookClient *book_client, const gchar *case_name, EContact **contact);
+gchar *new_vcard_from_test_case (const gchar *case_name);
+
+#endif /* CLIENT_TEST_UTILS_H */
diff --git a/tests/libebook/client/test-client-add-contact.c b/tests/libebook/client/test-client-add-contact.c
new file mode 100644
index 0000000..24b3de1
--- /dev/null
+++ b/tests/libebook/client/test-client-add-contact.c
@@ -0,0 +1,95 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <stdlib.h>
+#include <libebook/e-book-client.h>
+
+#include "client-test-utils.h"
+
+static void
+add_contact_cb (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	GError *error = NULL;
+	gchar *uid;
+
+	if (!e_book_client_add_contact_finish (E_BOOK_CLIENT (source_object), result, &uid, &error)) {
+		report_error ("add contact finish", &error);
+		stop_main_loop (1);
+		return;
+	}
+
+	printf ("Contact added as '%s'\n", uid);
+	g_free (uid);
+	stop_main_loop (0);
+}
+
+gint
+main (gint argc, gchar **argv)
+{
+	EBookClient *book_client;
+	GError *error = NULL;
+	EContact *contact;
+	gchar *vcard;
+
+	main_initialize ();
+
+	/*
+	 * Setup
+	 */
+	book_client = new_temp_client (NULL);
+	g_return_val_if_fail (book_client != NULL, 1);
+
+	if (!e_client_open_sync (E_CLIENT (book_client), FALSE, NULL, &error)) {
+		report_error ("client open sync", &error);
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	/*
+	 * Sync version
+	 */
+	if (!add_contact_from_test_case_verify (book_client, "simple-1", &contact)) {
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	g_object_unref (contact);
+
+	if (!e_client_remove_sync (E_CLIENT (book_client), NULL, &error)) {
+		report_error ("client remove sync", &error);
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	g_object_unref (book_client);
+
+	/*
+	 * Async version
+	 */
+	book_client = new_temp_client (NULL);
+	g_return_val_if_fail (book_client != NULL, 1);
+
+	if (!e_client_open_sync (E_CLIENT (book_client), FALSE, NULL, &error)) {
+		report_error ("client open sync", &error);
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	vcard = new_vcard_from_test_case ("simple-1");
+	contact = e_contact_new_from_vcard (vcard);
+	g_free (vcard);
+
+	e_book_client_add_contact (book_client, contact, NULL, add_contact_cb, NULL);
+	g_object_unref (contact);
+
+	start_main_loop (NULL, NULL);
+
+	if (!e_client_remove_sync (E_CLIENT (book_client), NULL, &error)) {
+		report_error ("client remove sync", &error);
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	g_object_unref (book_client);
+
+	return get_main_loop_stop_result ();
+}
diff --git a/tests/libebook/client/test-client-async.c b/tests/libebook/client/test-client-async.c
new file mode 100644
index 0000000..e3cc419
--- /dev/null
+++ b/tests/libebook/client/test-client-async.c
@@ -0,0 +1,121 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <stdlib.h>
+#include <libebook/e-book-client.h>
+#include <libebook/e-book-query.h>
+
+#include "client-test-utils.h"
+
+static void
+print_all_emails_cb (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	EBookClient *book_client;
+	GSList *contacts = NULL, *c;
+	GError *error = NULL;
+
+	book_client = E_BOOK_CLIENT (source_object);
+	g_return_if_fail (book_client != NULL);
+
+	if (!e_book_client_get_contacts_finish (book_client, result, &contacts, &error)) {
+		report_error ("get contacts finish", &error);
+		stop_main_loop (1);
+		return;
+	}
+
+	for (c = contacts; c; c = c->next) {
+		EContact *contact = E_CONTACT (c->data);
+
+		print_email (contact);
+	}
+
+	g_slist_foreach (contacts, (GFunc) g_object_unref, NULL);
+	g_slist_free (contacts);
+
+	stop_main_loop (0);
+}
+
+static void
+print_all_emails (EBookClient *book_client)
+{
+	EBookQuery *query;
+	gchar *sexp;
+
+	query = e_book_query_field_exists (E_CONTACT_FULL_NAME);
+	sexp = e_book_query_to_string (query);
+	e_book_query_unref (query);
+
+	e_book_client_get_contacts (book_client, sexp, NULL, print_all_emails_cb, NULL);
+
+	g_free (sexp);
+}
+
+static void
+print_email_cb (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	EBookClient *book_client;
+	EContact *contact = NULL;
+	GError *error = NULL;
+
+	book_client = E_BOOK_CLIENT (source_object);
+	g_return_if_fail (book_client != NULL);
+
+	if (!e_book_client_get_contact_finish (book_client, result, &contact, &error)) {
+		report_error ("get contact finish", &error);
+	} else {
+		print_email (contact);
+		g_object_unref (contact);
+	}
+
+	printf ("printing all contacts\n");
+	print_all_emails (book_client);
+}
+
+static void
+print_one_email (EBookClient *book_client)
+{
+	e_book_client_get_contact (book_client, "pas-id-0002023", NULL, print_email_cb, NULL);
+}
+
+static void
+client_loaded_cb (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	EBookClient *book_client;
+	GError *error = NULL;
+
+	book_client = E_BOOK_CLIENT (source_object);
+	g_return_if_fail (book_client != NULL);
+
+	if (!e_client_open_finish (E_CLIENT (book_client), result, &error)) {
+		report_error ("client open finish", &error);
+		stop_main_loop (1);
+		return;
+	}
+
+	printf ("printing one contact\n");
+	print_one_email (book_client);
+}
+
+gint
+main (gint argc, gchar **argv)
+{
+	EBookClient *book_client;
+	GError *error = NULL;
+
+	main_initialize ();
+
+	book_client = e_book_client_new_system (&error);
+	if (error) {
+		report_error ("create system addressbook", &error);
+		return 1;
+	}
+
+	printf ("loading addressbook\n");
+
+	e_client_open (E_CLIENT (book_client), FALSE, NULL, client_loaded_cb, NULL);
+
+	start_main_loop (NULL, NULL);
+
+	g_object_unref (book_client);
+
+	return get_main_loop_stop_result ();
+}
diff --git a/tests/libebook/client/test-client-examine.c b/tests/libebook/client/test-client-examine.c
new file mode 100644
index 0000000..687c74a
--- /dev/null
+++ b/tests/libebook/client/test-client-examine.c
@@ -0,0 +1,399 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <stdlib.h>
+#include <string.h>
+#include <libebook/e-book-client.h>
+#include <libedataserver/e-source-group.h>
+
+#include "client-test-utils.h"
+
+static gint running_async = 0;
+
+static GSList *
+get_known_prop_names (void)
+{
+	GSList *prop_names = NULL;
+
+	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_OPENED);
+	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_OPENING);
+	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_ONLINE);
+	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_READONLY);
+	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_CACHE_DIR);
+	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_CAPABILITIES);
+	prop_names = g_slist_append (prop_names, (gpointer) BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS);
+	prop_names = g_slist_append (prop_names, (gpointer) BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS);
+	prop_names = g_slist_append (prop_names, (gpointer) BOOK_BACKEND_PROPERTY_SUPPORTED_AUTH_METHODS);
+
+	return prop_names;
+}
+
+typedef struct _ExtraValues {
+	gpointer async_data;
+
+	GSList *todo_prop_names;
+	GHashTable *retrieved_props;
+} ExtraValues;
+
+static void
+extra_values_free (ExtraValues *evals)
+{
+	if (!evals)
+		return;
+
+	g_slist_free (evals->todo_prop_names);
+	g_hash_table_destroy (evals->retrieved_props);
+	g_free (evals);
+}
+
+static void
+print_each_property (gpointer prop_name, gpointer prop_value, gpointer user_data)
+{
+	g_return_if_fail (prop_name != NULL);
+
+	if (prop_value == NULL) {
+		g_print ("\t   %s: NULL\n", (const gchar *) prop_name);
+		return;
+	}
+
+	g_print ("\t   %s: ", (const gchar *) prop_name);
+
+	if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES) ||
+	    g_str_equal (prop_name, BOOK_BACKEND_PROPERTY_REQUIRED_FIELDS) ||
+	    g_str_equal (prop_name, BOOK_BACKEND_PROPERTY_SUPPORTED_FIELDS) ||
+	    g_str_equal (prop_name, BOOK_BACKEND_PROPERTY_SUPPORTED_AUTH_METHODS)) {
+		GSList *values = e_client_util_parse_comma_strings (prop_value), *v;
+
+		
+		for (v = values; v; v = v->next) {
+			if (v != values)
+				g_print (", ");
+
+			g_print ("'%s'", (const gchar *) v->data);
+		}
+
+		e_client_util_free_string_slist (values);
+	} else {
+		g_print ("'%s'", (const gchar *) prop_value);
+	}
+
+	g_print ("\n");
+}
+
+static void
+print_values (const ExtraValues *evals, EClient *client)
+{
+	const GSList *values;
+
+	g_return_if_fail (evals != NULL);
+
+	g_print ("\treadonly:%s\n", e_client_is_readonly (client) ? "yes" : "no");
+	g_print ("\tonline:%s\n", e_client_is_online (client) ? "yes" : "no");
+	g_print ("\topened:%s\n", e_client_is_opened (client) ? "yes" : "no");
+	g_print ("\tcapabilities: ");
+	values = e_client_get_capabilities (client);
+	if (!values) {
+		g_print ("NULL");
+	} else {
+		while (values) {
+			const gchar *cap = values->data;
+
+			g_print ("'%s'", cap);
+			if (!e_client_check_capability (client, cap))
+				g_print (" (not found in EClient)");
+
+			values = values->next;
+
+			if (values)
+				g_print (", ");
+		}
+	}
+	g_print ("\n");
+
+	g_print ("\tbackend properties:\n");
+	g_hash_table_foreach (evals->retrieved_props, print_each_property, NULL);
+}
+
+static void
+identify_source (ESource *source)
+{
+	const gchar *name, *uri;
+	gchar *abs_uri = NULL;
+
+	g_return_if_fail (source != NULL);
+
+	name = e_source_peek_name (source);
+	if (!name)
+		name = "Unknown name";
+
+	uri = e_source_peek_absolute_uri (source);
+	if (!uri) {
+		abs_uri = e_source_build_absolute_uri (source);
+		uri = abs_uri;
+	}
+	if (!uri)
+		uri = e_source_peek_relative_uri (source);
+	if (!uri)
+		uri = "Unknown uri";
+
+	g_print ("\n   Checking source '%s' (%s)\n", name, uri);
+
+	g_free (abs_uri);
+}
+
+static void
+identify_client (EBookClient *book_client)
+{
+	g_return_if_fail (book_client != NULL);
+	g_return_if_fail (E_IS_BOOK_CLIENT (book_client));
+
+	identify_source (e_client_get_source (E_CLIENT (book_client)));
+}
+
+static void client_opened_async (GObject *source_object, GAsyncResult *result, gpointer async_data);
+
+static void
+continue_next_source (gpointer async_data)
+{
+	ESource *source = NULL;
+	EBookClient *book_client;
+	GError *error = NULL;
+
+	g_return_if_fail (async_data != NULL);
+
+	while (async_data && foreach_configured_source_async_next (&async_data, &source)) {
+		book_client = e_book_client_new (source, &error);
+		if (!book_client) {
+			identify_source (source);
+			report_error ("book client new", &error);
+			continue;
+		}
+
+		e_client_open (E_CLIENT (book_client), TRUE, NULL, client_opened_async, async_data);
+		break;
+	}
+
+	if (!async_data) {
+		running_async--;
+		if (!running_async)
+			stop_main_loop (0);
+	}
+}
+
+static void
+client_got_backend_property_async (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	ExtraValues *evals = user_data;
+	gchar *prop_value = NULL;
+	GError *error = NULL;
+	EBookClient *book_client;
+
+	g_return_if_fail (source_object != NULL);
+	g_return_if_fail (E_IS_BOOK_CLIENT (source_object));
+	g_return_if_fail (evals != NULL);
+
+	book_client = E_BOOK_CLIENT (source_object);
+
+	if (!e_client_get_backend_property_finish (E_CLIENT (book_client), result, &prop_value, &error)) {
+		identify_client (book_client);
+		report_error ("get backend property finish", &error);
+	}
+
+	g_hash_table_insert (evals->retrieved_props, evals->todo_prop_names->data, prop_value);
+	evals->todo_prop_names = g_slist_remove (evals->todo_prop_names, evals->todo_prop_names->data);
+
+	if (!evals->todo_prop_names) {
+		/* to cache them, as it can be fetched with idle as well */
+		e_client_get_capabilities (E_CLIENT (source_object));
+
+		identify_client (book_client);
+		print_values (evals, E_CLIENT (source_object));
+
+		g_object_unref (source_object);
+
+		continue_next_source (evals->async_data);
+		extra_values_free (evals);
+	} else {
+		e_client_get_backend_property (E_CLIENT (book_client), evals->todo_prop_names->data, NULL, client_got_backend_property_async, evals);
+	}
+}
+
+static void
+client_set_backend_property_async (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	ExtraValues *evals = user_data;
+	GError *error = NULL;
+	EBookClient *book_client;
+
+	g_return_if_fail (source_object != NULL);
+	g_return_if_fail (E_IS_BOOK_CLIENT (source_object));
+	g_return_if_fail (evals != NULL);
+
+	book_client = E_BOOK_CLIENT (source_object);
+
+	if (!e_client_set_backend_property_finish (E_CLIENT (book_client), result, &error)) {
+		/* it may fail on the set_backend_property */
+		g_clear_error (&error);
+	} else {
+		identify_client (book_client);
+		g_printerr ("   Might fail on set_backend_property, but reported success\n");
+	}
+
+	e_client_get_backend_property (E_CLIENT (book_client), evals->todo_prop_names->data, NULL, client_got_backend_property_async, evals);
+}
+
+static void
+client_opened_async (GObject *source_object, GAsyncResult *result, gpointer async_data)
+{
+	ExtraValues *evals;
+	GError *error = NULL;
+	EBookClient *book_client;
+
+	g_return_if_fail (source_object != NULL);
+	g_return_if_fail (E_IS_BOOK_CLIENT (source_object));
+	g_return_if_fail (async_data != NULL);
+
+	book_client = E_BOOK_CLIENT (source_object);
+
+	if (!e_client_open_finish (E_CLIENT (source_object), result, &error)) {
+		identify_client (book_client);
+		report_error ("client open finish", &error);
+		g_object_unref (source_object);
+		continue_next_source (async_data);
+		return;
+	}
+
+	evals = g_new0 (ExtraValues, 1);
+	evals->async_data = async_data;
+	evals->todo_prop_names = get_known_prop_names ();
+	evals->retrieved_props = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);
+
+	e_client_set_backend_property (E_CLIENT (book_client), "*unknown*property*", "*value*", NULL, client_set_backend_property_async, evals);
+}
+
+static void
+check_source_sync (ESource *source)
+{
+	EBookClient *book_client;
+	GError *error = NULL;
+	GSList *properties, *p;
+	ExtraValues evals = { 0 };
+
+	g_return_if_fail (source != NULL);
+
+	identify_source (source);
+
+	book_client = e_book_client_new (source, &error);
+	if (!book_client) {
+		report_error ("book client new", &error);
+		return;
+	}
+
+	if (!e_client_open_sync (E_CLIENT (book_client), TRUE, NULL, &error)) {
+		report_error ("client open sync", &error);
+		g_object_unref (book_client);
+		return;
+	}
+
+	if (!e_client_set_backend_property_sync (E_CLIENT (book_client), "*unknown*property*", "*value*", NULL, &error)) {
+		g_clear_error (&error);
+	} else {
+		identify_client (book_client);
+		g_printerr ("   Might fail on set_backend_property, but reported success\n");
+	}
+
+	evals.retrieved_props = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);
+
+	properties = get_known_prop_names ();
+	for (p = properties; p != NULL; p = p->next) {
+		gchar *prop_value = NULL;
+
+		if (!e_client_get_backend_property_sync (E_CLIENT (book_client), p->data, &prop_value, NULL, &error)) {
+			identify_client (book_client);
+			report_error ("get backend property sync", &error);
+		} else {
+			g_hash_table_insert (evals.retrieved_props, p->data, prop_value);
+		}
+	}
+	g_slist_free (properties);
+
+	print_values (&evals, E_CLIENT (book_client));
+
+	g_hash_table_destroy (evals.retrieved_props);
+	g_object_unref (book_client);
+}
+
+static gboolean
+foreach_async (void)
+{
+	gpointer async_data;
+	ESource *source = NULL;
+	EBookClient *book_client;
+	GError *error = NULL;
+
+	async_data = foreach_configured_source_async_start (&source);
+	if (!async_data) {
+		stop_main_loop (1);
+		return FALSE;
+	}
+
+	running_async++;
+
+	while (book_client = e_book_client_new (source, &error), !book_client) {
+		identify_source (source);
+		report_error ("book client new", &error);
+
+		if (!foreach_configured_source_async_next (&async_data, &source)) {
+			running_async--;
+			if (!running_async)
+				stop_main_loop (0);
+			return FALSE;
+		}
+
+		identify_source (source);
+	}
+
+	e_client_open (E_CLIENT (book_client), TRUE, NULL, client_opened_async, async_data);
+
+	return TRUE;
+}
+
+static gboolean
+in_main_thread_idle_cb (gpointer unused)
+{
+	g_print ("* run in main thread with mainloop running\n");
+	foreach_configured_source (check_source_sync);
+	g_print ("---------------------------------------------------------\n\n");
+
+	g_print ("* run in main thread async\n");
+
+	if (!foreach_async ())
+		return FALSE;
+
+	return FALSE;
+}
+
+static gpointer
+worker_thread (gpointer unused)
+{
+	g_print ("* run in dedicated thread with mainloop running\n");
+	foreach_configured_source (check_source_sync);
+	g_print ("---------------------------------------------------------\n\n");
+
+	g_idle_add (in_main_thread_idle_cb, NULL);
+
+	return NULL;
+}
+
+gint
+main (gint argc, gchar **argv)
+{
+	main_initialize ();
+
+	g_print ("* run in main thread without mainloop\n");
+	foreach_configured_source (check_source_sync);
+	g_print ("---------------------------------------------------------\n\n");
+
+	start_in_thread_with_main_loop (worker_thread, NULL);
+
+	return get_main_loop_stop_result ();
+}
diff --git a/tests/libebook/client/test-client-get-contact.c b/tests/libebook/client/test-client-get-contact.c
new file mode 100644
index 0000000..7a8e0b7
--- /dev/null
+++ b/tests/libebook/client/test-client-get-contact.c
@@ -0,0 +1,70 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <stdlib.h>
+#include <libebook/e-book-client.h>
+
+#include "client-test-utils.h"
+
+static void
+contact_ready_cb (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	EContact *contact;
+	GError *error = NULL;
+
+	if (!e_book_client_get_contact_finish (E_BOOK_CLIENT (source_object), result, &contact, &error)) {
+		report_error ("get contact finish", &error);
+		stop_main_loop (1);
+	} else {
+		g_object_unref (contact);
+		stop_main_loop (0);
+	}
+}
+
+gint
+main (gint argc, gchar **argv)
+{
+	EBookClient *book_client;
+	EContact *contact_final;
+	GError *error = NULL;
+
+	main_initialize ();
+
+	/*
+	 * Setup
+	 */
+	book_client = new_temp_client (NULL);
+	g_return_val_if_fail (book_client != NULL, 1);
+
+	if (!e_client_open_sync (E_CLIENT (book_client), FALSE, NULL, &error)) {
+		report_error ("client open sync", &error);
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	/*
+	 * Sync version
+	 */
+	if (!add_contact_from_test_case_verify (book_client, "simple-1", &contact_final)) {
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	/*
+	 * Async version
+	 */
+	e_book_client_get_contact (book_client, e_contact_get_const (contact_final, E_CONTACT_UID), NULL, contact_ready_cb, NULL);
+
+	g_object_unref (contact_final);
+
+	start_main_loop (NULL, NULL);
+
+	if (!e_client_remove_sync (E_CLIENT (book_client), NULL, &error)) {
+		report_error ("client remove sync", &error);
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	g_object_unref (book_client);
+
+	return get_main_loop_stop_result ();
+}
diff --git a/tests/libebook/client/test-client-get-view.c b/tests/libebook/client/test-client-get-view.c
new file mode 100644
index 0000000..de7829f
--- /dev/null
+++ b/tests/libebook/client/test-client-get-view.c
@@ -0,0 +1,180 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <stdlib.h>
+#include <libebook/e-book-client.h>
+#include <libebook/e-book-query.h>
+
+#include "client-test-utils.h"
+
+static void
+objects_added (EBookClientView *view, const GSList *contacts)
+{
+	const GSList *l;
+
+	for (l = contacts; l; l = l->next) {
+		print_email (l->data);
+	}
+}
+
+static void
+objects_removed (EBookClientView *view, const GSList *ids)
+{
+	const GSList *l;
+
+	for (l = ids; l; l = l->next) {
+		printf ("   Removed contact: %s\n", (gchar *) l->data);
+	}
+}
+
+static void
+complete (EBookClientView *view, const GError *error)
+{
+	e_book_client_view_stop (view, NULL);
+	g_object_unref (view);
+
+	stop_main_loop (0);
+}
+
+static void
+setup_and_start_view (EBookClientView *view)
+{
+	GError *error = NULL;
+
+	g_signal_connect (view, "objects-added", G_CALLBACK (objects_added), NULL);
+	g_signal_connect (view, "objects-removed", G_CALLBACK (objects_removed), NULL);
+	g_signal_connect (view, "complete", G_CALLBACK (complete), NULL);
+
+	e_book_client_view_set_fields_of_interest (view, NULL, &error);
+	if (error)
+		report_error ("set fields of interest", &error);
+
+	e_book_client_view_start (view, &error);
+	if (error)
+		report_error ("start view", &error);
+}
+
+static void
+get_view_cb (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	EBookClientView *view;
+	GError *error = NULL;
+
+	if (!e_book_client_get_view_finish (E_BOOK_CLIENT (source_object), result, &view, &error)) {
+		report_error ("get view finish", &error);
+		stop_main_loop (1);
+
+		return;
+	}
+
+	setup_and_start_view (view);
+}
+
+static gboolean
+setup_book (EBookClient **book_client)
+{
+	GError *error = NULL;
+
+	g_return_val_if_fail (book_client != NULL, FALSE);
+
+	*book_client = new_temp_client (NULL);
+	g_return_val_if_fail (*book_client != NULL, FALSE);
+
+	if (!e_client_open_sync (E_CLIENT (*book_client), FALSE, NULL, &error)) {
+		report_error ("client open sync", &error);
+		g_object_unref (*book_client);
+		return FALSE;
+	}
+
+	if (!add_contact_from_test_case_verify (*book_client, "simple-1", NULL) ||
+	    !add_contact_from_test_case_verify (*book_client, "simple-2", NULL) ||
+	    !add_contact_from_test_case_verify (*book_client, "name-only", NULL)) {
+		g_object_unref (*book_client);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static gpointer
+call_get_view (gpointer user_data)
+{
+	EBookQuery *query;
+	EBookClient *book_client = user_data;
+	gchar *sexp;
+
+	g_return_val_if_fail (book_client != NULL, NULL);
+	g_return_val_if_fail (E_IS_BOOK_CLIENT (book_client), NULL);
+
+	query = e_book_query_any_field_contains ("");
+	sexp = e_book_query_to_string (query);
+	e_book_query_unref (query);
+
+	e_book_client_get_view (book_client, sexp, NULL, get_view_cb, NULL);
+
+	g_free (sexp);
+
+	return NULL;
+}
+
+gint
+main (gint argc, gchar **argv)
+{
+	EBookClient *book_client;
+	EBookQuery *query;
+	EBookClientView *view;
+	gchar *sexp;
+	GError *error = NULL;
+
+	main_initialize ();
+
+	/*
+	 * Sync version
+	 */
+	if (!setup_book (&book_client))
+		return 1;
+
+	query = e_book_query_any_field_contains ("");
+	sexp = e_book_query_to_string (query);
+	e_book_query_unref (query);
+	if (!e_book_client_get_view_sync (book_client, sexp, &view, NULL, &error)) {
+		report_error ("get book view sync", &error);
+		g_free (sexp);
+		g_object_unref (book_client);
+
+		return 1;
+	}
+
+	g_free (sexp);
+
+	setup_and_start_view (view);
+
+	start_main_loop (NULL, NULL);
+
+	if (!e_client_remove_sync (E_CLIENT (book_client), NULL, &error)) {
+		report_error ("client remove sync", &error);
+		g_object_unref (book_client);
+
+		return 1;
+	}
+
+	g_object_unref (book_client);
+
+	/*
+	 * Async version
+	 */
+	if (!setup_book (&book_client))
+		return 1;
+
+	start_in_idle_with_main_loop (call_get_view, book_client);
+
+	if (!e_client_remove_sync (E_CLIENT (book_client), NULL, &error)) {
+		report_error ("client remove sync", &error);
+		g_object_unref (book_client);
+
+		return 1;
+	}
+
+	g_object_unref (book_client);
+
+	return get_main_loop_stop_result ();
+}
diff --git a/tests/libebook/client/test-client-modify-contact.c b/tests/libebook/client/test-client-modify-contact.c
new file mode 100644
index 0000000..309e370
--- /dev/null
+++ b/tests/libebook/client/test-client-modify-contact.c
@@ -0,0 +1,159 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <stdlib.h>
+#include <libebook/e-book-client.h>
+
+#include "client-test-utils.h"
+
+#define EMAIL_ADD "foo bar com"
+
+static void
+verify_premodify_and_prepare_contact (EContact *contact)
+{
+	EVCardAttribute *attr;
+
+	/* ensure there is no email address to begin with, then add one */
+	g_assert (!e_vcard_get_attribute (E_VCARD (contact), EVC_EMAIL));
+	attr = e_vcard_attribute_new (NULL, EVC_EMAIL);
+	e_vcard_add_attribute_with_value (E_VCARD (contact), attr, EMAIL_ADD);
+}
+
+static void
+verify_modify (EContact *contact)
+{
+	EVCardAttribute *attr;
+	gchar *email_value;
+
+	g_assert ((attr = e_vcard_get_attribute (E_VCARD (contact), EVC_EMAIL)));
+	g_assert (e_vcard_attribute_is_single_valued (attr));
+	email_value = e_vcard_attribute_get_value (attr);
+	g_assert (!g_strcmp0 (email_value, EMAIL_ADD));
+	g_free (email_value);
+}
+
+static void
+contact_ready_cb (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	EContact *contact;
+	GError *error = NULL;
+
+	if (!e_book_client_get_contact_finish (E_BOOK_CLIENT (source_object), result, &contact, &error)) {
+		report_error ("get contact finish", &error);
+		stop_main_loop (1);
+		return;
+	}
+
+	verify_modify (contact);
+
+	g_object_unref (contact);
+
+	stop_main_loop (0);
+}
+
+static void
+contact_modified_cb (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	EContact *contact = user_data;
+	GError *error = NULL;
+
+	if (!e_book_client_modify_contact_finish (E_BOOK_CLIENT (source_object), result, &error)) {
+		report_error ("modify contact finish", &error);
+		stop_main_loop (1);
+		return;
+	}
+
+	e_book_client_get_contact (E_BOOK_CLIENT (source_object), e_contact_get_const (contact, E_CONTACT_UID), NULL, contact_ready_cb, NULL);
+}
+
+gint
+main (gint argc, gchar **argv)
+{
+	EBookClient *book_client;
+	GError *error = NULL;
+	EContact *contact, *book_contact;
+
+	main_initialize ();
+
+	/*
+	 * Setup
+	 */
+	book_client = new_temp_client (NULL);
+	g_return_val_if_fail (book_client != NULL, 1);
+
+	if (!e_client_open_sync (E_CLIENT (book_client), FALSE, NULL, &error)) {
+		report_error ("client open sync", &error);
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	/*
+	 * Sync version
+	 */
+	if (!add_contact_from_test_case_verify (book_client, "name-only", &contact)) {
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	verify_premodify_and_prepare_contact (contact);
+
+	if (!e_book_client_modify_contact_sync (book_client, contact, NULL, &error)) {
+		report_error ("modify contact sync", &error);
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	if (!e_book_client_get_contact_sync (book_client, e_contact_get_const (contact, E_CONTACT_UID), &book_contact, NULL, &error)) {
+		report_error ("get contact sync", &error);
+		g_object_unref (contact);
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	verify_modify (book_contact);
+
+	g_object_unref (book_contact);
+	g_object_unref (contact);
+
+	if (!e_client_remove_sync (E_CLIENT (book_client), NULL, &error)) {
+		report_error ("client remove sync", &error);
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	g_object_unref (book_client);
+
+	/*
+	 * Async version
+	 */
+	book_client = new_temp_client (NULL);
+	g_return_val_if_fail (book_client != NULL, 1);
+
+	if (!e_client_open_sync (E_CLIENT (book_client), FALSE, NULL, &error)) {
+		report_error ("client open sync", &error);
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	if (!add_contact_from_test_case_verify (book_client, "name-only", &contact)) {
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	verify_premodify_and_prepare_contact (contact);
+
+	e_book_client_modify_contact (book_client, contact, NULL, contact_modified_cb, contact);
+
+	start_main_loop (NULL, NULL);
+
+	g_object_unref (contact);
+
+	if (!e_client_remove_sync (E_CLIENT (book_client), NULL, &error)) {
+		report_error ("client remove sync", &error);
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	g_object_unref (book_client);
+
+	return get_main_loop_stop_result ();
+}
diff --git a/tests/libebook/client/test-client-nonexistent-id.c b/tests/libebook/client/test-client-nonexistent-id.c
new file mode 100644
index 0000000..058bf94
--- /dev/null
+++ b/tests/libebook/client/test-client-nonexistent-id.c
@@ -0,0 +1,44 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <libebook/e-book-client.h>
+
+#include "client-test-utils.h"
+
+gint
+main (gint argc, gchar **argv)
+{
+	GError *error = NULL;
+	EBookClient *book_client = NULL;
+
+	main_initialize ();
+
+	printf ("loading addressbook\n");
+
+	book_client = open_system_book (FALSE);
+	if (!book_client)
+		return 1;
+
+	printf ("removing nonexistent contact\n");
+	if (!e_book_client_remove_contact_by_uid_sync (book_client, "ii", NULL, &error)) {
+		if (!g_error_matches (error, E_BOOK_CLIENT_ERROR, E_BOOK_CLIENT_ERROR_CONTACT_NOT_FOUND)) {
+			report_error ("remove contact sync", &error);
+			g_object_unref (book_client);
+			return 1;
+		}
+
+		printf ("\tOK, ended with expected Not Found error\n");
+		g_error_free (error);
+	} else if (error) {
+		report_error ("remove contact sync returned error, but success", &error);
+		g_object_unref (book_client);
+		return 1;
+	} else {
+		report_error ("remove contact sync returned success, but should return error", NULL);
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	g_object_unref (book_client);
+
+	return 0;
+}
diff --git a/tests/libebook/client/test-client-refresh.c b/tests/libebook/client/test-client-refresh.c
new file mode 100644
index 0000000..37db6df
--- /dev/null
+++ b/tests/libebook/client/test-client-refresh.c
@@ -0,0 +1,114 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <stdlib.h>
+#include <string.h>
+#include <libebook/e-book-client.h>
+
+#include "client-test-utils.h"
+
+static gboolean
+test_sync (EBookClient *book_client)
+{
+	GError *error = NULL;
+
+	g_print ("Refresh supported: %s\n", e_client_check_refresh_supported (E_CLIENT (book_client)) ? "yes" : "no");
+
+	if (!e_client_refresh_sync (E_CLIENT (book_client), NULL, &error)) {
+		report_error ("refresh sync", &error);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+/* asynchronous callback with a main-loop running */
+static void
+async_refresh_result_ready (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	EBookClient *book_client;
+	GError *error = NULL;
+
+	book_client = E_BOOK_CLIENT (source_object);
+
+	if (!e_client_refresh_finish (E_CLIENT (book_client), result, &error)) {
+		report_error ("refresh finish", &error);
+		stop_main_loop (1);
+		return;
+	}
+
+	stop_main_loop (0);
+}
+
+/* synchronously in idle with main-loop running */
+static gboolean
+test_sync_in_idle (gpointer user_data)
+{
+	EBookClient *book_client = user_data;
+
+	g_return_val_if_fail (book_client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_BOOK_CLIENT (book_client), FALSE);
+
+	if (!test_sync (book_client)) {
+		stop_main_loop (1);
+		return FALSE;
+	}
+
+	g_print ("Refresh supported: %s\n", e_client_check_refresh_supported (E_CLIENT (book_client)) ? "yes" : "no");
+
+	e_client_refresh (E_CLIENT (book_client), NULL, async_refresh_result_ready, NULL);
+
+	return FALSE;
+}
+
+/* synchronously in a dedicated thread with main-loop running */
+static gpointer
+test_sync_in_thread (gpointer user_data)
+{
+	if (!test_sync (user_data)) {
+		stop_main_loop (1);
+		return NULL;
+	}
+
+	g_idle_add (test_sync_in_idle, user_data);
+
+	return NULL;
+}
+
+gint
+main (gint argc, gchar **argv)
+{
+	EBookClient *book_client;
+	GError *error = NULL;
+
+	main_initialize ();
+
+	book_client = new_temp_client (NULL);
+	g_return_val_if_fail (book_client != NULL, FALSE);
+
+	if (!e_client_open_sync (E_CLIENT (book_client), FALSE, NULL, &error)) {
+		report_error ("client open sync", &error);
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	/* synchronously without main-loop */
+	if (!test_sync (book_client)) {
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	start_in_thread_with_main_loop (test_sync_in_thread, book_client);
+
+	if (!e_client_remove_sync (E_CLIENT (book_client), NULL, &error)) {
+		report_error ("client remove sync", &error);
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	g_object_unref (book_client);
+
+	if (get_main_loop_stop_result () == 0)
+		g_print ("Test finished successfully.\n");
+
+	return get_main_loop_stop_result ();
+}
diff --git a/tests/libebook/client/test-client-remove-contact-by-uid.c b/tests/libebook/client/test-client-remove-contact-by-uid.c
new file mode 100644
index 0000000..b55615a
--- /dev/null
+++ b/tests/libebook/client/test-client-remove-contact-by-uid.c
@@ -0,0 +1,127 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <libebook/e-book-client.h>
+
+#include "client-test-utils.h"
+
+static void
+remove_contact_by_uid_cb (GObject *source_object, GAsyncResult *result, gpointer uid)
+{
+	GError *error = NULL;
+	EContact *contact = NULL;
+
+	if (!e_book_client_remove_contact_by_uid_finish (E_BOOK_CLIENT (source_object), result, &error)) {
+		report_error ("remove contact by uid finish", &error);
+		stop_main_loop (1);
+		return;
+	}
+
+	if (!e_book_client_get_contact_sync (E_BOOK_CLIENT (source_object), uid, &contact, NULL, &error) &&
+	    g_error_matches (error, E_BOOK_CLIENT_ERROR, E_BOOK_CLIENT_ERROR_CONTACT_NOT_FOUND)) {
+		g_clear_error (&error);
+		stop_main_loop (0);
+	} else {
+		report_error ("fail with get contact on removed contact", &error);
+		if (contact)
+			g_object_unref (contact);
+		stop_main_loop (1);
+	}
+}
+
+gint
+main (gint argc, gchar **argv)
+{
+	EBookClient *book_client;
+	GError *error = NULL;
+	EContact *contact;
+	gchar *uid;
+
+	main_initialize ();
+
+        /*
+         * Setup
+         */
+	book_client = new_temp_client (NULL);
+	g_return_val_if_fail (book_client != NULL, 1);
+
+	if (!e_client_open_sync (E_CLIENT (book_client), FALSE, NULL, &error)) {
+		report_error ("client open sync", &error);
+		g_object_unref (book_client);
+		return 1;
+	}
+
+        /*
+         * Sync version
+         */
+	if (!add_contact_from_test_case_verify (book_client, "simple-1", &contact)) {
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	uid = e_contact_get (contact, E_CONTACT_UID);
+	g_object_unref (contact);
+
+	if (!e_book_client_remove_contact_by_uid_sync (book_client, uid, NULL, &error)) {
+		report_error ("remove contact sync", &error);
+		g_object_unref (book_client);
+		g_free (uid);
+		return 1;
+	}
+
+	if (!e_book_client_get_contact_sync (book_client, uid, &contact, NULL, &error) &&
+	    g_error_matches (error, E_BOOK_CLIENT_ERROR, E_BOOK_CLIENT_ERROR_CONTACT_NOT_FOUND)) {
+		g_clear_error (&error);
+	} else {
+		report_error ("fail with get contact sync on removed contact", &error);
+		g_object_unref (book_client);
+		g_free (uid);
+		return 1;
+	}
+
+	g_free (uid);
+
+	if (!e_client_remove_sync (E_CLIENT (book_client), NULL, &error)) {
+		report_error ("client remove sync", &error);
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	g_object_unref (book_client);
+
+        /*
+         * Async version
+         */
+	book_client = new_temp_client (NULL);
+	g_return_val_if_fail (book_client != NULL, 1);
+
+	if (!e_client_open_sync (E_CLIENT (book_client), FALSE, NULL, &error)) {
+		report_error ("client open sync", &error);
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	contact = NULL;
+
+	if (!add_contact_from_test_case_verify (book_client, "simple-1", &contact)) {
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	uid = e_contact_get (contact, E_CONTACT_UID);
+	g_object_unref (contact);
+	e_book_client_remove_contact_by_uid (book_client, uid, NULL, remove_contact_by_uid_cb, uid);
+
+	start_main_loop (NULL, NULL);
+
+	g_free (uid);
+
+	if (!e_client_remove_sync (E_CLIENT (book_client), NULL, &error)) {
+		report_error ("client remove sync", &error);
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	g_object_unref (book_client);
+
+	return 0;
+}
diff --git a/tests/libebook/client/test-client-remove-contact.c b/tests/libebook/client/test-client-remove-contact.c
new file mode 100644
index 0000000..f944684
--- /dev/null
+++ b/tests/libebook/client/test-client-remove-contact.c
@@ -0,0 +1,130 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <libebook/e-book-client.h>
+
+#include "client-test-utils.h"
+
+static void
+remove_contact_cb (GObject *source_object, GAsyncResult *result, gpointer uid)
+{
+	GError *error = NULL;
+	EContact *contact = NULL;
+
+	if (!e_book_client_remove_contact_finish (E_BOOK_CLIENT (source_object), result, &error)) {
+		report_error ("remove contact finish", &error);
+		stop_main_loop (1);
+		return;
+	}
+
+	if (!e_book_client_get_contact_sync (E_BOOK_CLIENT (source_object), uid, &contact, NULL, &error) &&
+	    g_error_matches (error, E_BOOK_CLIENT_ERROR, E_BOOK_CLIENT_ERROR_CONTACT_NOT_FOUND)) {
+		g_clear_error (&error);
+		stop_main_loop (0);
+	} else {
+		report_error ("fail with get contact on removed contact", &error);
+		if (contact)
+			g_object_unref (contact);
+		stop_main_loop (1);
+	}
+}
+
+gint
+main (gint argc, gchar **argv)
+{
+	EBookClient *book_client;
+	GError *error = NULL;
+	EContact *contact;
+	gchar *uid;
+
+	main_initialize ();
+
+        /*
+         * Setup
+         */
+	book_client = new_temp_client (NULL);
+	g_return_val_if_fail (book_client != NULL, 1);
+
+	if (!e_client_open_sync (E_CLIENT (book_client), FALSE, NULL, &error)) {
+		report_error ("client open sync", &error);
+		g_object_unref (book_client);
+		return 1;
+	}
+
+        /*
+         * Sync version
+         */
+	if (!add_contact_from_test_case_verify (book_client, "simple-1", &contact)) {
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	uid = e_contact_get (contact, E_CONTACT_UID);
+
+	if (!e_book_client_remove_contact_sync (book_client, contact, NULL, &error)) {
+		report_error ("remove contact sync", &error);
+		g_object_unref (contact);
+		g_object_unref (book_client);
+		g_free (uid);
+		return 1;
+	}
+
+	g_object_unref (contact);
+
+	if (!e_book_client_get_contact_sync (book_client, uid, &contact, NULL, &error) &&
+	    g_error_matches (error, E_BOOK_CLIENT_ERROR, E_BOOK_CLIENT_ERROR_CONTACT_NOT_FOUND)) {
+		g_clear_error (&error);
+	} else {
+		report_error ("fail with get contact sync on removed contact", &error);
+		g_object_unref (book_client);
+		g_free (uid);
+		return 1;
+	}
+
+	g_free (uid);
+
+	if (!e_client_remove_sync (E_CLIENT (book_client), NULL, &error)) {
+		report_error ("client remove sync", &error);
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	g_object_unref (book_client);
+
+        /*
+         * Async version
+         */
+	book_client = new_temp_client (NULL);
+	g_return_val_if_fail (book_client != NULL, 1);
+
+	if (!e_client_open_sync (E_CLIENT (book_client), FALSE, NULL, &error)) {
+		report_error ("client open sync", &error);
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	contact = NULL;
+
+	if (!add_contact_from_test_case_verify (book_client, "simple-1", &contact)) {
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	uid = e_contact_get (contact, E_CONTACT_UID);
+	e_book_client_remove_contact (book_client, contact, NULL, remove_contact_cb, uid);
+
+	g_object_unref (contact);
+
+	start_main_loop (NULL, NULL);
+
+	g_free (uid);
+
+	if (!e_client_remove_sync (E_CLIENT (book_client), NULL, &error)) {
+		report_error ("client remove sync", &error);
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	g_object_unref (book_client);
+
+	return 0;
+}
diff --git a/tests/libebook/client/test-client-remove-contacts.c b/tests/libebook/client/test-client-remove-contacts.c
new file mode 100644
index 0000000..49c4dd1
--- /dev/null
+++ b/tests/libebook/client/test-client-remove-contacts.c
@@ -0,0 +1,160 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <libebook/e-book-client.h>
+
+#include "client-test-utils.h"
+
+static gboolean
+check_removed (EBookClient *book_client, const GSList *uids)
+{
+	g_return_val_if_fail (book_client != NULL, FALSE);
+	g_return_val_if_fail (uids != NULL, FALSE);
+
+	while (uids) {
+		GError *error = NULL;
+		EContact *contact = NULL;
+
+		if (!e_book_client_get_contact_sync (book_client, uids->data, &contact, NULL, &error) &&
+		    g_error_matches (error, E_BOOK_CLIENT_ERROR, E_BOOK_CLIENT_ERROR_CONTACT_NOT_FOUND)) {
+			g_clear_error (&error);
+		} else {
+			report_error ("fail with get contact on removed contact", &error);
+			if (contact)
+				g_object_unref (contact);
+			return FALSE;
+		}
+
+		uids = uids->next;
+	}
+
+	return TRUE;
+}
+
+static gboolean
+fill_book_client (EBookClient *book_client, GSList **uids)
+{
+	EContact *contact;
+
+	g_return_val_if_fail (book_client != NULL, FALSE);
+	g_return_val_if_fail (uids != NULL, FALSE);
+
+	*uids = NULL;
+
+	if (!add_contact_from_test_case_verify (book_client, "simple-1", &contact))
+		return FALSE;
+
+	*uids = g_slist_append (*uids, e_contact_get (contact, E_CONTACT_UID));
+	g_object_unref (contact);
+
+	if (!add_contact_from_test_case_verify (book_client, "simple-2", &contact))
+		return FALSE;
+
+	*uids = g_slist_append (*uids, e_contact_get (contact, E_CONTACT_UID));
+	g_object_unref (contact);
+
+	return TRUE;
+}
+
+static void
+remove_contacts_cb (GObject *source_object, GAsyncResult *result, gpointer uids)
+{
+	GError *error = NULL;
+
+	if (!e_book_client_remove_contacts_finish (E_BOOK_CLIENT (source_object), result, &error)) {
+		report_error ("remove contacts finish", &error);
+		stop_main_loop (1);
+		return;
+	}
+
+	stop_main_loop (check_removed (E_BOOK_CLIENT (source_object), uids) ? 0 : 1);
+}
+
+gint
+main (gint argc, gchar **argv)
+{
+	EBookClient *book_client;
+	GError *error = NULL;
+	GSList *uids;
+
+	main_initialize ();
+
+        /*
+         * Setup
+         */
+	book_client = new_temp_client (NULL);
+	g_return_val_if_fail (book_client != NULL, 1);
+
+	if (!e_client_open_sync (E_CLIENT (book_client), FALSE, NULL, &error)) {
+		report_error ("client open sync", &error);
+		g_object_unref (book_client);
+		return 1;
+	}
+
+        /*
+         * Sync version
+         */
+	if (!fill_book_client (book_client, &uids)) {
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	if (!e_book_client_remove_contacts_sync (book_client, uids, NULL, &error)) {
+		report_error ("remove contact sync", &error);
+		g_object_unref (book_client);
+		g_slist_foreach (uids, (GFunc) g_free, NULL);
+		g_slist_free (uids);
+		return 1;
+	}
+
+	if (!check_removed (book_client, uids)) {
+		g_object_unref (book_client);
+		g_slist_foreach (uids, (GFunc) g_free, NULL);
+		g_slist_free (uids);
+		return 1;
+	}
+
+	g_slist_foreach (uids, (GFunc) g_free, NULL);
+	g_slist_free (uids);
+
+	if (!e_client_remove_sync (E_CLIENT (book_client), NULL, &error)) {
+		report_error ("client remove sync", &error);
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	g_object_unref (book_client);
+
+        /*
+         * Async version
+         */
+	book_client = new_temp_client (NULL);
+	g_return_val_if_fail (book_client != NULL, 1);
+
+	if (!e_client_open_sync (E_CLIENT (book_client), FALSE, NULL, &error)) {
+		report_error ("client open sync", &error);
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	if (!fill_book_client (book_client, &uids)) {
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	e_book_client_remove_contacts (book_client, uids, NULL, remove_contacts_cb, uids);
+
+	start_main_loop (NULL, NULL);
+
+	g_slist_foreach (uids, (GFunc) g_free, NULL);
+	g_slist_free (uids);
+
+	if (!e_client_remove_sync (E_CLIENT (book_client), NULL, &error)) {
+		report_error ("client remove sync", &error);
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	g_object_unref (book_client);
+
+	return get_main_loop_stop_result ();
+}
diff --git a/tests/libebook/client/test-client-remove.c b/tests/libebook/client/test-client-remove.c
new file mode 100644
index 0000000..a463f4b
--- /dev/null
+++ b/tests/libebook/client/test-client-remove.c
@@ -0,0 +1,69 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <stdlib.h>
+#include <libebook/e-book-client.h>
+
+#include "client-test-utils.h"
+
+static void
+client_removed_cb (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	GError *error = NULL;
+
+	if (!e_client_remove_finish (E_CLIENT (source_object), result, &error)) {
+		report_error ("client remove finish", &error);
+		stop_main_loop (1);
+	} else {
+		stop_main_loop (0);
+	}
+}
+
+gint
+main (gint argc, gchar **argv)
+{
+	EBookClient *book_client;
+	GError *error = NULL;
+
+	main_initialize ();
+
+	book_client = new_temp_client (NULL);
+	g_return_val_if_fail (book_client != NULL, 1);
+
+	if (!e_client_open_sync (E_CLIENT (book_client), FALSE, NULL, &error)) {
+		report_error ("client open sync", &error);
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	/*
+	 * Sync version
+	 */
+	if (!e_client_remove_sync (E_CLIENT (book_client), NULL, &error)) {
+		report_error ("client remove sync", &error);
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	g_object_unref (book_client);
+
+	/*
+	 * Async version
+	 */
+
+	book_client = new_temp_client (NULL);
+	g_return_val_if_fail (book_client != NULL, 1);
+
+	if (!e_client_open_sync (E_CLIENT (book_client), FALSE, NULL, &error)) {
+		report_error ("client open sync", &error);
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	e_client_remove (E_CLIENT (book_client), NULL, client_removed_cb, NULL);
+
+	start_main_loop (NULL, NULL);
+
+	g_object_unref (book_client);
+
+	return get_main_loop_stop_result ();
+}
diff --git a/tests/libebook/client/test-client-search.c b/tests/libebook/client/test-client-search.c
new file mode 100644
index 0000000..f9b0c81
--- /dev/null
+++ b/tests/libebook/client/test-client-search.c
@@ -0,0 +1,67 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <stdlib.h>
+#include <libebook/e-book-client.h>
+#include <libebook/e-book-query.h>
+
+#include "client-test-utils.h"
+
+gint
+main (gint argc, gchar **argv)
+{
+	EBookClient *book_client;
+	const gchar *query_string;
+	EBookQuery *query;
+	gchar *sexp;
+	GSList *c, *contacts;
+	GError *error = NULL;
+
+	main_initialize ();
+
+	if (argc != 2) {
+		query_string = "contains \"full_name\" \"a\"";
+		printf ("usage: test-search <query>\n");
+		printf ("   using default query \"%s\"\n", query_string);
+	} else {
+		query_string = argv[1];
+	}
+
+	query = e_book_query_from_string (query_string);
+	if (!query) {
+		fprintf (stderr, " * Failed to parse query string '%s'\n", query_string);
+		return 1;
+	}
+
+	sexp = e_book_query_to_string (query);
+	e_book_query_unref (query);
+
+	book_client = open_system_book (FALSE);
+	if (!book_client) {
+		g_free (sexp);
+		return 1;
+	}
+
+	if (!e_book_client_get_contacts_sync (book_client, sexp, &contacts, NULL, &error)) {
+		report_error ("get contacts sync", &error);
+		g_free (sexp);
+		g_object_unref (book_client);
+		return 1;
+	}
+
+	for (c = contacts; c; c = c->next) {
+		EContact *contact = E_CONTACT (c->data);
+		gchar *vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
+
+		printf ("%s\n\n", vcard);
+
+		g_free (vcard);
+	}
+
+	g_slist_foreach (contacts, (GFunc) g_object_unref, NULL);
+	g_slist_free (contacts);
+
+	g_free (sexp);
+	g_object_unref (book_client);
+
+	return 0;
+}
diff --git a/tests/libebook/client/test-client-self.c b/tests/libebook/client/test-client-self.c
new file mode 100644
index 0000000..f0867a1
--- /dev/null
+++ b/tests/libebook/client/test-client-self.c
@@ -0,0 +1,46 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <stdlib.h>
+#include <libebook/e-book-client.h>
+
+#include "client-test-utils.h"
+
+gint
+main (gint argc, gchar **argv)
+{
+	EBookClient *book_client = NULL;
+	EContact *contact = NULL;
+	GError *error = NULL;
+	gchar *vcard;
+
+	main_initialize ();
+
+	printf ("getting the self contact\n");
+
+	if (!e_book_client_get_self (&contact, &book_client, &error)) {
+		report_error ("get self", &error);
+		return 1;
+	}
+
+	if (!contact) {
+		fprintf (stderr, " * Self contact not set\n");
+		if (book_client)
+			g_object_unref (book_client);
+		return 0;
+	}
+
+	if (!book_client) {
+		fprintf (stderr, " * Book client for a self contact not returned\n");
+		g_object_unref (contact);
+		return 1;
+	}
+
+	vcard = e_vcard_to_string (E_VCARD (contact), EVC_FORMAT_VCARD_30);
+	printf ("self contact = \n%s\n", vcard);
+	g_free (vcard);
+
+	g_object_unref (contact);
+	g_object_unref (book_client);
+
+	return 0;
+}
diff --git a/tests/libebook/client/test-client-stress-factory--fifo.c b/tests/libebook/client/test-client-stress-factory--fifo.c
new file mode 100644
index 0000000..240142c
--- /dev/null
+++ b/tests/libebook/client/test-client-stress-factory--fifo.c
@@ -0,0 +1,50 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <stdlib.h>
+#include <libebook/e-book-client.h>
+
+#include "client-test-utils.h"
+
+#define NUM_CLIENTS 200
+
+gint
+main (gint argc, gchar **argv)
+{
+	EBookClient *book_clients[NUM_CLIENTS];
+	GError *error = NULL;
+	gint ii;
+
+	main_initialize ();
+
+	/* Create and open many books; then remove each of them */
+
+	for (ii = 0; ii < NUM_CLIENTS; ii++) {
+		book_clients[ii] = new_temp_client (NULL);
+		g_return_val_if_fail (book_clients[ii] != NULL, 1);
+
+		if (!e_client_open_sync (E_CLIENT (book_clients[ii]), FALSE, NULL, &error)) {
+			report_error ("client open sync", &error);
+			while (ii >= 0) {
+				g_object_unref (book_clients[ii]);
+				ii--;
+			}
+
+			return 1;
+		}
+	}
+
+	for (ii = 0; ii < NUM_CLIENTS; ii++) {
+		if (!e_client_remove_sync (E_CLIENT (book_clients[ii]), NULL, &error)) {
+			report_error ("client remove sync", &error);
+			while (ii < NUM_CLIENTS) {
+				g_object_unref (book_clients[ii]);
+				ii++;
+			}
+			return 1;
+		}
+
+		g_object_unref (book_clients[ii]);
+	}
+
+	return 0;
+}
diff --git a/tests/libebook/client/test-client-stress-factory--serial.c b/tests/libebook/client/test-client-stress-factory--serial.c
new file mode 100644
index 0000000..7a76ae5
--- /dev/null
+++ b/tests/libebook/client/test-client-stress-factory--serial.c
@@ -0,0 +1,37 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <libebook/e-book-client.h>
+
+#include "client-test-utils.h"
+
+#define NUM_CLIENTS 200
+
+gint
+main (gint argc, gchar **argv)
+{
+	GError *error = NULL;
+	gint ii;
+
+	main_initialize ();
+
+	/* Serially create, open, (close), and remove many books */
+	for (ii = 0; ii < NUM_CLIENTS; ii++) {
+		EBookClient *book_client = new_temp_client (NULL);
+		g_return_val_if_fail (book_client != NULL, 1);
+
+		if (!e_client_open_sync (E_CLIENT (book_client), FALSE, NULL, &error)) {
+			report_error ("client open sync", &error);
+			return 1;
+		}
+
+		if (!e_client_remove_sync (E_CLIENT (book_client), NULL, &error)) {
+			report_error ("client remove sync", &error);
+			g_object_unref (book_client);
+			return 1;
+		}
+
+		g_object_unref (book_client);
+	}
+
+	return 0;
+}
diff --git a/tests/libebook/client/test-client-stress-factory--single-book.c b/tests/libebook/client/test-client-stress-factory--single-book.c
new file mode 100644
index 0000000..919d67a
--- /dev/null
+++ b/tests/libebook/client/test-client-stress-factory--single-book.c
@@ -0,0 +1,62 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <stdlib.h>
+#include <libebook/e-book-client.h>
+
+#include "client-test-utils.h"
+
+#define NUM_OPENS 200
+
+gint
+main (gint argc, gchar **argv)
+{
+	gchar *uri = NULL;
+	EBookClient *book_client;
+	GError *error = NULL;
+	gint ii;
+
+	main_initialize ();
+
+	book_client = new_temp_client (&uri);
+	g_return_val_if_fail (book_client != NULL, 1);
+	g_return_val_if_fail (uri != NULL, 1);
+
+	g_object_unref (book_client);
+
+	/* open and close the same book repeatedly */
+	for (ii = 0; ii < NUM_OPENS; ii++) {
+		book_client = e_book_client_new_from_uri (uri, &error);
+		if (!book_client) {
+			report_error ("new from uri", &error);
+			break;
+		}
+
+		if (!e_client_open_sync (E_CLIENT (book_client), FALSE, NULL, &error)) {
+			report_error ("client open sync", &error);
+			g_object_unref (book_client);
+			break;
+		}
+
+		g_object_unref (book_client);
+	}
+
+	book_client = e_book_client_new_from_uri (uri, &error);
+	if (!book_client) {
+		g_clear_error (&error);
+	} else if (!e_client_open_sync (E_CLIENT (book_client), FALSE, NULL, &error)) {
+		report_error ("client open sync", &error);
+		g_object_unref (book_client);
+		g_free (uri);
+		return 1;
+	} else 	if (!e_client_remove_sync (E_CLIENT (book_client), NULL, &error)) {
+		report_error ("client remove sync", &error);
+		g_object_unref (book_client);
+		g_free (uri);
+		return 1;
+	}
+
+	g_free (uri);
+	g_object_unref (book_client);
+
+	return ii == NUM_OPENS ? 0 : 1;
+}
diff --git a/tests/libebook/client/test-client-stress-views.c b/tests/libebook/client/test-client-stress-views.c
new file mode 100644
index 0000000..e6638da
--- /dev/null
+++ b/tests/libebook/client/test-client-stress-views.c
@@ -0,0 +1,128 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <stdlib.h>
+#include <libebook/e-book-client.h>
+#include <libebook/e-book-query.h>
+
+#include "client-test-utils.h"
+
+#define NUM_VIEWS 200
+
+static void
+objects_added (EBookClientView *view, const GSList *contacts)
+{
+	const GSList *l;
+
+	for (l = contacts; l; l = l->next) {
+		print_email (l->data);
+	}
+}
+
+static void
+objects_removed (EBookClientView *view, const GSList *ids)
+{
+	const GSList *l;
+
+	for (l = ids; l; l = l->next) {
+		printf ("   Removed contact: %s\n", (gchar *) l->data);
+	}
+}
+
+static void
+complete (EBookClientView *view, const GError *error)
+{
+	printf ("view_complete (status == %d, error_msg == %s%s%s)\n", error ? error->code : 0, error ? "'" : "", error ? error->message : "NULL", error ? "'" : "");
+}
+
+static gint
+stress_book_views (EBookClient *book_client, gboolean in_thread)
+{
+	EBookQuery *query;
+	EBookClientView *view = NULL;
+	EBookClientView *new_view;
+	gchar *sexp;
+	gint i;
+
+	g_return_val_if_fail (book_client != NULL, -1);
+	g_return_val_if_fail (E_IS_BOOK_CLIENT (book_client), -1);
+
+	query = e_book_query_any_field_contains ("");
+	sexp = e_book_query_to_string (query);
+	e_book_query_unref (query);
+
+	for (i = 0; i < NUM_VIEWS; i++) {
+		GError *error = NULL;
+
+		if (!e_book_client_get_view_sync (book_client, sexp, &new_view, NULL, &error)) {
+			report_error ("get book view sync", &error);
+			g_object_unref (view);
+			g_free (sexp);
+			return 1;
+		}
+
+		g_signal_connect (new_view, "objects-added", G_CALLBACK (objects_added), NULL);
+		g_signal_connect (new_view, "objects-removed", G_CALLBACK (objects_removed), NULL);
+		g_signal_connect (new_view, "complete", G_CALLBACK (complete), NULL);
+
+		e_book_client_view_start (new_view, NULL);
+
+		if (view) {
+			/* wait 100 ms when in a thread */
+			if (in_thread)
+				g_usleep (100000);
+
+			e_book_client_view_stop (view, NULL);
+			g_object_unref (view);
+		}
+
+		view = new_view;
+	}
+
+	e_book_client_view_stop (view, NULL);
+	g_object_unref (view);
+
+	g_free (sexp);
+
+	return 0;
+}
+
+static gpointer
+stress_book_views_thread (gpointer user_data)
+{
+	stop_main_loop (stress_book_views (user_data, TRUE));
+
+	return NULL;
+}
+
+gint
+main (gint argc, gchar **argv)
+{
+	EBookClient *book_client;
+	GError *error = NULL;
+
+	main_initialize ();
+
+	printf ("loading addressbook\n");
+
+	book_client = e_book_client_new_system (&error);
+	if (!book_client) {
+		report_error ("create local addressbook", &error);
+		return 1;
+	}
+
+	if (!e_client_open_sync (E_CLIENT (book_client), FALSE, NULL, &error)) {
+		g_object_unref (book_client);
+		report_error ("open client sync", &error);
+		return 1;
+	}
+
+	/* test from main thread */
+	stress_book_views (book_client, FALSE);
+
+	/* test from dedicated thread */
+	start_in_thread_with_main_loop (stress_book_views_thread, book_client);
+
+	g_object_unref (book_client);
+
+	return get_main_loop_stop_result ();
+}
diff --git a/tests/libebook/client/test-client.c b/tests/libebook/client/test-client.c
new file mode 100644
index 0000000..45011ab
--- /dev/null
+++ b/tests/libebook/client/test-client.c
@@ -0,0 +1,82 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <stdlib.h>
+#include <libebook/e-book-client.h>
+#include <libebook/e-book-query.h>
+
+#include "client-test-utils.h"
+
+static void
+print_all_emails (EBookClient *book)
+{
+	GError *error = NULL;
+	EBookQuery *query;
+	gchar *sexp;
+	gboolean result;
+	GSList *cards, *c;
+
+	query = e_book_query_field_exists (E_CONTACT_FULL_NAME);
+	sexp = e_book_query_to_string (query);
+	e_book_query_unref (query);
+
+	result = e_book_client_get_contacts_sync (book, sexp, &cards, NULL, &error);
+
+	g_free (sexp);
+
+	if (!result) {
+		fprintf (stderr, "Error getting card list: %s\n", error ? error->message : "Unknown error");
+		if (error)
+			g_error_free (error);
+		exit (1);
+	}
+
+	for (c = cards; c; c = c->next) {
+		EContact *contact = E_CONTACT (c->data);
+
+		print_email (contact);
+
+		g_object_unref (contact);
+	}
+
+	g_slist_free (cards);
+}
+
+static void
+print_one_email (EBookClient *book_client)
+{
+	EContact *contact;
+	GError *error = NULL;
+
+	if (!e_book_client_get_contact_sync (book_client, "pas-id-0002023", &contact, NULL, &error)) {
+		report_error ("get_contact_sync", &error);
+		return;
+	}
+
+	print_email (contact);
+
+	g_object_unref (contact);
+}
+
+gint
+main (gint argc, gchar **argv)
+{
+	EBookClient *book_client;
+
+	main_initialize ();
+
+	printf ("loading addressbook\n");
+
+	book_client = open_system_book (FALSE);
+	if (!book_client)
+		return 1;
+
+	printf ("printing one contact\n");
+	print_one_email (book_client);
+
+	printf ("printing all contacts\n");
+	print_all_emails (book_client);
+
+	g_object_unref (book_client);
+
+	return 0;
+}
diff --git a/tests/libebook/test-categories.c b/tests/libebook/test-categories.c
index bf24a74..2b73b6a 100644
--- a/tests/libebook/test-categories.c
+++ b/tests/libebook/test-categories.c
@@ -1,6 +1,6 @@
 #include <stdlib.h>
 #include <string.h>
-#include <libebook/e-book.h>
+#include <libebook/e-contact.h>
 
 gint
 main (gint argc, gchar **argv)
diff --git a/tests/libebook/test-date.c b/tests/libebook/test-date.c
index c2c6ad8..caf90a5 100644
--- a/tests/libebook/test-date.c
+++ b/tests/libebook/test-date.c
@@ -1,5 +1,5 @@
 #include <stdlib.h>
-#include <libebook/e-book.h>
+#include <libebook/e-contact.h>
 
 gint
 main (gint argc, gchar **argv)
diff --git a/tests/libebook/test-photo.c b/tests/libebook/test-photo.c
index 8848b9b..2200689 100644
--- a/tests/libebook/test-photo.c
+++ b/tests/libebook/test-photo.c
@@ -1,6 +1,6 @@
 #include <stdlib.h>
 #include <string.h>
-#include <libebook/e-book.h>
+#include <libebook/e-contact.h>
 
 static const gchar *photo_data =
 "/9j/4AAQSkZJRgABAQEARwBHAAD//gAXQ3JlYXRlZCB3aXRoIFRoZSBHSU1Q/9sAQwAIBgYHB\
diff --git a/tests/libebook/test-query.c b/tests/libebook/test-query.c
index 33c6143..44b593d 100644
--- a/tests/libebook/test-query.c
+++ b/tests/libebook/test-query.c
@@ -1,5 +1,5 @@
 #include <string.h>
-#include <libebook/e-book.h>
+#include <libebook/e-book-query.h>
 
 #define QUERY_STRING1
 #define QUERY_STRING2
diff --git a/tests/libebook/test-string.c b/tests/libebook/test-string.c
index 953802e..b958eac 100644
--- a/tests/libebook/test-string.c
+++ b/tests/libebook/test-string.c
@@ -1,6 +1,6 @@
 #include <stdlib.h>
 #include <string.h>
-#include <libebook/e-book.h>
+#include <libebook/e-contact.h>
 
 #define TEST_ID "test-uid"
 
diff --git a/tests/libebook/test-undefinedfield.c b/tests/libebook/test-undefinedfield.c
index 75e1dc0..03a393b 100644
--- a/tests/libebook/test-undefinedfield.c
+++ b/tests/libebook/test-undefinedfield.c
@@ -1,5 +1,5 @@
 #include <stdlib.h>
-#include <libebook/e-book.h>
+#include <libebook/e-contact.h>
 
 gint
 main (gint argc, gchar **argv)
diff --git a/tests/libebook/test-untyped-phones.c b/tests/libebook/test-untyped-phones.c
index 8ebb8f9..c5ef691 100644
--- a/tests/libebook/test-untyped-phones.c
+++ b/tests/libebook/test-untyped-phones.c
@@ -1,6 +1,6 @@
 #include <stdlib.h>
 #include <string.h>
-#include <libebook/e-book.h>
+#include <libebook/e-contact.h>
 
 /* TEL;WORK:... should map to PHONE_BUSINESS
    TEL;FAX:... should map to OTHER_FAX. */
diff --git a/tests/libecal/Makefile.am b/tests/libecal/Makefile.am
index e1fbff0..4227613 100644
--- a/tests/libecal/Makefile.am
+++ b/tests/libecal/Makefile.am
@@ -1,3 +1,5 @@
+SUBDIRS = client
+
 noinst_LTLIBRARIES = libecal-test-utils.la
 libecal_test_utils_la_SOURCES = ecal-test-utils.c ecal-test-utils.h
 
diff --git a/tests/libecal/client/Makefile.am b/tests/libecal/client/Makefile.am
new file mode 100644
index 0000000..9b9d08c
--- /dev/null
+++ b/tests/libecal/client/Makefile.am
@@ -0,0 +1,89 @@
+noinst_LTLIBRARIES = libclient-test-utils.la
+
+libclient_test_utils_la_SOURCES = client-test-utils.c client-test-utils.h
+
+libclient_test_utils_la_CPPFLAGS =				\
+	$(AM_CPPFLAGS)						\
+	-I$(top_srcdir)						\
+	-I$(top_builddir)					\
+	-I$(top_srcdir)/calendar				\
+	-I$(top_builddir)/calendar				\
+	-DSRCDIR=\""$(srcdir)"\"				\
+	$(EVOLUTION_CALENDAR_CFLAGS)				\
+	$(NULL)
+
+libclient_test_utils_la_LIBADD = 				\
+	$(top_builddir)/calendar/libecal/libecal-1.2.la		\
+	$(EVOLUTION_CALENDAR_LIBS)				\
+	$(NULL)
+
+# ordered by relative complexity
+TESTS = 					\
+	test-client-open			\
+	test-client-refresh			\
+	test-client-get-free-busy		\
+	test-client-add-timezone		\
+	test-client-examine			\
+	test-client-create-object		\
+	test-client-remove-object		\
+	test-client-get-object-list		\
+	test-client-modify-object		\
+	test-client-send-objects		\
+	test-client-receive-objects		\
+	test-client-get-attachment-uris		\
+	test-client-get-view			\
+	test-client-stress-views		\
+	test-client-stress-factory--serial	\
+	test-client-stress-factory--fifo	\
+	test-client-stress-factory--single-cal	\
+	$(NULL)
+
+# The test program
+noinst_PROGRAMS = $(TESTS)
+
+TEST_CPPFLAGS=					\
+	$(libclient_test_utils_la_CPPFLAGS)	\
+	$(NULL)
+
+TEST_LIBS =					\
+	$(libclient_test_utils_la_LIBS)		\
+	libclient-test-utils.la			\
+	$(NULL)
+
+# ordered alphanumerically
+test_client_add_timezone_LDADD=$(TEST_LIBS)
+test_client_add_timezone_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_create_object_LDADD=$(TEST_LIBS)
+test_client_create_object_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_examine_LDADD=$(TEST_LIBS)
+test_client_examine_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_get_attachment_uris_LDADD=$(TEST_LIBS)
+test_client_get_attachment_uris_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_get_free_busy_LDADD=$(TEST_LIBS)
+test_client_get_free_busy_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_get_object_list_LDADD=$(TEST_LIBS)
+test_client_get_object_list_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_get_view_LDADD=$(TEST_LIBS)
+test_client_get_view_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_modify_object_LDADD=$(TEST_LIBS)
+test_client_modify_object_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_open_LDADD=$(TEST_LIBS)
+test_client_open_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_receive_objects_LDADD=$(TEST_LIBS)
+test_client_receive_objects_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_refresh_LDADD=$(TEST_LIBS)
+test_client_refresh_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_remove_object_LDADD=$(TEST_LIBS)
+test_client_remove_object_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_send_objects_LDADD=$(TEST_LIBS)
+test_client_send_objects_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_stress_factory__fifo_LDADD=$(TEST_LIBS)
+test_client_stress_factory__fifo_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_stress_factory__serial_LDADD=$(TEST_LIBS)
+test_client_stress_factory__serial_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_stress_factory__single_cal_LDADD=$(TEST_LIBS)
+test_client_stress_factory__single_cal_CPPFLAGS=$(TEST_CPPFLAGS)
+test_client_stress_views_LDADD=$(TEST_LIBS)
+test_client_stress_views_CPPFLAGS=$(TEST_CPPFLAGS)
+
+-include $(top_srcdir)/git.mk
diff --git a/tests/libecal/client/client-test-utils.c b/tests/libecal/client/client-test-utils.c
new file mode 100644
index 0000000..4ff6915
--- /dev/null
+++ b/tests/libecal/client/client-test-utils.c
@@ -0,0 +1,350 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <stdio.h>
+
+#include "client-test-utils.h"
+
+void
+print_ecomp (ECalComponent *ecalcomp)
+{
+	const gchar *uid = NULL;
+	ECalComponentText summary = { 0 };
+
+	g_return_if_fail (ecalcomp != NULL);
+
+	e_cal_component_get_uid (ecalcomp, &uid);
+	e_cal_component_get_summary (ecalcomp, &summary);
+
+	g_print ("   Component: %s\n", uid ? uid : "no-uid");
+	g_print ("   Summary: %s\n", summary.value ? summary.value : "NULL");
+	g_print ("\n");
+}
+
+void
+print_icomp (icalcomponent *icalcomp)
+{
+	ECalComponent *ecomp;
+
+	g_return_if_fail (icalcomp != NULL);
+
+	ecomp = e_cal_component_new ();
+	icalcomp = icalcomponent_new_clone (icalcomp);
+
+	if (!e_cal_component_set_icalcomponent (ecomp, icalcomp)) {
+		icalcomponent_free (icalcomp);
+		g_object_unref (ecomp);
+		g_printerr ("%s: Failed to assing icalcomp to ECalComponent\n", G_STRFUNC);
+		g_print ("\n");
+		return;
+	}
+
+	print_ecomp (ecomp);
+
+	g_object_unref (ecomp);
+}
+
+void
+report_error (const gchar *operation, GError **error)
+{
+	g_return_if_fail (operation != NULL);
+
+	g_printerr ("Failed to %s: %s\n", operation, (error && *error) ? (*error)->message : "Unknown error");
+
+	g_clear_error (error);
+}
+
+void
+main_initialize (void)
+{
+	static gboolean initialized = FALSE;
+
+	if (initialized)
+		return;
+
+	g_type_init ();
+	g_thread_init (NULL);
+
+	initialized = TRUE;
+}
+
+struct IdleData {
+	GThreadFunc func;
+	gpointer data;
+	gboolean run_in_thread; /* FALSE to run in idle callback */
+};
+
+static gboolean
+idle_cb (gpointer data)
+{
+	struct IdleData *idle = data;
+
+	g_return_val_if_fail (idle != NULL, FALSE);
+	g_return_val_if_fail (idle->func != NULL, FALSE);
+
+	if (idle->run_in_thread) {
+		GError *error = NULL;
+
+		g_thread_create (idle->func, idle->data, FALSE, &error);
+
+		if (error) {
+			report_error ("create thread", &error);
+			stop_main_loop (1);
+		}
+	} else {
+		idle->func (idle->data);
+	}
+
+	g_free (idle);
+
+	return FALSE;
+}
+
+static GMainLoop *loop = NULL;
+static gint main_stop_result = 0;
+
+static void
+do_start (GThreadFunc func, gpointer data)
+{
+	main_initialize ();
+
+	g_return_if_fail (loop == NULL);
+
+	loop = g_main_loop_new (NULL, FALSE);
+
+	if (func)
+		func (data);
+
+	g_main_loop_run (loop);
+
+	g_main_loop_unref (loop);
+	loop = NULL;
+}
+
+/* Starts new main-loop, but just before that calls 'func'.
+   Main-loop is kept running, and this function blocks, 
+   until call of stop_main_loop().
+*/
+void
+start_main_loop (GThreadFunc func, gpointer data)
+{
+	g_return_if_fail (loop == NULL);
+
+	do_start (func, data);
+}
+
+/* Starts new main-loop and then invokes func in a new thread.
+   Main-loop is kept running, and this function blocks, 
+   until call of stop_main_loop().
+*/
+void
+start_in_thread_with_main_loop (GThreadFunc func, gpointer data)
+{
+	struct IdleData *idle;
+
+	g_return_if_fail (func != NULL);
+	g_return_if_fail (loop == NULL);
+
+	main_initialize ();
+
+	idle = g_new0 (struct IdleData, 1);
+	idle->func = func;
+	idle->data = data;
+	idle->run_in_thread = TRUE;
+
+	g_idle_add (idle_cb, idle);
+
+	do_start (NULL, NULL);
+}
+
+/* Starts new main-loop and then invokes func in an idle callback.
+   Main-loop is kept running, and this function blocks, 
+   until call of stop_main_loop().
+*/
+void
+start_in_idle_with_main_loop (GThreadFunc func, gpointer data)
+{
+	struct IdleData *idle;
+
+	g_return_if_fail (func != NULL);
+	g_return_if_fail (loop == NULL);
+
+	main_initialize ();
+
+	idle = g_new0 (struct IdleData, 1);
+	idle->func = func;
+	idle->data = data;
+	idle->run_in_thread = FALSE;
+
+	g_idle_add (idle_cb, idle);
+
+	do_start (NULL, NULL);
+}
+
+/* Stops main-loop previously run by start_main_loop,
+   start_in_thread_with_main_loop or start_in_idle_with_main_loop.
+*/
+void
+stop_main_loop (gint stop_result)
+{
+	g_return_if_fail (loop != NULL);
+
+	main_stop_result = stop_result;
+	g_main_loop_quit (loop);
+}
+
+/* returns value used in stop_main_loop() */
+gint
+get_main_loop_stop_result (void)
+{
+	return main_stop_result;
+}
+
+void
+foreach_configured_source (ECalClientSourceType source_type, void (*func) (ESource *source, ECalClientSourceType source_type))
+{
+	gpointer foreach_async_data;
+	ESource *source = NULL;
+
+	g_return_if_fail (func != NULL);
+
+	main_initialize ();
+
+	foreach_async_data = foreach_configured_source_async_start (source_type, &source);
+	if (!foreach_async_data)
+		return;
+
+	do {
+		func (source, source_type);
+	} while (foreach_configured_source_async_next (&foreach_async_data, &source));
+}
+
+struct ForeachConfiguredData
+{
+	ECalClientSourceType source_type;
+	ESourceList *source_list;
+	GSList *current_group;
+	GSList *current_source;
+};
+
+gpointer
+foreach_configured_source_async_start (ECalClientSourceType source_type, ESource **source)
+{
+	struct ForeachConfiguredData *async_data;
+	ESourceList *source_list = NULL;
+	GError *error = NULL;
+
+	g_return_val_if_fail (source != NULL, NULL);
+
+	main_initialize ();
+
+	if (!e_cal_client_get_sources (&source_list, source_type, &error)) {
+		report_error ("get addressbooks", &error);
+		return NULL;
+	}
+
+	g_return_val_if_fail (source_list != NULL, NULL);
+
+	async_data = g_new0 (struct ForeachConfiguredData, 1);
+	async_data->source_type = source_type;
+	async_data->source_list = source_list;
+	async_data->current_group = e_source_list_peek_groups (source_list);
+	if (!async_data->current_group) {
+		gpointer ad = async_data;
+
+		foreach_configured_source_async_next (&ad, source);
+		return ad;
+	}
+
+	async_data->current_source = e_source_group_peek_sources (async_data->current_group->data);
+	if (!async_data->current_source) {
+		gpointer ad = async_data;
+
+		if (foreach_configured_source_async_next (&ad, source))
+			return ad;
+
+		return NULL;
+	}
+
+	*source = async_data->current_source->data;
+
+	return async_data;
+}
+
+gboolean
+foreach_configured_source_async_next (gpointer *foreach_async_data, ESource **source)
+{
+	struct ForeachConfiguredData *async_data;
+
+	g_return_val_if_fail (foreach_async_data != NULL, FALSE);
+	g_return_val_if_fail (source != NULL, FALSE);
+
+	async_data = *foreach_async_data;
+	g_return_val_if_fail (async_data != NULL, FALSE);
+	g_return_val_if_fail (async_data->source_list != NULL, FALSE);
+	g_return_val_if_fail (async_data->current_group != NULL, FALSE);
+
+	if (async_data->current_source)
+		async_data->current_source = async_data->current_source->next;
+	if (async_data->current_source) {
+		*source = async_data->current_source->data;
+		return TRUE;
+	}
+
+	do {
+		async_data->current_group = async_data->current_group->next;
+		if (async_data->current_group) {
+			async_data->current_source = e_source_group_peek_sources (async_data->current_group->data);
+		}
+	} while (async_data->current_group && !async_data->current_source);
+
+	if (async_data->current_source) {
+		*source = async_data->current_source->data;
+		return TRUE;
+	}
+
+	g_object_unref (async_data->source_list);
+	g_free (async_data);
+
+	*foreach_async_data = NULL;
+
+	return FALSE;
+}
+
+ECalClientSourceType
+foreach_configured_source_async_get_source_type (gpointer foreach_async_data)
+{
+	struct ForeachConfiguredData *async_data = foreach_async_data;
+
+	g_return_val_if_fail (foreach_async_data != NULL, E_CAL_CLIENT_SOURCE_TYPE_LAST);
+
+	return async_data->source_type;
+}
+
+ECalClient *
+new_temp_client (ECalClientSourceType source_type, gchar **uri)
+{
+	ECalClient *cal_client;
+	ESource *source;
+	gchar *abs_uri, *filename;
+	GError *error = NULL;
+
+	filename = g_build_filename (g_get_tmp_dir (), "e-cal-client-test-XXXXXX/", NULL);
+	abs_uri = g_strconcat ("local:", filename, NULL);
+	g_free (filename);
+
+	source = e_source_new_with_absolute_uri ("Test cal", abs_uri);
+	if (uri)
+		*uri = abs_uri;
+	else
+		g_free (abs_uri);
+
+	g_return_val_if_fail (source != NULL, NULL);
+
+	cal_client = e_cal_client_new (source, source_type, &error);
+	g_object_unref (source);
+
+	if (error)
+		report_error ("new temp client", &error);
+
+	return cal_client;
+}
diff --git a/tests/libecal/client/client-test-utils.h b/tests/libecal/client/client-test-utils.h
new file mode 100644
index 0000000..127a642
--- /dev/null
+++ b/tests/libecal/client/client-test-utils.h
@@ -0,0 +1,25 @@
+#ifndef CLIENT_TEST_UTILS_H
+#define CLIENT_TEST_UTILS_H
+
+#include <glib.h>
+#include <libecal/e-cal-client.h>
+
+void print_ecomp (ECalComponent *ecalcomp);
+void print_icomp (icalcomponent *icalcomp);
+void report_error (const gchar *operation, GError **error);
+
+void main_initialize (void);
+void start_main_loop (GThreadFunc func, gpointer data);
+void start_in_thread_with_main_loop (GThreadFunc func, gpointer data);
+void start_in_idle_with_main_loop (GThreadFunc func, gpointer data);
+void stop_main_loop (gint stop_result);
+gint get_main_loop_stop_result (void);
+
+void foreach_configured_source (ECalClientSourceType source_type, void (*func) (ESource *source, ECalClientSourceType source_type));
+gpointer foreach_configured_source_async_start (ECalClientSourceType source_type, ESource **source);
+gboolean foreach_configured_source_async_next (gpointer *foreach_async_data, ESource **source);
+ECalClientSourceType foreach_configured_source_async_get_source_type (gpointer foreach_async_data);
+
+ECalClient *new_temp_client (ECalClientSourceType source_type, gchar **uri);
+
+#endif /* CLIENT_TEST_UTILS_H */
diff --git a/tests/libecal/client/test-client-add-timezone.c b/tests/libecal/client/test-client-add-timezone.c
new file mode 100644
index 0000000..ece2391
--- /dev/null
+++ b/tests/libecal/client/test-client-add-timezone.c
@@ -0,0 +1,209 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <stdlib.h>
+#include <libecal/e-cal-client.h>
+#include <libical/ical.h>
+
+#include "client-test-utils.h"
+
+#define TZID_NEW "XYZ"
+#define TZNAME_NEW "Ex Wye Zee"
+
+static gboolean
+test_zones (icaltimezone *zone1, icaltimezone *zone2)
+{
+	if (!zone2) {
+		g_printerr ("Failure: get timezone returned NULL\n");
+		return FALSE;
+	}
+
+	if (g_strcmp0 (icaltimezone_get_tzid (zone1), icaltimezone_get_tzid (zone2)) != 0) {
+		g_printerr ("Failure: tzid doesn't match, expected '%s', got '%s'\n", icaltimezone_get_tzid (zone1), icaltimezone_get_tzid (zone2));
+		return FALSE;
+	}
+
+	if (g_strcmp0 (icaltimezone_get_tznames (zone1), icaltimezone_get_tznames (zone2)) != 0) {
+		g_printerr ("Failure: tznames doesn't match, expected '%s', got '%s'\n", icaltimezone_get_tznames (zone1), icaltimezone_get_tznames (zone2));
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static gboolean
+test_sync (icaltimezone *zone)
+{
+	ECalClient *cal_client;
+	icaltimezone *zone2 = NULL;
+	GError *error = NULL;
+	gboolean res;
+
+	g_return_val_if_fail (zone != NULL, FALSE);
+
+	cal_client = new_temp_client (E_CAL_CLIENT_SOURCE_TYPE_EVENTS, NULL);
+	g_return_val_if_fail (cal_client != NULL, FALSE);
+
+	if (!e_client_open_sync (E_CLIENT (cal_client), FALSE, NULL, &error)) {
+		report_error ("client open sync", &error);
+		g_object_unref (cal_client);
+		return FALSE;
+	}
+
+	if (!e_cal_client_add_timezone_sync (cal_client, zone, NULL, &error)) {
+		report_error ("add timezone sync", &error);
+		g_object_unref (cal_client);
+		return FALSE;
+	}
+
+	if (!e_cal_client_get_timezone_sync (cal_client, TZID_NEW, &zone2, NULL, &error)) {
+		report_error ("get timezone sync", &error);
+		g_object_unref (cal_client);
+		return FALSE;
+	}
+
+	res = test_zones (zone, zone2);
+
+	if (!e_client_remove_sync (E_CLIENT (cal_client), NULL, &error)) {
+		report_error ("client remove sync", &error);
+		g_object_unref (cal_client);
+		return FALSE;
+	}
+
+	g_object_unref (cal_client);
+
+	return res;
+}
+
+/* asynchronous read callback with a main-loop running */
+static void
+async_read_result_ready (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	ECalClient *cal_client;
+	GError *error = NULL;
+	icaltimezone *zone1 = user_data, *zone2 = NULL;
+	gboolean res;
+
+	g_return_if_fail (zone1 != NULL);
+
+	cal_client = E_CAL_CLIENT (source_object);
+
+	if (!e_cal_client_get_timezone_finish (cal_client, result, &zone2, &error)) {
+		report_error ("get timezone finish", &error);
+		g_object_unref (cal_client);
+		stop_main_loop (1);
+		return;
+	}
+
+	res = test_zones (zone1, zone2);
+
+	if (!e_client_remove_sync (E_CLIENT (cal_client), NULL, &error)) {
+		report_error ("client remove sync", &error);
+	}
+
+	g_object_unref (cal_client);
+
+	stop_main_loop (res ? 0 : 1);
+}
+
+/* asynchronous write callback with a main-loop running */
+static void
+async_write_result_ready (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	ECalClient *cal_client;
+	GError *error = NULL;
+
+	g_return_if_fail (user_data != NULL);
+
+	cal_client = E_CAL_CLIENT (source_object);
+
+	if (!e_cal_client_add_timezone_finish (cal_client, result, &error)) {
+		report_error ("add timezone finish", &error);
+		g_object_unref (cal_client);
+		stop_main_loop (1);
+		return;
+	}
+
+	e_cal_client_get_timezone (cal_client, TZID_NEW, NULL, async_read_result_ready, user_data);
+}
+
+/* synchronously in idle with main-loop running */
+static gboolean
+test_sync_in_idle (gpointer user_data)
+{
+	ECalClient *cal_client;
+	GError *error = NULL;
+	icaltimezone *zone = user_data;
+
+	g_return_val_if_fail (zone != NULL, FALSE);
+
+	if (!test_sync (zone)) {
+		stop_main_loop (1);
+		return FALSE;
+	}
+
+	cal_client = new_temp_client (E_CAL_CLIENT_SOURCE_TYPE_EVENTS, NULL);
+	g_return_val_if_fail (cal_client != NULL, FALSE);
+
+	if (!e_client_open_sync (E_CLIENT (cal_client), FALSE, NULL, &error)) {
+		report_error ("client open sync", &error);
+		g_object_unref (cal_client);
+		stop_main_loop (1);
+		return FALSE;
+	}
+
+	e_cal_client_add_timezone (cal_client, zone, NULL, async_write_result_ready, zone);
+
+	return FALSE;
+}
+
+/* synchronously in a dedicated thread with main-loop running */
+static gpointer
+test_sync_in_thread (gpointer user_data)
+{
+	icaltimezone *zone = user_data;
+
+	g_return_val_if_fail (zone != NULL, NULL);
+
+	if (!test_sync (zone)) {
+		stop_main_loop (1);
+		return NULL;
+	}
+
+	g_idle_add (test_sync_in_idle, zone);
+
+	return NULL;
+}
+
+gint
+main (gint argc, gchar **argv)
+{
+	icalproperty *property;
+	icalcomponent *component;
+	icaltimezone *zone;
+
+	main_initialize ();
+
+	/* Build up new timezone */
+	component = icalcomponent_new_vtimezone ();
+	property = icalproperty_new_tzid (TZID_NEW);
+	icalcomponent_add_property (component, property);
+	property = icalproperty_new_tzname (TZNAME_NEW);
+	icalcomponent_add_property (component, property);
+	zone = icaltimezone_new ();
+	icaltimezone_set_component (zone, component);
+
+	/* synchronously without main-loop */
+	if (!test_sync (zone)) {
+		icaltimezone_free (zone, TRUE);
+		return 1;
+	}
+
+	start_in_thread_with_main_loop (test_sync_in_thread, zone);
+
+	icaltimezone_free (zone, TRUE);
+
+	if (get_main_loop_stop_result () == 0)
+		g_print ("Test finished successfully.\n");
+
+	return get_main_loop_stop_result ();
+}
diff --git a/tests/libecal/client/test-client-create-object.c b/tests/libecal/client/test-client-create-object.c
new file mode 100644
index 0000000..25af903
--- /dev/null
+++ b/tests/libecal/client/test-client-create-object.c
@@ -0,0 +1,297 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <stdlib.h>
+#include <libecal/e-cal-client.h>
+#include <libical/ical.h>
+
+#include "client-test-utils.h"
+
+static gboolean
+test_icalcomps (icalcomponent *icalcomp1, icalcomponent *icalcomp2)
+{
+	struct icaltimetype t1, t2;
+
+	if (!icalcomp2) {
+		g_printerr ("Failure: get object returned NULL\n");
+		return FALSE;
+	}
+
+	if (g_strcmp0 (icalcomponent_get_uid (icalcomp1), icalcomponent_get_uid (icalcomp2)) != 0) {
+		g_printerr ("Failure: uid doesn't match, expected '%s', got '%s'\n", icalcomponent_get_uid (icalcomp1), icalcomponent_get_uid (icalcomp2));
+		return FALSE;
+	}
+
+	if (g_strcmp0 (icalcomponent_get_summary (icalcomp1), icalcomponent_get_summary (icalcomp2)) != 0) {
+		g_printerr ("Failure: summary doesn't match, expected '%s', got '%s'\n", icalcomponent_get_summary (icalcomp1), icalcomponent_get_summary (icalcomp2));
+		return FALSE;
+	}
+
+	t1 = icalcomponent_get_dtstart (icalcomp1);
+	t2 = icalcomponent_get_dtstart (icalcomp2);
+
+	if (icaltime_compare (t1, t2) != 0) {
+		g_printerr ("Failure: dtend doesn't match, expected '%s', got '%s'\n", icaltime_as_ical_string (t1), icaltime_as_ical_string (t2));
+		return FALSE;
+	}
+
+	t1 = icalcomponent_get_dtend (icalcomp1);
+	t2 = icalcomponent_get_dtend (icalcomp2);
+
+	if (icaltime_compare (t1, t2) != 0) {
+		g_printerr ("Failure: dtend doesn't match, expected '%s', got '%s'\n", icaltime_as_ical_string (t1), icaltime_as_ical_string (t2));
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static gboolean
+test_sync (icalcomponent *icalcomp)
+{
+	ECalClient *cal_client;
+	icalcomponent *icalcomp2 = NULL, *clone;
+	GError *error = NULL;
+	gchar *uid = NULL;
+	gboolean res;
+
+	g_return_val_if_fail (icalcomp != NULL, FALSE);
+
+	cal_client = new_temp_client (E_CAL_CLIENT_SOURCE_TYPE_EVENTS, NULL);
+	g_return_val_if_fail (cal_client != NULL, FALSE);
+
+	if (!e_client_open_sync (E_CLIENT (cal_client), FALSE, NULL, &error)) {
+		report_error ("client open sync", &error);
+		g_object_unref (cal_client);
+		return FALSE;
+	}
+
+	if (!e_cal_client_create_object_sync (cal_client, icalcomp, &uid, NULL, &error)) {
+		report_error ("create object sync", &error);
+		g_object_unref (cal_client);
+		return FALSE;
+	}
+
+	if (!e_cal_client_get_object_sync (cal_client, uid, NULL, &icalcomp2, NULL, &error)) {
+		report_error ("get object sync", &error);
+		g_free (uid);
+		g_object_unref (cal_client);
+		return FALSE;
+	}
+
+	clone = icalcomponent_new_clone (icalcomp);
+	icalcomponent_set_uid (clone, uid);
+
+	res = test_icalcomps (clone, icalcomp2);
+
+	icalcomponent_free (icalcomp2);
+
+	if (res) {
+		GSList *ecalcomps = NULL;
+	
+		if (!e_cal_client_get_objects_for_uid_sync (cal_client, uid, &ecalcomps, NULL, &error)) {
+			report_error ("get objects for uid sync", &error);
+			res = FALSE;
+		}
+
+		if (g_slist_length (ecalcomps) != 1) {
+			g_printerr ("Failure: expected 1 component, bug got %d\n", g_slist_length (ecalcomps));
+			res = FALSE;
+		} else {
+			ECalComponent *ecalcomp = ecalcomps->data;
+
+			res = test_icalcomps (clone, e_cal_component_get_icalcomponent (ecalcomp));
+		}
+
+		e_cal_client_free_ecalcomp_slist (ecalcomps);
+	}
+
+	icalcomponent_free (clone);
+	g_free (uid);
+
+	if (!e_client_remove_sync (E_CLIENT (cal_client), NULL, &error)) {
+		report_error ("client remove sync", &error);
+		g_object_unref (cal_client);
+		return FALSE;
+	}
+
+	g_object_unref (cal_client);
+
+	return res;
+}
+
+/* asynchronous read2 callback with a main-loop running */
+static void
+async_read2_result_ready (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	ECalClient *cal_client;
+	GError *error = NULL;
+	icalcomponent *icalcomp1 = user_data;
+	GSList *ecalcomps = NULL;
+	gboolean res;
+
+	g_return_if_fail (icalcomp1 != NULL);
+
+	cal_client = E_CAL_CLIENT (source_object);
+
+	if (!e_cal_client_get_objects_for_uid_finish (cal_client, result, &ecalcomps, &error)) {
+		report_error ("get objects for uid finish", &error);
+		g_object_unref (cal_client);
+		icalcomponent_free (icalcomp1);
+		stop_main_loop (1);
+		return;
+	}
+
+	if (g_slist_length (ecalcomps) != 1) {
+		g_printerr ("Failure: expected 1 component, bug got %d\n", g_slist_length (ecalcomps));
+		res = FALSE;
+	} else {
+		ECalComponent *ecalcomp = ecalcomps->data;
+
+		res = test_icalcomps (icalcomp1, e_cal_component_get_icalcomponent (ecalcomp));
+	}
+
+	e_cal_client_free_ecalcomp_slist (ecalcomps);
+
+	if (!e_client_remove_sync (E_CLIENT (cal_client), NULL, &error)) {
+		report_error ("client remove sync", &error);
+	}
+
+	g_object_unref (cal_client);
+	icalcomponent_free (icalcomp1);
+
+	stop_main_loop (res ? 0 : 1);
+}
+
+/* asynchronous read callback with a main-loop running */
+static void
+async_read_result_ready (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	ECalClient *cal_client;
+	GError *error = NULL;
+	icalcomponent *icalcomp1 = user_data, *icalcomp2 = NULL;
+
+	g_return_if_fail (icalcomp1 != NULL);
+
+	cal_client = E_CAL_CLIENT (source_object);
+
+	if (!e_cal_client_get_object_finish (cal_client, result, &icalcomp2, &error)) {
+		report_error ("get object finish", &error);
+		g_object_unref (cal_client);
+		icalcomponent_free (icalcomp1);
+		stop_main_loop (1);
+		return;
+	}
+
+	test_icalcomps (icalcomp1, icalcomp2);
+
+	icalcomponent_free (icalcomp2);
+
+	e_cal_client_get_objects_for_uid (cal_client, icalcomponent_get_uid (icalcomp1), NULL, async_read2_result_ready, icalcomp1);
+}
+
+/* asynchronous write callback with a main-loop running */
+static void
+async_write_result_ready (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	ECalClient *cal_client;
+	GError *error = NULL;
+	gchar *uid = NULL;
+	icalcomponent *clone, *icalcomp = user_data;
+
+	g_return_if_fail (icalcomp != NULL);
+
+	cal_client = E_CAL_CLIENT (source_object);
+
+	if (!e_cal_client_create_object_finish (cal_client, result, &uid, &error)) {
+		report_error ("create object finish", &error);
+		g_object_unref (cal_client);
+		stop_main_loop (1);
+		return;
+	}
+
+	clone = icalcomponent_new_clone (icalcomp);
+	icalcomponent_set_uid (clone, uid);
+
+	e_cal_client_get_object (cal_client, uid, NULL, NULL, async_read_result_ready, clone);
+
+	g_free (uid);
+}
+
+/* synchronously in idle with main-loop running */
+static gboolean
+test_sync_in_idle (gpointer user_data)
+{
+	ECalClient *cal_client;
+	GError *error = NULL;
+	icalcomponent *icalcomp = user_data;
+
+	g_return_val_if_fail (icalcomp != NULL, FALSE);
+
+	if (!test_sync (icalcomp)) {
+		stop_main_loop (1);
+		return FALSE;
+	}
+
+	cal_client = new_temp_client (E_CAL_CLIENT_SOURCE_TYPE_EVENTS, NULL);
+	g_return_val_if_fail (cal_client != NULL, FALSE);
+
+	if (!e_client_open_sync (E_CLIENT (cal_client), FALSE, NULL, &error)) {
+		report_error ("client open sync", &error);
+		g_object_unref (cal_client);
+		stop_main_loop (1);
+		return FALSE;
+	}
+
+	e_cal_client_create_object (cal_client, icalcomp, NULL, async_write_result_ready, icalcomp);
+
+	return FALSE;
+}
+
+/* synchronously in a dedicated thread with main-loop running */
+static gpointer
+test_sync_in_thread (gpointer user_data)
+{
+	icalcomponent *icalcomp = user_data;
+
+	g_return_val_if_fail (icalcomp != NULL, NULL);
+
+	if (!test_sync (icalcomp)) {
+		stop_main_loop (1);
+		return NULL;
+	}
+
+	g_idle_add (test_sync_in_idle, icalcomp);
+
+	return NULL;
+}
+
+gint
+main (gint argc, gchar **argv)
+{
+	icalcomponent *icalcomp;
+	struct icaltimetype now;
+
+	main_initialize ();
+
+	/* Build up new component */
+	now = icaltime_current_time_with_zone (icaltimezone_get_utc_timezone ());
+	icalcomp = icalcomponent_new (ICAL_VEVENT_COMPONENT);
+	icalcomponent_set_summary (icalcomp, "Test event summary");
+	icalcomponent_set_dtstart (icalcomp, now);
+	icalcomponent_set_dtend   (icalcomp, icaltime_from_timet (icaltime_as_timet (now) + 60 * 60 * 60, 0));
+
+	/* synchronously without main-loop */
+	if (!test_sync (icalcomp)) {
+		icalcomponent_free (icalcomp);
+		return 1;
+	}
+
+	start_in_thread_with_main_loop (test_sync_in_thread, icalcomp);
+
+	icalcomponent_free (icalcomp);
+
+	if (get_main_loop_stop_result () == 0)
+		g_print ("Test finished successfully.\n");
+
+	return get_main_loop_stop_result ();
+}
diff --git a/tests/libecal/client/test-client-examine.c b/tests/libecal/client/test-client-examine.c
new file mode 100644
index 0000000..3a1298e
--- /dev/null
+++ b/tests/libecal/client/test-client-examine.c
@@ -0,0 +1,487 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <stdlib.h>
+#include <string.h>
+#include <libecal/e-cal-client.h>
+#include <libedataserver/e-source-group.h>
+
+#include "client-test-utils.h"
+
+static gint running_async = 0;
+
+static GSList *
+get_known_prop_names (void)
+{
+	GSList *prop_names = NULL;
+
+	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_OPENED);
+	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_OPENING);
+	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_ONLINE);
+	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_READONLY);
+	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_CACHE_DIR);
+	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_CAPABILITIES);
+	prop_names = g_slist_append (prop_names, (gpointer) CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS);
+	prop_names = g_slist_append (prop_names, (gpointer) CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS);
+	prop_names = g_slist_append (prop_names, (gpointer) CAL_BACKEND_PROPERTY_DEFAULT_OBJECT);
+
+	return prop_names;
+}
+
+typedef struct _ExtraValues {
+	gpointer async_data;
+
+	GSList *todo_prop_names;
+	GHashTable *retrieved_props;
+	const gchar *cache_dir;
+	icalcomponent *default_object;
+} ExtraValues;
+
+static void
+extra_values_free (ExtraValues *evals)
+{
+	if (!evals)
+		return;
+
+	if (evals->default_object)
+		icalcomponent_free (evals->default_object);
+	g_slist_free (evals->todo_prop_names);
+	g_hash_table_destroy (evals->retrieved_props);
+	g_free (evals);
+}
+
+static void
+print_with_prefix (const gchar *str, const gchar *prefix)
+{
+	const gchar *p = str, *n;
+	while (n = strchr (p, '\n'), p) {
+		if (!n) {
+			g_print ("%s%s\n", prefix, p);
+			break;
+		} else {
+			g_print ("%s%.*s\n", prefix, (gint) (n - p), p);
+			n++;
+		}
+
+		p = n;
+	}
+}
+
+static void
+print_each_property (gpointer prop_name, gpointer prop_value, gpointer user_data)
+{
+	g_return_if_fail (prop_name != NULL);
+
+	if (prop_value == NULL) {
+		g_print ("\t   %s: NULL\n", (const gchar *) prop_name);
+		return;
+	}
+
+	g_print ("\t   %s: ", (const gchar *) prop_name);
+
+	if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
+		GSList *values = e_client_util_parse_comma_strings (prop_value), *v;
+
+		
+		for (v = values; v; v = v->next) {
+			if (v != values)
+				g_print (", ");
+
+			g_print ("'%s'", (const gchar *) v->data);
+		}
+
+		e_client_util_free_string_slist (values);
+	} else if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_DEFAULT_OBJECT)) {
+		g_print ("\n");
+		print_with_prefix (prop_value, "\t\t");
+	} else {
+		g_print ("'%s'", (const gchar *) prop_value);
+	}
+
+	g_print ("\n");
+}
+
+static void
+print_values (const ExtraValues *evals, EClient *client)
+{
+	const GSList *values;
+
+	g_return_if_fail (evals != NULL);
+
+	g_print ("\treadonly:%s\n", e_client_is_readonly (client) ? "yes" : "no");
+	g_print ("\tonline:%s\n", e_client_is_online (client) ? "yes" : "no");
+	g_print ("\topened:%s\n", e_client_is_opened (client) ? "yes" : "no");
+	g_print ("\tcache dir: %s%s%s\n", evals->cache_dir ? "'" : "", evals->cache_dir ? evals->cache_dir : "none", evals->cache_dir ? "'" : "");
+	g_print ("\tcapabilities: ");
+	values = e_client_get_capabilities (client);
+	if (!values) {
+		g_print ("NULL");
+	} else {
+		while (values) {
+			const gchar *cap = values->data;
+
+			g_print ("'%s'", cap);
+			if (!e_client_check_capability (client, cap))
+				g_print (" (not found in EClient)");
+
+			values = values->next;
+
+			if (values)
+				g_print (", ");
+		}
+	}
+	g_print ("\n");
+
+	g_print ("\tdefault object: %s\n", evals->default_object ? "" : "none");
+	if (evals->default_object) {
+		gchar *comp_str = icalcomponent_as_ical_string_r (evals->default_object);
+		print_with_prefix (comp_str, "\t   ");
+		g_free (comp_str);
+	}
+
+	g_print ("\tbackend properties:\n");
+	g_hash_table_foreach (evals->retrieved_props, print_each_property, NULL);
+}
+
+static void
+identify_source (ESource *source, ECalClientSourceType source_type)
+{
+	const gchar *name, *uri, *type;
+	gchar *abs_uri = NULL;
+
+	g_return_if_fail (source != NULL);
+
+	switch (source_type) {
+	case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+		type = "events";
+		break;
+	case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+		type = "tasks";
+		break;
+	case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+		type = "memos";
+		break;
+	default:
+		type = "unknown-type";
+		break;
+	}
+
+	name = e_source_peek_name (source);
+	if (!name)
+		name = "Unknown name";
+
+	uri = e_source_peek_absolute_uri (source);
+	if (!uri) {
+		abs_uri = e_source_build_absolute_uri (source);
+		uri = abs_uri;
+	}
+	if (!uri)
+		uri = e_source_peek_relative_uri (source);
+	if (!uri)
+		uri = "Unknown uri";
+
+	g_print ("\n   Checking %s source '%s' (%s)\n", type, name, uri);
+
+	g_free (abs_uri);
+}
+
+static void
+identify_client (ECalClient *cal_client)
+{
+	g_return_if_fail (cal_client != NULL);
+	g_return_if_fail (E_IS_CAL_CLIENT (cal_client));
+
+	identify_source (e_client_get_source (E_CLIENT (cal_client)), e_cal_client_get_source_type (cal_client));
+}
+
+static void client_opened_async (GObject *source_object, GAsyncResult *result, gpointer async_data);
+
+static void
+continue_next_source (gpointer async_data)
+{
+	ESource *source = NULL;
+	ECalClient *cal_client;
+	GError *error = NULL;
+
+	g_return_if_fail (async_data != NULL);
+
+	while (async_data && foreach_configured_source_async_next (&async_data, &source)) {
+		ECalClientSourceType source_type = foreach_configured_source_async_get_source_type (async_data);
+
+		cal_client = e_cal_client_new (source, source_type, &error);
+		if (!cal_client) {
+			identify_source (source, source_type);
+			report_error ("cal client new", &error);
+			continue;
+		}
+
+		e_client_open (E_CLIENT (cal_client), TRUE, NULL, client_opened_async, async_data);
+		break;
+	}
+
+	if (!async_data) {
+		running_async--;
+		if (!running_async)
+			stop_main_loop (0);
+	}
+}
+
+static void
+client_got_backend_property_async (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	ExtraValues *evals = user_data;
+	gchar *prop_value = NULL;
+	GError *error = NULL;
+	ECalClient *cal_client;
+
+	g_return_if_fail (source_object != NULL);
+	g_return_if_fail (E_IS_CAL_CLIENT (source_object));
+	g_return_if_fail (evals != NULL);
+
+	cal_client = E_CAL_CLIENT (source_object);
+
+	if (!e_client_get_backend_property_finish (E_CLIENT (cal_client), result, &prop_value, &error)) {
+		identify_client (cal_client);
+		report_error ("get backend property finish", &error);
+	}
+
+	g_hash_table_insert (evals->retrieved_props, evals->todo_prop_names->data, prop_value);
+	evals->todo_prop_names = g_slist_remove (evals->todo_prop_names, evals->todo_prop_names->data);
+
+	if (!evals->todo_prop_names) {
+		evals->cache_dir = e_cal_client_get_local_attachment_store (cal_client);
+
+		/* to cache them, as it can be fetched with idle as well */
+		e_client_get_capabilities (E_CLIENT (source_object));
+
+		identify_client (cal_client);
+		print_values (evals, E_CLIENT (source_object));
+
+		g_object_unref (source_object);
+
+		continue_next_source (evals->async_data);
+		extra_values_free (evals);
+	} else {
+		e_client_get_backend_property (E_CLIENT (cal_client), evals->todo_prop_names->data, NULL, client_got_backend_property_async, evals);
+	}
+}
+
+static void
+client_set_backend_property_async (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	ExtraValues *evals = user_data;
+	GError *error = NULL;
+	ECalClient *cal_client;
+
+	g_return_if_fail (source_object != NULL);
+	g_return_if_fail (E_IS_CAL_CLIENT (source_object));
+	g_return_if_fail (evals != NULL);
+
+	cal_client = E_CAL_CLIENT (source_object);
+
+	if (!e_client_set_backend_property_finish (E_CLIENT (cal_client), result, &error)) {
+		/* it may fail on the set_backend_property */
+		g_clear_error (&error);
+	} else {
+		identify_client (cal_client);
+		g_printerr ("   Might fail on set_backend_property, but reported success\n");
+	}
+
+	e_client_get_backend_property (E_CLIENT (cal_client), evals->todo_prop_names->data, NULL, client_got_backend_property_async, evals);
+}
+
+static void
+client_got_default_object_async (GObject *source_object, GAsyncResult *result, gpointer evals_data)
+{
+	ExtraValues *evals = evals_data;
+	ECalClient *cal_client;
+	GError *error = NULL;
+
+	g_return_if_fail (source_object != NULL);
+	g_return_if_fail (E_IS_CAL_CLIENT (source_object));
+	g_return_if_fail (evals != NULL);
+
+	cal_client = E_CAL_CLIENT (source_object);
+
+	if (!e_cal_client_get_default_object_finish (cal_client, result, &evals->default_object, &error)) {
+		identify_client (cal_client);
+		report_error ("get default object finish", &error);
+	}
+
+	e_client_set_backend_property (E_CLIENT (cal_client), "*unknown*property*", "*value*", NULL, client_set_backend_property_async, evals);
+}
+
+static void
+client_opened_async (GObject *source_object, GAsyncResult *result, gpointer async_data)
+{
+	ExtraValues *evals;
+	GError *error = NULL;
+	ECalClient *cal_client;
+
+	g_return_if_fail (source_object != NULL);
+	g_return_if_fail (E_IS_CAL_CLIENT (source_object));
+	g_return_if_fail (async_data != NULL);
+
+	cal_client = E_CAL_CLIENT (source_object);
+
+	if (!e_client_open_finish (E_CLIENT (source_object), result, &error)) {
+		identify_client (cal_client);
+		report_error ("client open finish", &error);
+		g_object_unref (source_object);
+		continue_next_source (async_data);
+		return;
+	}
+
+	evals = g_new0 (ExtraValues, 1);
+	evals->async_data = async_data;
+	evals->todo_prop_names = get_known_prop_names ();
+	evals->retrieved_props = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);
+	
+	e_cal_client_get_default_object (cal_client, NULL, client_got_default_object_async, evals);
+}
+
+static void
+check_source_sync (ESource *source, ECalClientSourceType source_type)
+{
+	ECalClient *cal_client;
+	GError *error = NULL;
+	GSList *properties, *p;
+	ExtraValues evals = { 0 };
+
+	g_return_if_fail (source != NULL);
+
+	identify_source (source, source_type);
+
+	cal_client = e_cal_client_new (source, source_type, &error);
+	if (!cal_client) {
+		report_error ("cal client new", &error);
+		return;
+	}
+
+	if (!e_client_open_sync (E_CLIENT (cal_client), TRUE, NULL, &error)) {
+		report_error ("client open sync", &error);
+		g_object_unref (cal_client);
+		return;
+	}
+
+	if (!e_cal_client_get_default_object_sync (cal_client, &evals.default_object, NULL, &error)) {
+		report_error ("get default object sync", &error);
+	}
+
+	if (!e_client_set_backend_property_sync (E_CLIENT (cal_client), "*unknown*property*", "*value*", NULL, &error)) {
+		g_clear_error (&error);
+	} else {
+		identify_client (cal_client);
+		g_printerr ("   Might fail on set_backend_property, but reported success\n");
+	}
+
+	evals.retrieved_props = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);
+
+	properties = get_known_prop_names ();
+	for (p = properties; p != NULL; p = p->next) {
+		gchar *prop_value = NULL;
+
+		if (!e_client_get_backend_property_sync (E_CLIENT (cal_client), p->data, &prop_value, NULL, &error)) {
+			identify_client (cal_client);
+			report_error ("get backend property sync", &error);
+		} else {
+			g_hash_table_insert (evals.retrieved_props, p->data, prop_value);
+		}
+	}
+	g_slist_free (properties);
+
+	evals.cache_dir = e_cal_client_get_local_attachment_store (cal_client);
+
+	print_values (&evals, E_CLIENT (cal_client));
+
+	g_hash_table_destroy (evals.retrieved_props);
+	icalcomponent_free (evals.default_object);
+	g_object_unref (cal_client);
+}
+
+static gboolean
+foreach_async (ECalClientSourceType source_type)
+{
+	gpointer async_data;
+	ESource *source = NULL;
+	ECalClient *cal_client;
+	GError *error = NULL;
+
+	async_data = foreach_configured_source_async_start (source_type, &source);
+	if (!async_data) {
+		stop_main_loop (1);
+		return FALSE;
+	}
+
+	running_async++;
+
+	while (cal_client = e_cal_client_new (source, source_type, &error), !cal_client) {
+		identify_source (source, source_type);
+		report_error ("cal client new", &error);
+
+		if (!foreach_configured_source_async_next (&async_data, &source)) {
+			running_async--;
+			if (!running_async)
+				stop_main_loop (0);
+			return FALSE;
+		}
+
+		identify_source (source, source_type);
+	}
+
+	e_client_open (E_CLIENT (cal_client), TRUE, NULL, client_opened_async, async_data);
+
+	return TRUE;
+}
+
+static gboolean
+in_main_thread_idle_cb (gpointer unused)
+{
+	g_print ("* run in main thread with mainloop running\n");
+	foreach_configured_source (E_CAL_CLIENT_SOURCE_TYPE_EVENTS, check_source_sync);
+	foreach_configured_source (E_CAL_CLIENT_SOURCE_TYPE_TASKS, check_source_sync);
+	foreach_configured_source (E_CAL_CLIENT_SOURCE_TYPE_MEMOS, check_source_sync);
+	g_print ("---------------------------------------------------------\n\n");
+
+	g_print ("* run in main thread async\n");
+
+	if (!foreach_async (E_CAL_CLIENT_SOURCE_TYPE_EVENTS))
+		return FALSE;
+
+	if (!foreach_async (E_CAL_CLIENT_SOURCE_TYPE_TASKS))
+		return FALSE;
+
+	if (!foreach_async (E_CAL_CLIENT_SOURCE_TYPE_MEMOS))
+		return FALSE;
+
+	return FALSE;
+}
+
+static gpointer
+worker_thread (gpointer unused)
+{
+	g_print ("* run in dedicated thread with mainloop running\n");
+	foreach_configured_source (E_CAL_CLIENT_SOURCE_TYPE_EVENTS, check_source_sync);
+	foreach_configured_source (E_CAL_CLIENT_SOURCE_TYPE_TASKS, check_source_sync);
+	foreach_configured_source (E_CAL_CLIENT_SOURCE_TYPE_MEMOS, check_source_sync);
+	g_print ("---------------------------------------------------------\n\n");
+
+	g_idle_add (in_main_thread_idle_cb, NULL);
+
+	return NULL;
+}
+
+gint
+main (gint argc, gchar **argv)
+{
+	main_initialize ();
+
+	g_print ("* run in main thread without mainloop\n");
+	foreach_configured_source (E_CAL_CLIENT_SOURCE_TYPE_EVENTS, check_source_sync);
+	foreach_configured_source (E_CAL_CLIENT_SOURCE_TYPE_TASKS, check_source_sync);
+	foreach_configured_source (E_CAL_CLIENT_SOURCE_TYPE_MEMOS, check_source_sync);
+	g_print ("---------------------------------------------------------\n\n");
+
+	start_in_thread_with_main_loop (worker_thread, NULL);
+
+	return get_main_loop_stop_result ();
+}
diff --git a/tests/libecal/client/test-client-get-attachment-uris.c b/tests/libecal/client/test-client-get-attachment-uris.c
new file mode 100644
index 0000000..0d9a5ce
--- /dev/null
+++ b/tests/libecal/client/test-client-get-attachment-uris.c
@@ -0,0 +1,191 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <stdlib.h>
+#include <string.h>
+#include <libecal/e-cal-client.h>
+#include <libical/ical.h>
+
+#include "client-test-utils.h"
+
+#define ATTACH1 "file:///tmp/file1.x"
+#define ATTACH2 "file:///tmp/file2"
+#define ATTACH3 "file:///tmp/dir/fileÄ?Å¡Ä?Å?žýáíé3"
+
+static gboolean
+manage_result (GSList *attachment_uris)
+{
+	gboolean res;
+
+	g_return_val_if_fail (attachment_uris != NULL, FALSE);
+	g_return_val_if_fail (g_slist_length (attachment_uris) == 3, FALSE);
+
+	res = g_slist_find_custom (attachment_uris, ATTACH1, g_str_equal)
+	   && g_slist_find_custom (attachment_uris, ATTACH2, g_str_equal)
+	   && g_slist_find_custom (attachment_uris, ATTACH3, g_str_equal);
+
+	if (!res) {
+		GSList *au;
+
+		g_printerr ("Failed: didn't return same three attachment uris, got instead:\n");
+		for (au = attachment_uris; au; au = au->next)
+			g_printerr ("\t'%s'\n", (const gchar *) au->data);
+	}
+
+	e_client_util_free_string_slist (attachment_uris);
+
+	return res;
+}
+
+static gboolean
+test_sync (ECalClient *cal_client)
+{
+	GError *error = NULL;
+	GSList *attachment_uris = NULL;
+	const gchar *uid = g_object_get_data (G_OBJECT (cal_client), "use-uid");
+
+	g_return_val_if_fail (uid != NULL, FALSE);
+
+	if (!e_cal_client_get_attachment_uris_sync (cal_client, uid, NULL, &attachment_uris, NULL, &error)) {
+		report_error ("get attachment uris sync", &error);
+		return FALSE;
+	}
+
+	return manage_result (attachment_uris);
+}
+
+/* asynchronous callback with a main-loop running */
+static void
+async_attachment_uris_result_ready (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	ECalClient *cal_client;
+	GError *error = NULL;
+	GSList *attachment_uris = NULL;
+
+	cal_client = E_CAL_CLIENT (source_object);
+
+	if (!e_cal_client_get_attachment_uris_finish (cal_client, result, &attachment_uris, &error)) {
+		report_error ("get attachment uris finish", &error);
+		stop_main_loop (1);
+		return;
+	}
+
+	stop_main_loop (manage_result (attachment_uris) ? 0 : 1);
+}
+
+/* synchronously in idle with main-loop running */
+static gboolean
+test_sync_in_idle (gpointer user_data)
+{
+	ECalClient *cal_client = user_data;
+	const gchar *uid;
+
+	g_return_val_if_fail (cal_client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (cal_client), FALSE);
+
+	if (!test_sync (cal_client)) {
+		stop_main_loop (1);
+		return FALSE;
+	}
+
+	uid = g_object_get_data (G_OBJECT (cal_client), "use-uid");
+
+	e_cal_client_get_attachment_uris (cal_client, uid, NULL, NULL, async_attachment_uris_result_ready, NULL);
+
+	return FALSE;
+}
+
+/* synchronously in a dedicated thread with main-loop running */
+static gpointer
+test_sync_in_thread (gpointer user_data)
+{
+	if (!test_sync (user_data)) {
+		stop_main_loop (1);
+		return NULL;
+	}
+
+	g_idle_add (test_sync_in_idle, user_data);
+
+	return NULL;
+}
+
+static void
+add_attach (icalcomponent *icalcomp, const gchar *uri)
+{
+	gsize buf_size;
+	gchar *buf;
+	icalproperty *prop;
+	icalattach *attach;
+
+	g_return_if_fail (icalcomp != NULL);
+	g_return_if_fail (uri != NULL);
+
+	buf_size = 2 * strlen (uri);
+	buf = g_malloc0 (buf_size);
+	icalvalue_encode_ical_string (uri, buf, buf_size);
+	attach = icalattach_new_from_url (uri);
+	prop = icalproperty_new_attach (attach);
+	icalcomponent_add_property (icalcomp, prop);
+	icalattach_unref (attach);
+	g_free (buf);
+}
+
+gint
+main (gint argc, gchar **argv)
+{
+	ECalClient *cal_client;
+	GError *error = NULL;
+	icalcomponent *icalcomp;
+	struct icaltimetype now;
+	gchar *uid = NULL;
+
+	main_initialize ();
+
+	cal_client = new_temp_client (E_CAL_CLIENT_SOURCE_TYPE_EVENTS, NULL);
+	g_return_val_if_fail (cal_client != NULL, FALSE);
+
+	if (!e_client_open_sync (E_CLIENT (cal_client), FALSE, NULL, &error)) {
+		report_error ("client open sync", &error);
+		g_object_unref (cal_client);
+		return 1;
+	}
+
+	now = icaltime_current_time_with_zone (icaltimezone_get_utc_timezone ());
+	icalcomp = icalcomponent_new (ICAL_VEVENT_COMPONENT);
+	icalcomponent_set_summary (icalcomp, "Test event summary");
+	icalcomponent_set_dtstart (icalcomp, now);
+	icalcomponent_set_dtend   (icalcomp, icaltime_from_timet (icaltime_as_timet (now) + 60 * 60 * 60, 0));
+	add_attach (icalcomp, ATTACH1);
+	add_attach (icalcomp, ATTACH2);
+	add_attach (icalcomp, ATTACH3);
+
+	if (!e_cal_client_create_object_sync (cal_client, icalcomp, &uid, NULL, &error)) {
+		report_error ("create object sync", &error);
+		icalcomponent_free (icalcomp);
+		g_object_unref (cal_client);
+		return 1;
+	}
+
+	icalcomponent_free (icalcomp);
+	g_object_set_data_full (G_OBJECT (cal_client), "use-uid", uid, g_free);
+
+	/* synchronously without main-loop */
+	if (!test_sync (cal_client)) {
+		g_object_unref (cal_client);
+		return 1;
+	}
+
+	start_in_thread_with_main_loop (test_sync_in_thread, cal_client);
+
+	if (!e_client_remove_sync (E_CLIENT (cal_client), NULL, &error)) {
+		report_error ("client remove sync", &error);
+		g_object_unref (cal_client);
+		return 1;
+	}
+
+	g_object_unref (cal_client);
+
+	if (get_main_loop_stop_result () == 0)
+		g_print ("Test finished successfully.\n");
+
+	return get_main_loop_stop_result ();
+}
diff --git a/tests/libecal/client/test-client-get-free-busy.c b/tests/libecal/client/test-client-get-free-busy.c
new file mode 100644
index 0000000..a493c97
--- /dev/null
+++ b/tests/libecal/client/test-client-get-free-busy.c
@@ -0,0 +1,164 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <stdlib.h>
+#include <libecal/e-cal-client.h>
+#include <libecal/e-cal-time-util.h>
+#include <libical/ical.h>
+
+#include "client-test-utils.h"
+
+#define USER_EMAIL "user example com"
+
+static void
+free_busy_data_cb (ECalClient *client, const GSList *free_busy, const gchar *func_name)
+{
+	g_print ("   Received %d Free/Busy components from %s\n", g_slist_length ((GSList *) free_busy), func_name);
+}
+
+static gboolean
+test_sync (void)
+{
+	ECalClient *cal_client;
+	GError *error = NULL;
+	icaltimezone *utc;
+	GSList *users = NULL;
+	time_t start, end;
+	gulong sig_id;
+
+	cal_client = new_temp_client (E_CAL_CLIENT_SOURCE_TYPE_EVENTS, NULL);
+	g_return_val_if_fail (cal_client != NULL, FALSE);
+
+	if (!e_client_open_sync (E_CLIENT (cal_client), FALSE, NULL, &error)) {
+		report_error ("client open sync", &error);
+		g_object_unref (cal_client);
+		return FALSE;
+	}
+
+	utc = icaltimezone_get_utc_timezone ();
+	start = time_from_isodate ("20040212T000000Z");
+	end = time_add_day_with_zone (start, 2, utc);
+	users = g_slist_append (users, (gpointer) USER_EMAIL);
+
+	sig_id = g_signal_connect (cal_client, "free-busy-data", G_CALLBACK (free_busy_data_cb), (gpointer) G_STRFUNC);
+
+	if (!e_cal_client_get_free_busy_sync (cal_client, start, end, users, NULL, &error)) {
+		report_error ("get free busy sync", &error);
+		g_signal_handler_disconnect (cal_client, sig_id);
+		g_object_unref (cal_client);
+		g_slist_free (users);
+		return FALSE;
+	}
+
+	g_signal_handler_disconnect (cal_client, sig_id);
+
+	g_slist_free (users);
+
+	if (!e_client_remove_sync (E_CLIENT (cal_client), NULL, &error)) {
+		report_error ("client remove sync", &error);
+		g_object_unref (cal_client);
+		return FALSE;
+	}
+
+	g_object_unref (cal_client);
+
+	return TRUE;
+}
+
+/* asynchronous get_free_busy callback with a main-loop running */
+static void
+async_get_free_busy_result_ready (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	ECalClient *cal_client;
+	GError *error = NULL;
+
+	cal_client = E_CAL_CLIENT (source_object);
+
+	if (!e_cal_client_get_free_busy_finish (cal_client, result, &error)) {
+		report_error ("create object finish", &error);
+		g_object_unref (cal_client);
+		stop_main_loop (1);
+		return;
+	}
+
+	if (!e_client_remove_sync (E_CLIENT (cal_client), NULL, &error)) {
+		report_error ("client remove sync", &error);
+		g_object_unref (cal_client);
+		stop_main_loop (1);
+		return;
+	}
+
+	g_object_unref (cal_client);
+
+	stop_main_loop (0);
+}
+
+/* synchronously in idle with main-loop running */
+static gboolean
+test_async_in_idle (gpointer user_data)
+{
+	ECalClient *cal_client;
+	GError *error = NULL;
+	icaltimezone *utc;
+	GSList *users = NULL;
+	time_t start, end;
+
+	if (!test_sync ()) {
+		stop_main_loop (1);
+		return FALSE;
+	}
+
+	cal_client = new_temp_client (E_CAL_CLIENT_SOURCE_TYPE_EVENTS, NULL);
+	g_return_val_if_fail (cal_client != NULL, FALSE);
+
+	if (!e_client_open_sync (E_CLIENT (cal_client), FALSE, NULL, &error)) {
+		report_error ("client open sync", &error);
+		g_object_unref (cal_client);
+		stop_main_loop (1);
+		return FALSE;
+	}
+
+	utc = icaltimezone_get_utc_timezone ();
+	start = time_from_isodate ("20040212T000000Z");
+	end = time_add_day_with_zone (start, 2, utc);
+	users = g_slist_append (users, (gpointer) USER_EMAIL);
+
+	/* here is all Free/Busy information received */
+	g_signal_connect (cal_client, "free-busy-data", G_CALLBACK (free_busy_data_cb), (gpointer) G_STRFUNC);
+
+	e_cal_client_get_free_busy (cal_client, start, end, users, NULL, async_get_free_busy_result_ready, NULL);
+
+	g_slist_free (users);
+
+	return FALSE;
+}
+
+/* synchronously in a dedicated thread with main-loop running */
+static gpointer
+test_sync_in_thread (gpointer user_data)
+{
+	if (!test_sync ()) {
+		stop_main_loop (1);
+		return NULL;
+	}
+
+	g_idle_add (test_async_in_idle, NULL);
+
+	return NULL;
+}
+
+gint
+main (gint argc, gchar **argv)
+{
+	main_initialize ();
+
+	/* synchronously without main-loop */
+	if (!test_sync ())
+		return 1;
+
+	start_in_thread_with_main_loop (test_sync_in_thread, NULL);
+
+	if (get_main_loop_stop_result () == 0)
+		g_print ("Test finished successfully.\n");
+
+	return get_main_loop_stop_result ();
+}
diff --git a/tests/libecal/client/test-client-get-object-list.c b/tests/libecal/client/test-client-get-object-list.c
new file mode 100644
index 0000000..0566f2e
--- /dev/null
+++ b/tests/libecal/client/test-client-get-object-list.c
@@ -0,0 +1,203 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <stdlib.h>
+#include <libecal/e-cal-client.h>
+#include <libical/ical.h>
+
+#include "client-test-utils.h"
+
+#define EVENT_SUMMARY "Creation of new test event"
+#define EVENT_QUERY "(contains? \"summary\" \"" EVENT_SUMMARY "\")"
+
+static gboolean
+test_result (icalcomponent *icalcomp)
+{
+	g_return_val_if_fail (icalcomp != NULL, FALSE);
+	g_return_val_if_fail (g_strcmp0 (icalcomponent_get_summary (icalcomp), EVENT_SUMMARY) == 0, FALSE);
+
+	return TRUE;
+}
+
+static gboolean
+test_sync (ECalClient *cal_client)
+{
+	GError *error = NULL;
+	GSList *icalcomps = NULL, *ecalcomps = NULL;
+	gboolean res = TRUE;
+
+	if (!e_cal_client_get_object_list_sync (cal_client, EVENT_QUERY, &icalcomps, NULL, &error)) {
+		report_error ("get object list sync", &error);
+		return FALSE;
+	}
+
+	if (g_slist_length (icalcomps) != 1) {
+		g_printerr ("Failure: expected 1 item returned in icalcomps, got %d\n", g_slist_length (icalcomps));
+		res = FALSE;
+	} else {
+		res = res && test_result (icalcomps->data);
+	}
+
+	e_cal_client_free_icalcomp_slist (icalcomps);
+
+	if (!e_cal_client_get_object_list_as_comps_sync (cal_client, EVENT_QUERY, &ecalcomps, NULL, &error)) {
+		report_error ("get object list as comps sync", &error);
+		return FALSE;
+	}
+
+	if (g_slist_length (ecalcomps) != 1) {
+		g_printerr ("Failure: expected 1 item returned in ecalcomps, got %d\n", g_slist_length (ecalcomps));
+		res = FALSE;
+	} else {
+		res = res && test_result (e_cal_component_get_icalcomponent (ecalcomps->data));
+	}
+
+	e_cal_client_free_ecalcomp_slist (ecalcomps);
+
+	return res;
+}
+
+/* asynchronous callback with a main-loop running */
+static void
+async_get_object_list_as_comps_result_ready (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	ECalClient *cal_client;
+	GError *error = NULL;
+	GSList *ecalcomps = NULL;
+	gboolean res = TRUE;
+
+	cal_client = E_CAL_CLIENT (source_object);
+
+	if (!e_cal_client_get_object_list_as_comps_finish (cal_client, result, &ecalcomps, &error)) {
+		report_error ("get object list as comps finish", &error);
+		stop_main_loop (1);
+		return;
+	}
+
+	if (g_slist_length (ecalcomps) != 1) {
+		g_printerr ("Failure: expected 1 item returned in ecalcomps, got %d\n", g_slist_length (ecalcomps));
+		res = FALSE;
+	} else {
+		res = res && test_result (e_cal_component_get_icalcomponent (ecalcomps->data));
+	}
+
+	e_cal_client_free_ecalcomp_slist (ecalcomps);
+	stop_main_loop (res ? 0 : 1);
+}
+
+/* asynchronous callback with a main-loop running */
+static void
+async_get_object_list_result_ready (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	ECalClient *cal_client;
+	GError *error = NULL;
+	GSList *icalcomps = NULL;
+
+	cal_client = E_CAL_CLIENT (source_object);
+
+	if (!e_cal_client_get_object_list_finish (cal_client, result, &icalcomps, &error)) {
+		report_error ("get object list finish", &error);
+		stop_main_loop (1);
+		return;
+	}
+
+	if (g_slist_length (icalcomps) != 1) {
+		g_printerr ("Failure: expected 1 item returned in icalcomps, got %d\n", g_slist_length (icalcomps));
+	} else {
+		test_result (icalcomps->data);
+	}
+
+	e_cal_client_free_icalcomp_slist (icalcomps);
+
+	e_cal_client_get_object_list_as_comps (cal_client, EVENT_QUERY, NULL, async_get_object_list_as_comps_result_ready, NULL);
+}
+
+/* synchronously in idle with main-loop running */
+static gboolean
+test_sync_in_idle (gpointer user_data)
+{
+	ECalClient *cal_client = user_data;
+
+	g_return_val_if_fail (cal_client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (cal_client), FALSE);
+
+	if (!test_sync (cal_client)) {
+		stop_main_loop (1);
+		return FALSE;
+	}
+
+	e_cal_client_get_object_list (cal_client, EVENT_QUERY, NULL, async_get_object_list_result_ready, NULL);
+
+	return FALSE;
+}
+
+/* synchronously in a dedicated thread with main-loop running */
+static gpointer
+test_sync_in_thread (gpointer user_data)
+{
+	if (!test_sync (user_data)) {
+		stop_main_loop (1);
+		return NULL;
+	}
+
+	g_idle_add (test_sync_in_idle, user_data);
+
+	return NULL;
+}
+
+gint
+main (gint argc, gchar **argv)
+{
+	ECalClient *cal_client;
+	GError *error = NULL;
+	icalcomponent *icalcomp;
+	struct icaltimetype now;
+	gchar *uid = NULL;
+
+	main_initialize ();
+
+	cal_client = new_temp_client (E_CAL_CLIENT_SOURCE_TYPE_EVENTS, NULL);
+	g_return_val_if_fail (cal_client != NULL, FALSE);
+
+	if (!e_client_open_sync (E_CLIENT (cal_client), FALSE, NULL, &error)) {
+		report_error ("client open sync", &error);
+		g_object_unref (cal_client);
+		return 1;
+	}
+
+	now = icaltime_current_time_with_zone (icaltimezone_get_utc_timezone ());
+	icalcomp = icalcomponent_new (ICAL_VEVENT_COMPONENT);
+	icalcomponent_set_summary (icalcomp, EVENT_SUMMARY);
+	icalcomponent_set_dtstart (icalcomp, now);
+	icalcomponent_set_dtend   (icalcomp, icaltime_from_timet (icaltime_as_timet (now) + 60 * 60 * 60, 0));
+
+	if (!e_cal_client_create_object_sync (cal_client, icalcomp, &uid, NULL, &error)) {
+		report_error ("create object sync", &error);
+		g_object_unref (cal_client);
+		icalcomponent_free (icalcomp);
+		return 1;
+	}
+
+	icalcomponent_free (icalcomp);
+	g_free (uid);
+
+	/* synchronously without main-loop */
+	if (!test_sync (cal_client)) {
+		g_object_unref (cal_client);
+		return 1;
+	}
+
+	start_in_thread_with_main_loop (test_sync_in_thread, cal_client);
+
+	if (!e_client_remove_sync (E_CLIENT (cal_client), NULL, &error)) {
+		report_error ("client remove sync", &error);
+		g_object_unref (cal_client);
+		return 1;
+	}
+
+	g_object_unref (cal_client);
+
+	if (get_main_loop_stop_result () == 0)
+		g_print ("Test finished successfully.\n");
+
+	return get_main_loop_stop_result ();
+}
diff --git a/tests/libecal/client/test-client-get-view.c b/tests/libecal/client/test-client-get-view.c
new file mode 100644
index 0000000..2142b22
--- /dev/null
+++ b/tests/libecal/client/test-client-get-view.c
@@ -0,0 +1,230 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <stdlib.h>
+#include <libecal/e-cal-client.h>
+#include <libical/ical.h>
+
+#include "client-test-utils.h"
+
+typedef enum {
+	SUBTEST_OBJECTS_ADDED,
+	SUBTEST_OBJECTS_MODIFIED,
+	SUBTEST_OBJECTS_REMOVED,
+	SUBTEST_VIEW_DONE,
+	NUM_SUBTESTS,
+	SUBTEST_RESET
+} SubTestId;
+
+static void
+subtest_passed (SubTestId id)
+{
+	static guint subtests_complete = 0;
+
+	if (id == SUBTEST_RESET) {
+		subtests_complete = 0;
+		return;
+	}
+
+	subtests_complete |= (1 << id);
+
+	if (subtests_complete == ((1 << NUM_SUBTESTS) - 1))
+		stop_main_loop (0);
+}
+
+static void
+objects_added_cb (GObject *object, const GSList *objects, gpointer data)
+{
+	const GSList *l;
+
+	for (l = objects; l; l = l->next)
+                g_print ("Object added %s (%s)\n", icalcomponent_get_uid (l->data), icalcomponent_get_summary (l->data));
+
+	subtest_passed (SUBTEST_OBJECTS_ADDED);
+}
+
+static void
+objects_modified_cb (GObject *object, const GSList *objects, gpointer data)
+{
+	const GSList *l;
+
+	for (l = objects; l; l = l->next)
+                g_print ("Object modified %s (%s)\n", icalcomponent_get_uid (l->data), icalcomponent_get_summary (l->data));
+
+	subtest_passed (SUBTEST_OBJECTS_MODIFIED);
+}
+
+static void
+objects_removed_cb (GObject *object, const GSList *objects, gpointer data)
+{
+	const GSList *l;
+
+	for (l = objects; l; l = l->next) {
+		ECalComponentId *id = l->data;
+
+                g_print ("Object removed: uid: %s, rid: %s\n", id->uid, id->rid);
+	}
+
+	subtest_passed (SUBTEST_OBJECTS_REMOVED);
+}
+
+static void
+complete_cb (GObject *object, const GError *error, gpointer data)
+{
+        g_print ("View complete (status: %d, error_msg:%s)\n", error ? error->code : 0, error ? error->message : "NULL");
+
+	subtest_passed (SUBTEST_VIEW_DONE);
+}
+
+static gpointer
+alter_cal_client (gpointer user_data)
+{
+	ECalClient *cal_client = user_data;
+	GError *error = NULL;
+	icalcomponent *icalcomp;
+	struct icaltimetype now;
+	gchar *uid = NULL;
+
+	g_return_val_if_fail (cal_client != NULL, NULL);
+
+	now = icaltime_current_time_with_zone (icaltimezone_get_utc_timezone ());
+	icalcomp = icalcomponent_new (ICAL_VEVENT_COMPONENT);
+	icalcomponent_set_summary (icalcomp, "Initial event summary");
+	icalcomponent_set_dtstart (icalcomp, now);
+	icalcomponent_set_dtend   (icalcomp, icaltime_from_timet (icaltime_as_timet (now) + 60 * 60 * 60, 0));
+
+	if (!e_cal_client_create_object_sync (cal_client, icalcomp, &uid, NULL, &error)) {
+		report_error ("create object sync", &error);
+		icalcomponent_free (icalcomp);
+		stop_main_loop (1);
+		return NULL;
+	}
+
+	icalcomponent_set_uid (icalcomp, uid);
+	icalcomponent_set_summary (icalcomp, "Modified event summary");
+
+	if (!e_cal_client_modify_object_sync (cal_client, icalcomp, CALOBJ_MOD_ALL, NULL, &error)) {
+		report_error ("modify object sync", &error);
+		icalcomponent_free (icalcomp);
+		g_free (uid);
+		stop_main_loop (1);
+		return NULL;
+	}
+
+	if (!e_cal_client_remove_object_sync (cal_client, uid, NULL, CALOBJ_MOD_ALL, NULL, &error)) {
+		report_error ("remove object sync", &error);
+		icalcomponent_free (icalcomp);
+		g_free (uid);
+		stop_main_loop (1);
+		return NULL;
+	}
+
+	g_free (uid);
+	icalcomponent_free (icalcomp);
+
+	return NULL;
+}
+
+static void
+async_get_view_ready (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	ECalClient *cal_client = E_CAL_CLIENT (source_object);
+	ECalClientView *view = NULL;
+	GError *error = NULL;
+
+	g_return_if_fail (cal_client != NULL);
+
+	if (!e_cal_client_get_view_finish (cal_client, result, &view, &error)) {
+		report_error ("get view finish", &error);
+		stop_main_loop (1);
+		return;
+	}
+
+	subtest_passed (SUBTEST_RESET);
+	g_signal_connect (view, "objects_added", G_CALLBACK (objects_added_cb), cal_client);
+	g_signal_connect (view, "objects_modified", G_CALLBACK (objects_modified_cb), cal_client);
+	g_signal_connect (view, "objects_removed", G_CALLBACK (objects_removed_cb), cal_client);
+	g_signal_connect (view, "complete", G_CALLBACK (complete_cb), cal_client);
+
+	g_object_set_data_full (G_OBJECT (cal_client), "cal-view", view, g_object_unref);
+
+	e_cal_client_view_set_fields_of_interest (view, NULL, &error);
+	if (error)
+		report_error ("set fields of interest", &error);
+	e_cal_client_view_start (view, NULL);
+
+	alter_cal_client (cal_client);
+}
+
+static gpointer
+get_view_async (gpointer user_data)
+{
+	ECalClient *cal_client = user_data;
+
+	g_return_val_if_fail (user_data != NULL, NULL);
+
+	e_cal_client_get_view (cal_client, "(contains? \"any\" \"event\")", NULL, async_get_view_ready, NULL);
+
+	return NULL;
+}
+
+gint
+main (gint argc, gchar **argv)
+{
+	ECalClientView *view = NULL;
+	ECalClient *cal_client;
+	GError *error = NULL;
+
+	main_initialize ();
+
+	cal_client = new_temp_client (E_CAL_CLIENT_SOURCE_TYPE_EVENTS, NULL);
+	g_return_val_if_fail (cal_client != NULL, FALSE);
+
+	if (!e_client_open_sync (E_CLIENT (cal_client), FALSE, NULL, &error)) {
+		report_error ("client open sync", &error);
+		g_object_unref (cal_client);
+		return 1;
+	}
+
+	if (!e_cal_client_get_view_sync (cal_client, "(contains? \"any\" \"event\")", &view, NULL, &error)) {
+		report_error ("get view sync", &error);
+		g_object_unref (cal_client);
+		return 1;
+	}
+
+	subtest_passed (SUBTEST_RESET);
+	g_signal_connect (view, "objects_added", G_CALLBACK (objects_added_cb), cal_client);
+	g_signal_connect (view, "objects_modified", G_CALLBACK (objects_modified_cb), cal_client);
+	g_signal_connect (view, "objects_removed", G_CALLBACK (objects_removed_cb), cal_client);
+	g_signal_connect (view, "complete", G_CALLBACK (complete_cb), cal_client);
+
+	e_cal_client_view_set_fields_of_interest (view, NULL, &error);
+	if (error)
+		report_error ("set fields of interest", &error);
+	e_cal_client_view_start (view, NULL);
+
+	start_in_thread_with_main_loop (alter_cal_client, cal_client);
+
+	g_object_unref (view);
+
+	if (get_main_loop_stop_result () != 0) {
+		g_object_unref (cal_client);
+		return get_main_loop_stop_result ();
+	}
+
+	start_in_idle_with_main_loop (get_view_async, cal_client);
+
+	g_object_set_data (G_OBJECT (cal_client), "cal-view", NULL);
+
+	if (!e_client_remove_sync (E_CLIENT (cal_client), NULL, &error)) {
+		report_error ("client remove sync", &error);
+		g_object_unref (cal_client);
+		return 1;
+	}
+
+	g_object_unref (cal_client);
+
+	if (get_main_loop_stop_result () == 0)
+		g_print ("Test finished successfully.\n");
+
+	return get_main_loop_stop_result ();
+}
diff --git a/tests/libecal/client/test-client-modify-object.c b/tests/libecal/client/test-client-modify-object.c
new file mode 100644
index 0000000..f8e9641
--- /dev/null
+++ b/tests/libecal/client/test-client-modify-object.c
@@ -0,0 +1,194 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <stdlib.h>
+#include <libecal/e-cal-client.h>
+#include <libical/ical.h>
+
+#include "client-test-utils.h"
+
+#define EVENT_SUMMARY "Creation of new test event"
+
+static gboolean
+test_result (icalcomponent *icalcomp)
+{
+	g_return_val_if_fail (icalcomp != NULL, FALSE);
+	g_return_val_if_fail (g_strcmp0 (icalcomponent_get_summary (icalcomp), EVENT_SUMMARY) == 0, FALSE);
+
+	return TRUE;
+}
+
+static gboolean
+test_sync (ECalClient *cal_client)
+{
+	GError *error = NULL;
+	icalcomponent *icalcomp = NULL;
+	const gchar *uid = g_object_get_data (G_OBJECT (cal_client), "use-uid");
+
+	g_return_val_if_fail (uid != NULL, FALSE);
+
+	if (!e_cal_client_get_object_sync (cal_client, uid, NULL, &icalcomp, NULL, &error)) {
+		report_error ("get object sync", &error);
+		return FALSE;
+	}
+
+	icalcomponent_set_summary (icalcomp, EVENT_SUMMARY);
+
+	if (!e_cal_client_modify_object_sync (cal_client, icalcomp, CALOBJ_MOD_ALL, NULL, &error)) {
+		report_error ("modify object sync", &error);
+		icalcomponent_free (icalcomp);
+		return FALSE;
+	}
+
+	icalcomponent_free (icalcomp);
+
+	if (!e_cal_client_get_object_sync (cal_client, uid, NULL, &icalcomp, NULL, &error)) {
+		report_error ("get object sync after modification", &error);
+		return FALSE;
+	}
+
+	if (!test_result (icalcomp)) {
+		icalcomponent_free (icalcomp);
+		return FALSE;
+	}
+
+	icalcomponent_free (icalcomp);
+
+	return TRUE;
+}
+
+/* asynchronous callback with a main-loop running */
+static void
+async_modify_result_ready (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	ECalClient *cal_client;
+	GError *error = NULL;
+	icalcomponent *icalcomp = NULL;
+	const gchar *uid;
+
+	cal_client = E_CAL_CLIENT (source_object);
+	uid = g_object_get_data (G_OBJECT (cal_client), "use-uid");
+
+	if (!e_cal_client_modify_object_finish (cal_client, result, &error)) {
+		report_error ("modify object finish", &error);
+		stop_main_loop (1);
+		return;
+	}
+
+	if (!e_cal_client_get_object_sync (cal_client, uid, NULL, &icalcomp, NULL, &error)) {
+		report_error ("get object sync after async modification", &error);
+		return;
+	}
+
+	if (!test_result (icalcomp)) {
+		stop_main_loop (1);
+	} else {
+		stop_main_loop (0);
+	}
+
+	icalcomponent_free (icalcomp);
+}
+
+/* synchronously in idle with main-loop running */
+static gboolean
+test_sync_in_idle (gpointer user_data)
+{
+	ECalClient *cal_client = user_data;
+	const gchar *uid = g_object_get_data (G_OBJECT (cal_client), "use-uid");
+	icalcomponent *icalcomp = NULL;
+	GError *error = NULL;
+
+	g_return_val_if_fail (cal_client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (cal_client), FALSE);
+
+	if (!test_sync (cal_client)) {
+		stop_main_loop (1);
+		return FALSE;
+	}
+
+	if (!e_cal_client_get_object_sync (cal_client, uid, NULL, &icalcomp, NULL, &error)) {
+		report_error ("get object sync", &error);
+		stop_main_loop (1);
+		return FALSE;
+	}
+
+	icalcomponent_set_summary (icalcomp, EVENT_SUMMARY);
+
+	e_cal_client_modify_object (cal_client, icalcomp, CALOBJ_MOD_ALL, NULL, async_modify_result_ready, NULL);
+
+	icalcomponent_free (icalcomp);
+
+	return FALSE;
+}
+
+/* synchronously in a dedicated thread with main-loop running */
+static gpointer
+test_sync_in_thread (gpointer user_data)
+{
+	if (!test_sync (user_data)) {
+		stop_main_loop (1);
+		return NULL;
+	}
+
+	g_idle_add (test_sync_in_idle, user_data);
+
+	return NULL;
+}
+
+gint
+main (gint argc, gchar **argv)
+{
+	ECalClient *cal_client;
+	GError *error = NULL;
+	icalcomponent *icalcomp;
+	struct icaltimetype now;
+	gchar *uid = NULL;
+
+	main_initialize ();
+
+	cal_client = new_temp_client (E_CAL_CLIENT_SOURCE_TYPE_EVENTS, NULL);
+	g_return_val_if_fail (cal_client != NULL, FALSE);
+
+	if (!e_client_open_sync (E_CLIENT (cal_client), FALSE, NULL, &error)) {
+		report_error ("client open sync", &error);
+		g_object_unref (cal_client);
+		return 1;
+	}
+
+	now = icaltime_current_time_with_zone (icaltimezone_get_utc_timezone ());
+	icalcomp = icalcomponent_new (ICAL_VEVENT_COMPONENT);
+	icalcomponent_set_summary (icalcomp, "Initial" EVENT_SUMMARY);
+	icalcomponent_set_dtstart (icalcomp, now);
+	icalcomponent_set_dtend   (icalcomp, icaltime_from_timet (icaltime_as_timet (now) + 60 * 60 * 60, 0));
+
+	if (!e_cal_client_create_object_sync (cal_client, icalcomp, &uid, NULL, &error)) {
+		report_error ("create object sync", &error);
+		g_object_unref (cal_client);
+		icalcomponent_free (icalcomp);
+		return 1;
+	}
+
+	icalcomponent_free (icalcomp);
+
+	g_object_set_data_full (G_OBJECT (cal_client), "use-uid", uid, g_free);
+
+	/* synchronously without main-loop */
+	if (!test_sync (cal_client)) {
+		g_object_unref (cal_client);
+		return 1;
+	}
+
+	start_in_thread_with_main_loop (test_sync_in_thread, cal_client);
+
+	if (!e_client_remove_sync (E_CLIENT (cal_client), NULL, &error)) {
+		report_error ("client remove sync", &error);
+		g_object_unref (cal_client);
+		return 1;
+	}
+
+	g_object_unref (cal_client);
+
+	if (get_main_loop_stop_result () == 0)
+		g_print ("Test finished successfully.\n");
+
+	return get_main_loop_stop_result ();
+}
diff --git a/tests/libecal/client/test-client-open.c b/tests/libecal/client/test-client-open.c
new file mode 100644
index 0000000..4aa3e21
--- /dev/null
+++ b/tests/libecal/client/test-client-open.c
@@ -0,0 +1,124 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <stdlib.h>
+#include <libecal/e-cal-client.h>
+#include <libical/ical.h>
+
+#include "client-test-utils.h"
+
+static gboolean
+test_sync (void)
+{
+	ECalClient *cal_client;
+	GError *error = NULL;
+
+	cal_client = new_temp_client (E_CAL_CLIENT_SOURCE_TYPE_EVENTS, NULL);
+	g_return_val_if_fail (cal_client != NULL, FALSE);
+
+	if (!e_client_open_sync (E_CLIENT (cal_client), FALSE, NULL, &error)) {
+		report_error ("client open sync", &error);
+		g_object_unref (cal_client);
+		return FALSE;
+	}
+
+	if (!e_client_remove_sync (E_CLIENT (cal_client), NULL, &error)) {
+		report_error ("client remove sync", &error);
+		g_object_unref (cal_client);
+		return FALSE;
+	}
+
+	g_object_unref (cal_client);
+
+	return TRUE;
+}
+
+/* asynchronous remove callback with a main-loop running */
+static void
+async_remove_ready (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	ECalClient *cal_client;
+	GError *error = NULL;
+
+	cal_client = E_CAL_CLIENT (source_object);
+
+	if (!e_client_remove_finish (E_CLIENT (cal_client), result, &error)) {
+		report_error ("remove finish", &error);
+		g_object_unref (cal_client);
+		stop_main_loop (1);
+		return;
+	}
+
+	g_object_unref (cal_client);
+
+	stop_main_loop (0);
+}
+
+/* asynchronous open callback with a main-loop running */
+static void
+async_open_ready (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	ECalClient *cal_client;
+	GError *error = NULL;
+
+	cal_client = E_CAL_CLIENT (source_object);
+
+	if (!e_client_open_finish (E_CLIENT (cal_client), result, &error)) {
+		report_error ("open finish", &error);
+		g_object_unref (cal_client);
+		stop_main_loop (1);
+		return;
+	}
+
+	e_client_remove (E_CLIENT (cal_client), NULL, async_remove_ready, NULL);
+}
+
+/* synchronously in idle with main-loop running */
+static gboolean
+test_sync_in_idle (gpointer user_data)
+{
+	ECalClient *cal_client;
+
+	if (!test_sync ()) {
+		stop_main_loop (1);
+		return FALSE;
+	}
+
+	cal_client = new_temp_client (E_CAL_CLIENT_SOURCE_TYPE_EVENTS, NULL);
+	g_return_val_if_fail (cal_client != NULL, FALSE);
+
+	e_client_open (E_CLIENT (cal_client), FALSE, NULL, async_open_ready, NULL);
+
+	return FALSE;
+}
+
+/* synchronously in a dedicated thread with main-loop running */
+static gpointer
+test_sync_in_thread (gpointer user_data)
+{
+	if (!test_sync ()) {
+		stop_main_loop (1);
+		return NULL;
+	}
+
+	g_idle_add (test_sync_in_idle, NULL);
+
+	return NULL;
+}
+
+gint
+main (gint argc, gchar **argv)
+{
+	main_initialize ();
+
+	/* synchronously without main-loop */
+	if (!test_sync ()) {
+		return 1;
+	}
+
+	start_in_thread_with_main_loop (test_sync_in_thread, NULL);
+
+	if (get_main_loop_stop_result () == 0)
+		g_print ("Test finished successfully.\n");
+
+	return get_main_loop_stop_result ();
+}
diff --git a/tests/libecal/client/test-client-receive-objects.c b/tests/libecal/client/test-client-receive-objects.c
new file mode 100644
index 0000000..90858f4
--- /dev/null
+++ b/tests/libecal/client/test-client-receive-objects.c
@@ -0,0 +1,142 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <stdlib.h>
+#include <libecal/e-cal-client.h>
+#include <libical/ical.h>
+
+#include "client-test-utils.h"
+
+static icalcomponent *
+create_object (void)
+{
+	icalcomponent *icalcomp;
+	struct icaltimetype now;
+
+	now = icaltime_current_time_with_zone (icaltimezone_get_utc_timezone ());
+	icalcomp = icalcomponent_new (ICAL_VEVENT_COMPONENT);
+	icalcomponent_set_summary (icalcomp, "To-be-received event summary");
+	icalcomponent_set_dtstart (icalcomp, now);
+	icalcomponent_set_dtend   (icalcomp, icaltime_from_timet (icaltime_as_timet (now) + 60 * 60 * 60, 0));
+
+	return icalcomp;
+}
+
+static gboolean
+test_sync (ECalClient *cal_client)
+{
+	GError *error = NULL;
+	icalcomponent *icalcomp;
+
+	icalcomp = create_object ();
+
+	g_return_val_if_fail (icalcomp != NULL, FALSE);
+
+	if (!e_cal_client_receive_objects_sync (cal_client, icalcomp, NULL, &error)) {
+		report_error ("receive objects sync", &error);
+		icalcomponent_free (icalcomp);
+		return FALSE;
+	}
+
+	icalcomponent_free (icalcomp);
+
+	return TRUE;
+}
+
+/* asynchronous callback with a main-loop running */
+static void
+async_receive_result_ready (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	ECalClient *cal_client;
+	GError *error = NULL;
+
+	cal_client = E_CAL_CLIENT (source_object);
+
+	if (!e_cal_client_receive_objects_finish (cal_client, result, &error)) {
+		report_error ("receive objects finish", &error);
+		stop_main_loop (1);
+		return;
+	}
+
+	stop_main_loop (0);
+}
+
+/* synchronously in idle with main-loop running */
+static gboolean
+test_sync_in_idle (gpointer user_data)
+{
+	ECalClient *cal_client = user_data;
+	icalcomponent *icalcomp;
+
+	g_return_val_if_fail (cal_client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (cal_client), FALSE);
+
+	if (!test_sync (cal_client)) {
+		stop_main_loop (1);
+		return FALSE;
+	}
+
+	icalcomp = create_object ();
+	if (!icalcomp) {
+		stop_main_loop (1);
+		return FALSE;
+	}
+
+	e_cal_client_receive_objects (cal_client, icalcomp, NULL, async_receive_result_ready, NULL);
+
+	icalcomponent_free (icalcomp);
+
+	return FALSE;
+}
+
+/* synchronously in a dedicated thread with main-loop running */
+static gpointer
+test_sync_in_thread (gpointer user_data)
+{
+	if (!test_sync (user_data)) {
+		stop_main_loop (1);
+		return NULL;
+	}
+
+	g_idle_add (test_sync_in_idle, user_data);
+
+	return NULL;
+}
+
+gint
+main (gint argc, gchar **argv)
+{
+	ECalClient *cal_client;
+	GError *error = NULL;
+
+	main_initialize ();
+
+	cal_client = new_temp_client (E_CAL_CLIENT_SOURCE_TYPE_EVENTS, NULL);
+	g_return_val_if_fail (cal_client != NULL, FALSE);
+
+	if (!e_client_open_sync (E_CLIENT (cal_client), FALSE, NULL, &error)) {
+		report_error ("client open sync", &error);
+		g_object_unref (cal_client);
+		return 1;
+	}
+
+	/* synchronously without main-loop */
+	if (!test_sync (cal_client)) {
+		g_object_unref (cal_client);
+		return 1;
+	}
+
+	start_in_thread_with_main_loop (test_sync_in_thread, cal_client);
+
+	if (!e_client_remove_sync (E_CLIENT (cal_client), NULL, &error)) {
+		report_error ("client remove sync", &error);
+		g_object_unref (cal_client);
+		return 1;
+	}
+
+	g_object_unref (cal_client);
+
+	if (get_main_loop_stop_result () == 0)
+		g_print ("Test finished successfully.\n");
+
+	return get_main_loop_stop_result ();
+}
diff --git a/tests/libecal/client/test-client-refresh.c b/tests/libecal/client/test-client-refresh.c
new file mode 100644
index 0000000..5ebae91
--- /dev/null
+++ b/tests/libecal/client/test-client-refresh.c
@@ -0,0 +1,134 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <stdlib.h>
+#include <string.h>
+#include <libecal/e-cal-client.h>
+#include <libical/ical.h>
+
+#include "client-test-utils.h"
+
+static gboolean
+test_sync (ECalClient *cal_client)
+{
+	GError *error = NULL;
+
+	g_print ("Refresh supported: %s\n", e_client_check_refresh_supported (E_CLIENT (cal_client)) ? "yes" : "no");
+
+	if (!e_client_refresh_sync (E_CLIENT (cal_client), NULL, &error)) {
+		report_error ("refresh sync", &error);
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+/* asynchronous callback with a main-loop running */
+static void
+async_refresh_result_ready (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	ECalClient *cal_client;
+	GError *error = NULL;
+
+	cal_client = E_CAL_CLIENT (source_object);
+
+	if (!e_client_refresh_finish (E_CLIENT (cal_client), result, &error)) {
+		report_error ("refresh finish", &error);
+		stop_main_loop (1);
+		return;
+	}
+
+	stop_main_loop (0);
+}
+
+/* synchronously in idle with main-loop running */
+static gboolean
+test_sync_in_idle (gpointer user_data)
+{
+	ECalClient *cal_client = user_data;
+
+	g_return_val_if_fail (cal_client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (cal_client), FALSE);
+
+	if (!test_sync (cal_client)) {
+		stop_main_loop (1);
+		return FALSE;
+	}
+
+	g_print ("Refresh supported: %s\n", e_client_check_refresh_supported (E_CLIENT (cal_client)) ? "yes" : "no");
+
+	e_client_refresh (E_CLIENT (cal_client), NULL, async_refresh_result_ready, NULL);
+
+	return FALSE;
+}
+
+/* synchronously in a dedicated thread with main-loop running */
+static gpointer
+test_sync_in_thread (gpointer user_data)
+{
+	if (!test_sync (user_data)) {
+		stop_main_loop (1);
+		return NULL;
+	}
+
+	g_idle_add (test_sync_in_idle, user_data);
+
+	return NULL;
+}
+
+gint
+main (gint argc, gchar **argv)
+{
+	ECalClient *cal_client;
+	GError *error = NULL;
+	icalcomponent *icalcomp;
+	struct icaltimetype now;
+	gchar *uid = NULL;
+
+	main_initialize ();
+
+	cal_client = new_temp_client (E_CAL_CLIENT_SOURCE_TYPE_EVENTS, NULL);
+	g_return_val_if_fail (cal_client != NULL, FALSE);
+
+	if (!e_client_open_sync (E_CLIENT (cal_client), FALSE, NULL, &error)) {
+		report_error ("client open sync", &error);
+		g_object_unref (cal_client);
+		return 1;
+	}
+
+	now = icaltime_current_time_with_zone (icaltimezone_get_utc_timezone ());
+	icalcomp = icalcomponent_new (ICAL_VEVENT_COMPONENT);
+	icalcomponent_set_summary (icalcomp, "Test event summary");
+	icalcomponent_set_dtstart (icalcomp, now);
+	icalcomponent_set_dtend   (icalcomp, icaltime_from_timet (icaltime_as_timet (now) + 60 * 60 * 60, 0));
+
+	if (!e_cal_client_create_object_sync (cal_client, icalcomp, &uid, NULL, &error)) {
+		report_error ("create object sync", &error);
+		icalcomponent_free (icalcomp);
+		g_object_unref (cal_client);
+		return 1;
+	}
+
+	icalcomponent_free (icalcomp);
+	g_free (uid);
+
+	/* synchronously without main-loop */
+	if (!test_sync (cal_client)) {
+		g_object_unref (cal_client);
+		return 1;
+	}
+
+	start_in_thread_with_main_loop (test_sync_in_thread, cal_client);
+
+	if (!e_client_remove_sync (E_CLIENT (cal_client), NULL, &error)) {
+		report_error ("client remove sync", &error);
+		g_object_unref (cal_client);
+		return 1;
+	}
+
+	g_object_unref (cal_client);
+
+	if (get_main_loop_stop_result () == 0)
+		g_print ("Test finished successfully.\n");
+
+	return get_main_loop_stop_result ();
+}
diff --git a/tests/libecal/client/test-client-remove-object.c b/tests/libecal/client/test-client-remove-object.c
new file mode 100644
index 0000000..6fbd02d
--- /dev/null
+++ b/tests/libecal/client/test-client-remove-object.c
@@ -0,0 +1,156 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <stdlib.h>
+#include <libecal/e-cal-client.h>
+#include <libical/ical.h>
+
+#include "client-test-utils.h"
+
+static gchar *
+create_object (ECalClient *cal_client)
+{
+	icalcomponent *icalcomp;
+	struct icaltimetype now;
+	gchar *uid = NULL;
+	GError *error = NULL;
+
+	g_return_val_if_fail (cal_client != NULL, NULL);
+
+	now = icaltime_current_time_with_zone (icaltimezone_get_utc_timezone ());
+	icalcomp = icalcomponent_new (ICAL_VEVENT_COMPONENT);
+	icalcomponent_set_summary (icalcomp, "To-be-removed event summary");
+	icalcomponent_set_dtstart (icalcomp, now);
+	icalcomponent_set_dtend   (icalcomp, icaltime_from_timet (icaltime_as_timet (now) + 60 * 60 * 60, 0));
+
+	if (!e_cal_client_create_object_sync (cal_client, icalcomp, &uid, NULL, &error)) {
+		report_error ("create object sync", &error);
+		icalcomponent_free (icalcomp);
+		return NULL;
+	}
+
+	icalcomponent_free (icalcomp);
+
+	g_return_val_if_fail (uid != NULL, NULL);
+
+	return uid;
+}
+
+static gboolean
+test_sync (ECalClient *cal_client)
+{
+	GError *error = NULL;
+	gchar *uid;
+
+	uid = create_object (cal_client);
+
+	g_return_val_if_fail (uid != NULL, FALSE);
+
+	if (!e_cal_client_remove_object_sync (cal_client, uid, NULL, CALOBJ_MOD_ALL, NULL, &error)) {
+		report_error ("remove object sync", &error);
+		g_free (uid);
+		return FALSE;
+	}
+
+	g_free (uid);
+
+	return TRUE;
+}
+
+/* asynchronous callback with a main-loop running */
+static void
+async_remove_result_ready (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	ECalClient *cal_client;
+	GError *error = NULL;
+
+	cal_client = E_CAL_CLIENT (source_object);
+
+	if (!e_cal_client_remove_object_finish (cal_client, result, &error)) {
+		report_error ("remove object finish", &error);
+		stop_main_loop (1);
+		return;
+	}
+
+	stop_main_loop (0);
+}
+
+/* synchronously in idle with main-loop running */
+static gboolean
+test_sync_in_idle (gpointer user_data)
+{
+	ECalClient *cal_client = user_data;
+	gchar *uid;
+
+	g_return_val_if_fail (cal_client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (cal_client), FALSE);
+
+	if (!test_sync (cal_client)) {
+		stop_main_loop (1);
+		return FALSE;
+	}
+
+	uid = create_object (cal_client);
+	if (!uid) {
+		stop_main_loop (1);
+		return FALSE;
+	}
+
+	e_cal_client_remove_object (cal_client, uid, NULL, CALOBJ_MOD_ALL, NULL, async_remove_result_ready, NULL);
+
+	g_free (uid);
+
+	return FALSE;
+}
+
+/* synchronously in a dedicated thread with main-loop running */
+static gpointer
+test_sync_in_thread (gpointer user_data)
+{
+	if (!test_sync (user_data)) {
+		stop_main_loop (1);
+		return NULL;
+	}
+
+	g_idle_add (test_sync_in_idle, user_data);
+
+	return NULL;
+}
+
+gint
+main (gint argc, gchar **argv)
+{
+	ECalClient *cal_client;
+	GError *error = NULL;
+
+	main_initialize ();
+
+	cal_client = new_temp_client (E_CAL_CLIENT_SOURCE_TYPE_EVENTS, NULL);
+	g_return_val_if_fail (cal_client != NULL, FALSE);
+
+	if (!e_client_open_sync (E_CLIENT (cal_client), FALSE, NULL, &error)) {
+		report_error ("client open sync", &error);
+		g_object_unref (cal_client);
+		return 1;
+	}
+
+	/* synchronously without main-loop */
+	if (!test_sync (cal_client)) {
+		g_object_unref (cal_client);
+		return 1;
+	}
+
+	start_in_thread_with_main_loop (test_sync_in_thread, cal_client);
+
+	if (!e_client_remove_sync (E_CLIENT (cal_client), NULL, &error)) {
+		report_error ("client remove sync", &error);
+		g_object_unref (cal_client);
+		return 1;
+	}
+
+	g_object_unref (cal_client);
+
+	if (get_main_loop_stop_result () == 0)
+		g_print ("Test finished successfully.\n");
+
+	return get_main_loop_stop_result ();
+}
diff --git a/tests/libecal/client/test-client-send-objects.c b/tests/libecal/client/test-client-send-objects.c
new file mode 100644
index 0000000..f8dfb7a
--- /dev/null
+++ b/tests/libecal/client/test-client-send-objects.c
@@ -0,0 +1,169 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <stdlib.h>
+#include <libecal/e-cal-client.h>
+#include <libical/ical.h>
+
+#include "client-test-utils.h"
+
+static icalcomponent *
+create_object (void)
+{
+	icalcomponent *icalcomp;
+	struct icaltimetype now;
+
+	now = icaltime_current_time_with_zone (icaltimezone_get_utc_timezone ());
+	icalcomp = icalcomponent_new (ICAL_VEVENT_COMPONENT);
+	icalcomponent_set_summary (icalcomp, "To-be-sent event summary");
+	icalcomponent_set_dtstart (icalcomp, now);
+	icalcomponent_set_dtend   (icalcomp, icaltime_from_timet (icaltime_as_timet (now) + 60 * 60 * 60, 0));
+
+	return icalcomp;
+}
+
+static gboolean
+manage_result (GSList *users, icalcomponent *modified_icalcomp)
+{
+	g_print ("Wishes to send to %d users", g_slist_length (users));
+	if (users) {
+		GSList *u;
+
+		g_print (": ");
+
+		for (u = users; u; u = u->next)
+			g_print ("%s%s", u == users ? "" : ", ", (const gchar *) u->data);
+	}
+	g_print ("\n");
+
+	if (!modified_icalcomp)
+		g_print ("No modified icalcomp, would send the same\n");
+	else
+		print_icomp (modified_icalcomp);
+
+	e_client_util_free_string_slist (users);
+	if (modified_icalcomp)
+		icalcomponent_free (modified_icalcomp);
+
+	return TRUE;
+}
+
+static gboolean
+test_sync (ECalClient *cal_client)
+{
+	GError *error = NULL;
+	icalcomponent *icalcomp, *modified_icalcomp = NULL;
+	GSList *users = NULL;
+
+	icalcomp = create_object ();
+
+	if (!e_cal_client_send_objects_sync (cal_client, icalcomp, &users, &modified_icalcomp, NULL, &error)) {
+		report_error ("send objects sync", &error);
+		icalcomponent_free (icalcomp);
+		return FALSE;
+	}
+
+	icalcomponent_free (icalcomp);
+
+	return manage_result (users, modified_icalcomp);
+}
+
+/* asynchronous callback with a main-loop running */
+static void
+async_send_result_ready (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	ECalClient *cal_client;
+	GError *error = NULL;
+	GSList *users = NULL;
+	icalcomponent *modified_icalcomp = NULL;
+
+	cal_client = E_CAL_CLIENT (source_object);
+
+	if (!e_cal_client_send_objects_finish (cal_client, result, &users, &modified_icalcomp, &error)) {
+		report_error ("send objects finish", &error);
+		stop_main_loop (1);
+		return;
+	}
+
+	stop_main_loop (manage_result (users, modified_icalcomp) ? 0 : 1);
+}
+
+/* synchronously in idle with main-loop running */
+static gboolean
+test_sync_in_idle (gpointer user_data)
+{
+	ECalClient *cal_client = user_data;
+	icalcomponent *icalcomp;
+
+	g_return_val_if_fail (cal_client != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (cal_client), FALSE);
+
+	if (!test_sync (cal_client)) {
+		stop_main_loop (1);
+		return FALSE;
+	}
+
+	icalcomp = create_object ();
+	if (!icalcomp) {
+		stop_main_loop (1);
+		return FALSE;
+	}
+
+	e_cal_client_send_objects (cal_client, icalcomp, NULL, async_send_result_ready, NULL);
+
+	icalcomponent_free (icalcomp);
+
+	return FALSE;
+}
+
+/* synchronously in a dedicated thread with main-loop running */
+static gpointer
+test_sync_in_thread (gpointer user_data)
+{
+	if (!test_sync (user_data)) {
+		stop_main_loop (1);
+		return NULL;
+	}
+
+	g_idle_add (test_sync_in_idle, user_data);
+
+	return NULL;
+}
+
+gint
+main (gint argc, gchar **argv)
+{
+	ECalClient *cal_client;
+	GError *error = NULL;
+
+	main_initialize ();
+
+	cal_client = new_temp_client (E_CAL_CLIENT_SOURCE_TYPE_EVENTS, NULL);
+	g_return_val_if_fail (cal_client != NULL, FALSE);
+
+	if (!e_client_open_sync (E_CLIENT (cal_client), FALSE, NULL, &error)) {
+		report_error ("client open sync", &error);
+		g_object_unref (cal_client);
+		return 1;
+	}
+
+	/* synchronously without main-loop */
+	if (!test_sync (cal_client)) {
+		g_object_unref (cal_client);
+		return 1;
+	}
+
+	start_in_thread_with_main_loop (test_sync_in_thread, cal_client);
+
+	if (!e_client_remove_sync (E_CLIENT (cal_client), NULL, &error)) {
+		report_error ("client remove sync", &error);
+		g_object_unref (cal_client);
+		return 1;
+	}
+
+	g_object_unref (cal_client);
+
+	if (get_main_loop_stop_result () == 0)
+		g_print ("Test finished successfully.\n");
+
+	return get_main_loop_stop_result ();
+}
diff --git a/tests/libecal/client/test-client-stress-factory--fifo.c b/tests/libecal/client/test-client-stress-factory--fifo.c
new file mode 100644
index 0000000..5a9db0a
--- /dev/null
+++ b/tests/libecal/client/test-client-stress-factory--fifo.c
@@ -0,0 +1,51 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <stdlib.h>
+#include <libecal/e-cal-client.h>
+
+#include "client-test-utils.h"
+
+#define NUM_CLIENTS 200
+
+gint
+main (gint argc, gchar **argv)
+{
+	ECalClientSourceType source_type = E_CAL_CLIENT_SOURCE_TYPE_EVENTS;
+	ECalClient *cal_clients[NUM_CLIENTS];
+	GError *error = NULL;
+	gint ii;
+
+	main_initialize ();
+
+	/* Create and open many cals; then remove each of them */
+
+	for (ii = 0; ii < NUM_CLIENTS; ii++) {
+		cal_clients[ii] = new_temp_client (source_type, NULL);
+		g_return_val_if_fail (cal_clients[ii] != NULL, 1);
+
+		if (!e_client_open_sync (E_CLIENT (cal_clients[ii]), FALSE, NULL, &error)) {
+			report_error ("client open sync", &error);
+			while (ii >= 0) {
+				g_object_unref (cal_clients[ii]);
+				ii--;
+			}
+
+			return 1;
+		}
+	}
+
+	for (ii = 0; ii < NUM_CLIENTS; ii++) {
+		if (!e_client_remove_sync (E_CLIENT (cal_clients[ii]), NULL, &error)) {
+			report_error ("client remove sync", &error);
+			while (ii < NUM_CLIENTS) {
+				g_object_unref (cal_clients[ii]);
+				ii++;
+			}
+			return 1;
+		}
+
+		g_object_unref (cal_clients[ii]);
+	}
+
+	return 0;
+}
diff --git a/tests/libecal/client/test-client-stress-factory--serial.c b/tests/libecal/client/test-client-stress-factory--serial.c
new file mode 100644
index 0000000..c178487
--- /dev/null
+++ b/tests/libecal/client/test-client-stress-factory--serial.c
@@ -0,0 +1,38 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <libecal/e-cal-client.h>
+
+#include "client-test-utils.h"
+
+#define NUM_CLIENTS 200
+
+gint
+main (gint argc, gchar **argv)
+{
+	ECalClientSourceType source_type = E_CAL_CLIENT_SOURCE_TYPE_EVENTS;
+	GError *error = NULL;
+	gint ii;
+
+	main_initialize ();
+
+	/* Serially create, open, (close), and remove many cals */
+	for (ii = 0; ii < NUM_CLIENTS; ii++) {
+		ECalClient *cal_client = new_temp_client (source_type, NULL);
+		g_return_val_if_fail (cal_client != NULL, 1);
+
+		if (!e_client_open_sync (E_CLIENT (cal_client), FALSE, NULL, &error)) {
+			report_error ("client open sync", &error);
+			return 1;
+		}
+
+		if (!e_client_remove_sync (E_CLIENT (cal_client), NULL, &error)) {
+			report_error ("client remove sync", &error);
+			g_object_unref (cal_client);
+			return 1;
+		}
+
+		g_object_unref (cal_client);
+	}
+
+	return 0;
+}
diff --git a/tests/libecal/client/test-client-stress-factory--single-cal.c b/tests/libecal/client/test-client-stress-factory--single-cal.c
new file mode 100644
index 0000000..579dffc
--- /dev/null
+++ b/tests/libecal/client/test-client-stress-factory--single-cal.c
@@ -0,0 +1,63 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <stdlib.h>
+#include <libecal/e-cal-client.h>
+
+#include "client-test-utils.h"
+
+#define NUM_OPENS 200
+
+gint
+main (gint argc, gchar **argv)
+{
+	ECalClientSourceType source_type = E_CAL_CLIENT_SOURCE_TYPE_EVENTS;
+	gchar *uri = NULL;
+	ECalClient *cal_client;
+	GError *error = NULL;
+	gint ii;
+
+	main_initialize ();
+
+	cal_client = new_temp_client (source_type, &uri);
+	g_return_val_if_fail (cal_client != NULL, 1);
+	g_return_val_if_fail (uri != NULL, 1);
+
+	g_object_unref (cal_client);
+
+	/* open and close the same cal repeatedly */
+	for (ii = 0; ii < NUM_OPENS; ii++) {
+		cal_client = e_cal_client_new_from_uri (uri, source_type, &error);
+		if (!cal_client) {
+			report_error ("new from uri", &error);
+			break;
+		}
+
+		if (!e_client_open_sync (E_CLIENT (cal_client), FALSE, NULL, &error)) {
+			report_error ("client open sync", &error);
+			g_object_unref (cal_client);
+			break;
+		}
+
+		g_object_unref (cal_client);
+	}
+
+	cal_client = e_cal_client_new_from_uri (uri, source_type, &error);
+	if (!cal_client) {
+		g_clear_error (&error);
+	} else if (!e_client_open_sync (E_CLIENT (cal_client), FALSE, NULL, &error)) {
+		report_error ("client open sync", &error);
+		g_object_unref (cal_client);
+		g_free (uri);
+		return 1;
+	} else 	if (!e_client_remove_sync (E_CLIENT (cal_client), NULL, &error)) {
+		report_error ("client remove sync", &error);
+		g_object_unref (cal_client);
+		g_free (uri);
+		return 1;
+	}
+
+	g_free (uri);
+	g_object_unref (cal_client);
+
+	return ii == NUM_OPENS ? 0 : 1;
+}
diff --git a/tests/libecal/client/test-client-stress-views.c b/tests/libecal/client/test-client-stress-views.c
new file mode 100644
index 0000000..7086b76
--- /dev/null
+++ b/tests/libecal/client/test-client-stress-views.c
@@ -0,0 +1,116 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <stdlib.h>
+#include <libecal/e-cal-client.h>
+
+#include "client-test-utils.h"
+
+#define NUM_VIEWS 200
+
+static void
+objects_added (ECalClientView *cal_view, const GSList *objects)
+{
+	const GSList *l;
+
+	for (l = objects; l; l = l->next) {
+		print_icomp (l->data);
+	}
+}
+
+static void
+objects_removed (ECalClientView *view, const GSList *ids)
+{
+	const GSList *l;
+
+	for (l = ids; l; l = l->next) {
+		printf ("   Removed contact: %s\n", (gchar *) l->data);
+	}
+}
+
+static void
+complete (ECalClientView *view, const GError *error)
+{
+	printf ("view_complete (status == %d, error_msg == %s%s%s)\n", error ? error->code : 0, error ? "'" : "", error ? error->message : "NULL", error ? "'" : "");
+}
+
+static gint
+stress_cal_views (ECalClient *cal_client, gboolean in_thread)
+{
+	ECalClientView *view = NULL;
+	ECalClientView *new_view;
+	gint i;
+
+	g_return_val_if_fail (cal_client != NULL, -1);
+	g_return_val_if_fail (E_IS_CAL_CLIENT (cal_client), -1);
+
+	for (i = 0; i < NUM_VIEWS; i++) {
+		GError *error = NULL;
+
+		if (!e_cal_client_get_view_sync (cal_client, "#t", &new_view, NULL, &error)) {
+			report_error ("get cal view sync", &error);
+			g_object_unref (view);
+			return 1;
+		}
+
+		g_signal_connect (new_view, "objects_added", G_CALLBACK (objects_added), NULL);
+		g_signal_connect (new_view, "objects_removed", G_CALLBACK (objects_removed), NULL);
+		g_signal_connect (new_view, "complete", G_CALLBACK (complete), NULL);
+
+		e_cal_client_view_start (new_view, NULL);
+
+		if (view) {
+			/* wait 100 ms when in a thread */
+			if (in_thread)
+				g_usleep (100000);
+
+			e_cal_client_view_stop (view, NULL);
+			g_object_unref (view);
+		}
+
+		view = new_view;
+	}
+
+	e_cal_client_view_stop (view, NULL);
+	g_object_unref (view);
+
+	return 0;
+}
+
+static gpointer
+stress_cal_views_thread (gpointer user_data)
+{
+	stop_main_loop (stress_cal_views (user_data, TRUE));
+
+	return NULL;
+}
+
+gint
+main (gint argc, gchar **argv)
+{
+	ECalClient *cal_client;
+	GError *error = NULL;
+
+	main_initialize ();
+
+	cal_client = e_cal_client_new_system (E_CAL_CLIENT_SOURCE_TYPE_EVENTS, &error);
+	if (!cal_client) {
+		report_error ("create local calendar", &error);
+		return 1;
+	}
+
+	if (!e_client_open_sync (E_CLIENT (cal_client), FALSE, NULL, &error)) {
+		g_object_unref (cal_client);
+		report_error ("open client sync", &error);
+		return 1;
+	}
+
+	/* test from main thread */
+	stress_cal_views (cal_client, FALSE);
+
+	/* test from dedicated thread */
+	start_in_thread_with_main_loop (stress_cal_views_thread, cal_client);
+
+	g_object_unref (cal_client);
+
+	return get_main_loop_stop_result ();
+}
diff --git a/tests/libecal/ecal-test-utils.c b/tests/libecal/ecal-test-utils.c
index 7f90366..9273796 100644
--- a/tests/libecal/ecal-test-utils.c
+++ b/tests/libecal/ecal-test-utils.c
@@ -632,7 +632,6 @@ ecal_test_utils_cal_get_free_busy (ECal   *cal,
 
 			comp_string = e_cal_component_get_as_string (comp);
 			test_print ("%s\n", comp_string);
-			g_object_unref (comp);
 			g_free (comp_string);
 		}
 	} else {
diff --git a/tests/libecal/test-ecal-get-free-busy.c b/tests/libecal/test-ecal-get-free-busy.c
index 7ed04d2..796bf98 100644
--- a/tests/libecal/test-ecal-get-free-busy.c
+++ b/tests/libecal/test-ecal-get-free-busy.c
@@ -25,8 +25,7 @@ main (gint argc, gchar **argv)
 	utc = icaltimezone_get_utc_timezone ();
 	start = time_from_isodate ("20040212T000000Z");
 	end = time_add_day_with_zone (start, 2, utc);
-	/* XXX: create dummy list, which the file backend will ignore */
-	users = g_list_prepend (users, NULL);
+	users = g_list_prepend (users, (gpointer) "user example com");
 
 	free_busy = ecal_test_utils_cal_get_free_busy (cal, users, start, end);
 
diff --git a/tests/libedataserverui/Makefile.am b/tests/libedataserverui/Makefile.am
index 4473a07..4603dff 100644
--- a/tests/libedataserverui/Makefile.am
+++ b/tests/libedataserverui/Makefile.am
@@ -1,5 +1,6 @@
 noinst_PROGRAMS = 							\
 	test-category-completion					\
+	test-client-examine-auth					\
 	test-source-combo-box						\
 	test-source-selector						\
 	test-contact-store						\
@@ -27,6 +28,10 @@ test_category_completion_CPPFLAGS = $(TEST_EDATASERVERUI_CPPFLAGS)
 test_category_completion_SOURCES = test-category-completion.c
 test_category_completion_LDADD = $(TEST_EDATASERVERUI_LDFLAGS)
 
+test_client_examine_auth_CPPFLAGS = $(TEST_EDATASERVERUI_CPPFLAGS)
+test_client_examine_auth_SOURCES = test-client-examine-auth.c
+test_client_examine_auth_LDADD = $(TEST_EDATASERVERUI_LDFLAGS)
+
 test_source_selector_CPPFLAGS = $(TEST_EDATASERVERUI_CPPFLAGS)
 test_source_selector_SOURCES = test-source-selector.c
 test_source_selector_LDADD =  $(TEST_EDATASERVERUI_LDFLAGS)
diff --git a/tests/libedataserverui/test-client-examine-auth.c b/tests/libedataserverui/test-client-examine-auth.c
new file mode 100644
index 0000000..d63f4d5
--- /dev/null
+++ b/tests/libedataserverui/test-client-examine-auth.c
@@ -0,0 +1,418 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+#include <glib.h>
+
+#include <libedataserver/e-source-group.h>
+#include <libedataserverui/e-client-utils.h>
+#include <libedataserverui/e-passwords.h>
+
+static void stop_main_loop (gint stop_result);
+static void report_error (const gchar *operation, GError **error);
+static gpointer foreach_configured_source_async_start (ESource **source);
+static gboolean foreach_configured_source_async_next (gpointer *foreach_async_data, ESource **source);
+static gboolean foreach_async (void);
+
+static gint running_async = 0;
+static EClientSourceType source_type = E_CLIENT_SOURCE_TYPE_CONTACTS;
+
+static GSList *
+get_known_prop_names (void)
+{
+	GSList *prop_names = NULL;
+
+	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_OPENED);
+	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_OPENING);
+	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_ONLINE);
+	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_READONLY);
+	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_CACHE_DIR);
+	prop_names = g_slist_append (prop_names, (gpointer) CLIENT_BACKEND_PROPERTY_CAPABILITIES);
+
+	return prop_names;
+}
+
+typedef struct _ExtraValues {
+	gpointer async_data;
+
+	GSList *todo_prop_names;
+	GHashTable *retrieved_props;
+} ExtraValues;
+
+static void
+extra_values_free (ExtraValues *evals)
+{
+	if (!evals)
+		return;
+
+	g_slist_free (evals->todo_prop_names);
+	g_hash_table_destroy (evals->retrieved_props);
+	g_free (evals);
+}
+
+static void
+print_each_property (gpointer prop_name, gpointer prop_value, gpointer user_data)
+{
+	g_return_if_fail (prop_name != NULL);
+
+	if (prop_value == NULL) {
+		g_print ("\t   %s: NULL\n", (const gchar *) prop_name);
+		return;
+	}
+
+	g_print ("\t   %s: ", (const gchar *) prop_name);
+
+	if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
+		GSList *values = e_client_util_parse_comma_strings (prop_value), *v;
+
+		
+		for (v = values; v; v = v->next) {
+			if (v != values)
+				g_print (", ");
+
+			g_print ("'%s'", (const gchar *) v->data);
+		}
+
+		e_client_util_free_string_slist (values);
+	} else {
+		g_print ("'%s'", (const gchar *) prop_value);
+	}
+
+	g_print ("\n");
+}
+
+static void
+print_values (const ExtraValues *evals, EClient *client)
+{
+	const GSList *values;
+
+	g_return_if_fail (evals != NULL);
+
+	g_print ("\treadonly:%s\n", e_client_is_readonly (client) ? "yes" : "no");
+	g_print ("\tonline:%s\n", e_client_is_online (client) ? "yes" : "no");
+	g_print ("\topened:%s\n", e_client_is_opened (client) ? "yes" : "no");
+	g_print ("\tcapabilities: ");
+	values = e_client_get_capabilities (client);
+	if (!values) {
+		g_print ("NULL");
+	} else {
+		while (values) {
+			const gchar *cap = values->data;
+
+			g_print ("'%s'", cap);
+			if (!e_client_check_capability (client, cap))
+				g_print (" (not found in EClient)");
+
+			values = values->next;
+
+			if (values)
+				g_print (", ");
+		}
+	}
+	g_print ("\n");
+
+	g_print ("\tbackend properties:\n");
+	g_hash_table_foreach (evals->retrieved_props, print_each_property, NULL);
+}
+
+static void
+identify_source (ESource *source)
+{
+	const gchar *name, *uri;
+	gchar *abs_uri = NULL;
+
+	g_return_if_fail (source != NULL);
+
+	name = e_source_peek_name (source);
+	if (!name)
+		name = "Unknown name";
+
+	uri = e_source_peek_absolute_uri (source);
+	if (!uri) {
+		abs_uri = e_source_build_absolute_uri (source);
+		uri = abs_uri;
+	}
+	if (!uri)
+		uri = e_source_peek_relative_uri (source);
+	if (!uri)
+		uri = "Unknown uri";
+
+	g_print ("\n   Checking source '%s' (%s)\n", name, uri);
+
+	g_free (abs_uri);
+}
+
+static void client_opened_async (GObject *source_object, GAsyncResult *result, gpointer async_data);
+
+static void
+continue_next_source (gpointer async_data)
+{
+	ESource *source = NULL;
+
+	g_return_if_fail (async_data != NULL);
+
+	while (async_data && foreach_configured_source_async_next (&async_data, &source)) {
+		identify_source (source);
+		e_client_utils_open_new (source, source_type, TRUE,
+			e_client_utils_authenticate_handler, NULL,
+			NULL, client_opened_async, async_data);
+		break;
+	}
+
+	if (!async_data) {
+		running_async--;
+		if (!running_async) {
+			while (source_type++, source_type < E_CLIENT_SOURCE_TYPE_LAST) {
+				if (foreach_async ())
+					return;
+			}
+
+			stop_main_loop (0);
+		}
+	}
+}
+
+static void
+client_got_backend_property_async (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	ExtraValues *evals = user_data;
+	gchar *prop_value = NULL;
+	GError *error = NULL;
+	EClient *client;
+
+	g_return_if_fail (source_object != NULL);
+	g_return_if_fail (E_IS_CLIENT (source_object));
+	g_return_if_fail (evals != NULL);
+
+	client = E_CLIENT (source_object);
+
+	if (!e_client_get_backend_property_finish (client, result, &prop_value, &error)) {
+		report_error ("get backend property finish", &error);
+	}
+
+	g_hash_table_insert (evals->retrieved_props, evals->todo_prop_names->data, prop_value);
+	evals->todo_prop_names = g_slist_remove (evals->todo_prop_names, evals->todo_prop_names->data);
+
+	if (!evals->todo_prop_names) {
+		/* to cache them, as it can be fetched with idle as well */
+		e_client_get_capabilities (client);
+
+		print_values (evals, client);
+
+		g_object_unref (source_object);
+
+		continue_next_source (evals->async_data);
+		extra_values_free (evals);
+	} else {
+		e_client_get_backend_property (client, evals->todo_prop_names->data, NULL, client_got_backend_property_async, evals);
+	}
+}
+
+static void
+client_set_backend_property_async (GObject *source_object, GAsyncResult *result, gpointer user_data)
+{
+	ExtraValues *evals = user_data;
+	GError *error = NULL;
+	EClient *client;
+
+	g_return_if_fail (source_object != NULL);
+	g_return_if_fail (E_IS_CLIENT (source_object));
+	g_return_if_fail (evals != NULL);
+
+	client = E_CLIENT (source_object);
+
+	if (!e_client_set_backend_property_finish (client, result, &error)) {
+		/* it may fail on the set_backend_property */
+		g_clear_error (&error);
+	} else {
+		g_printerr ("   Might fail on set_backend_property, but reported success\n");
+	}
+
+	e_client_get_backend_property (client, evals->todo_prop_names->data, NULL, client_got_backend_property_async, evals);
+}
+
+static void
+client_opened_async (GObject *source_object, GAsyncResult *result, gpointer async_data)
+{
+	ExtraValues *evals;
+	GError *error = NULL;
+	EClient *client = NULL;
+
+	g_return_if_fail (source_object == NULL);
+	g_return_if_fail (async_data != NULL);
+
+	if (!e_client_utils_open_new_finish (result, &client, &error)) {
+		report_error ("client utils open new finish", &error);
+		continue_next_source (async_data);
+		return;
+	}
+
+	evals = g_new0 (ExtraValues, 1);
+	evals->async_data = async_data;
+	evals->todo_prop_names = get_known_prop_names ();
+	evals->retrieved_props = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);
+
+	e_client_set_backend_property (client, "*unknown*property*", "*value*", NULL, client_set_backend_property_async, evals);
+}
+
+static gboolean
+foreach_async (void)
+{
+	gpointer async_data;
+	ESource *source = NULL;
+
+	async_data = foreach_configured_source_async_start (&source);
+	if (!async_data) {
+		stop_main_loop (1);
+		return FALSE;
+	}
+
+	running_async++;
+
+	identify_source (source);
+	e_client_utils_open_new (source, source_type, TRUE,
+		e_client_utils_authenticate_handler, NULL,
+		NULL, client_opened_async, async_data);
+
+	return TRUE;
+}
+
+static gboolean
+in_main_thread_idle_cb (gpointer unused)
+{
+	if (!foreach_async ())
+		return FALSE;
+
+	return FALSE;
+}
+
+static GMainLoop *loop = NULL;
+static gint main_stop_result = 0;
+
+static void
+stop_main_loop (gint stop_result)
+{
+	g_return_if_fail (loop != NULL);
+
+	main_stop_result = stop_result;
+	g_main_loop_quit (loop);
+}
+
+static gint
+get_main_loop_stop_result (void)
+{
+	return main_stop_result;
+}
+
+struct ForeachConfiguredData
+{
+	ESourceList *source_list;
+	GSList *current_group;
+	GSList *current_source;
+};
+
+static gpointer
+foreach_configured_source_async_start (ESource **source)
+{
+	struct ForeachConfiguredData *async_data;
+	ESourceList *source_list = NULL;
+	GError *error = NULL;
+
+	g_return_val_if_fail (source != NULL, NULL);
+
+	if (!e_client_utils_get_sources (&source_list, source_type, &error)) {
+		report_error ("get sources", &error);
+		return NULL;
+	}
+
+	g_return_val_if_fail (source_list != NULL, NULL);
+
+	async_data = g_new0 (struct ForeachConfiguredData, 1);
+	async_data->source_list = source_list;
+	async_data->current_group = e_source_list_peek_groups (source_list);
+	if (!async_data->current_group) {
+		gpointer ad = async_data;
+
+		foreach_configured_source_async_next (&ad, source);
+		return ad;
+	}
+
+	async_data->current_source = e_source_group_peek_sources (async_data->current_group->data);
+	if (!async_data->current_source) {
+		gpointer ad = async_data;
+
+		if (foreach_configured_source_async_next (&ad, source))
+			return ad;
+
+		return NULL;
+	}
+
+	*source = async_data->current_source->data;
+
+	return async_data;
+}
+
+static gboolean
+foreach_configured_source_async_next (gpointer *foreach_async_data, ESource **source)
+{
+	struct ForeachConfiguredData *async_data;
+
+	g_return_val_if_fail (foreach_async_data != NULL, FALSE);
+	g_return_val_if_fail (source != NULL, FALSE);
+
+	async_data = *foreach_async_data;
+	g_return_val_if_fail (async_data != NULL, FALSE);
+	g_return_val_if_fail (async_data->source_list != NULL, FALSE);
+	g_return_val_if_fail (async_data->current_group != NULL, FALSE);
+
+	if (async_data->current_source)
+		async_data->current_source = async_data->current_source->next;
+	if (async_data->current_source) {
+		*source = async_data->current_source->data;
+		return TRUE;
+	}
+
+	do {
+		async_data->current_group = async_data->current_group->next;
+		if (async_data->current_group)
+			async_data->current_source = e_source_group_peek_sources (async_data->current_group->data);
+	} while (async_data->current_group && !async_data->current_source);
+
+	if (async_data->current_source) {
+		*source = async_data->current_source->data;
+		return TRUE;
+	}
+
+	g_object_unref (async_data->source_list);
+	g_free (async_data);
+
+	*foreach_async_data = NULL;
+
+	return FALSE;
+}
+
+static void
+report_error (const gchar *operation, GError **error)
+{
+	g_return_if_fail (operation != NULL);
+
+	g_printerr ("Failed to %s: %s\n", operation, (error && *error) ? (*error)->message : "Unknown error");
+
+	g_clear_error (error);
+}
+
+gint
+main (gint argc, gchar **argv)
+{
+	g_type_init ();
+	g_thread_init (NULL);
+	gtk_init (&argc, &argv);
+
+	e_passwords_init ();
+
+	g_idle_add (in_main_thread_idle_cb, NULL);
+
+	loop = g_main_loop_new (NULL, FALSE);
+	g_main_loop_run (loop);
+	g_main_loop_unref (loop);
+
+	return get_main_loop_stop_result ();
+}



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