[evolution-data-server] Replace EGdbusCal with EDBusCalendar.



commit 3092e4873222d88bb3779de286542ea3a61d3346
Author: Matthew Barnes <mbarnes redhat com>
Date:   Sun Jan 27 09:29:41 2013 -0500

    Replace EGdbusCal with EDBusCalendar.

 calendar/libecal/e-cal-client.c                    | 3771 +++++++++++++-------
 calendar/libecal/e-cal-client.h                    |   48 +-
 calendar/libedata-cal/e-cal-backend.c              |   48 +-
 calendar/libedata-cal/e-cal-backend.h              |    8 +-
 calendar/libedata-cal/e-data-cal.c                 | 1020 ++++--
 calendar/libedata-cal/e-data-cal.h                 |    8 +-
 calendar/libegdbus/Makefile.am                     |    2 -
 calendar/libegdbus/e-gdbus-cal.c                   | 2078 -----------
 calendar/libegdbus/e-gdbus-cal.h                   |  316 --
 .../libedata-cal/libedata-cal-sections.txt         |    8 +-
 10 files changed, 3265 insertions(+), 4042 deletions(-)
---
diff --git a/calendar/libecal/e-cal-client.c b/calendar/libecal/e-cal-client.c
index 5403c96..9670229 100644
--- a/calendar/libecal/e-cal-client.c
+++ b/calendar/libecal/e-cal-client.c
@@ -27,6 +27,7 @@
 #include <gio/gio.h>
 
 /* Private D-Bus classes. */
+#include <e-dbus-calendar.h>
 #include <e-dbus-calendar-factory.h>
 
 #include <libedataserver/e-client-private.h>
@@ -39,22 +40,63 @@
 #include "e-cal-types.h"
 #include "e-timezone-cache.h"
 
-#include "e-gdbus-cal.h"
-
 #define E_CAL_CLIENT_GET_PRIVATE(obj) \
 	(G_TYPE_INSTANCE_GET_PRIVATE \
 	((obj), E_TYPE_CAL_CLIENT, ECalClientPrivate))
 
+/* Set this to a sufficiently large value
+ * to cover most long-running operations. */
+#define DBUS_PROXY_TIMEOUT_MS (3 * 60 * 1000)  /* 3 minutes */
+
+typedef struct _AsyncContext AsyncContext;
+typedef struct _SignalClosure SignalClosure;
+typedef struct _RunInThreadClosure RunInThreadClosure;
+
 struct _ECalClientPrivate {
-	GDBusProxy *dbus_proxy;
+	EDBusCalendar *dbus_proxy;
+	GMainContext *main_context;
 	guint gone_signal_id;
 
 	ECalClientSourceType source_type;
 	icaltimezone *default_zone;
-	gchar *cache_dir;
 
 	GMutex zone_cache_lock;
 	GHashTable *zone_cache;
+
+	gulong dbus_proxy_error_handler_id;
+	gulong dbus_proxy_notify_handler_id;
+	gulong dbus_proxy_free_busy_data_handler_id;
+};
+
+struct _AsyncContext {
+	ECalClientView *client_view;
+	icalcomponent *in_comp;
+	icalcomponent *out_comp;
+	icaltimezone *zone;
+	GSList *comp_list;
+	GSList *object_list;
+	GSList *string_list;
+	gchar *sexp;
+	gchar *tzid;
+	gchar *uid;
+	gchar *rid;
+	gchar *auid;
+	CalObjModType mod;
+	time_t start;
+	time_t end;
+};
+
+struct _SignalClosure {
+	EClient *client;
+	gchar *property_name;
+	gchar *error_message;
+	gchar **free_busy_data;
+};
+
+struct _RunInThreadClosure {
+	GSimpleAsyncThreadFunc func;
+	GSimpleAsyncResult *simple;
+	GCancellable *cancellable;
 };
 
 enum {
@@ -68,6 +110,10 @@ enum {
 };
 
 /* Forward Declarations */
+static void	e_cal_client_initable_init
+					(GInitableIface *interface);
+static void	e_cal_client_async_initable_init
+					(GAsyncInitableIface *interface);
 static void	e_cal_client_timezone_cache_init
 					(ETimezoneCacheInterface *interface);
 
@@ -78,10 +124,77 @@ G_DEFINE_TYPE_WITH_CODE (
 	e_cal_client,
 	E_TYPE_CLIENT,
 	G_IMPLEMENT_INTERFACE (
+		G_TYPE_INITABLE,
+		e_cal_client_initable_init)
+	G_IMPLEMENT_INTERFACE (
+		G_TYPE_ASYNC_INITABLE,
+		e_cal_client_async_initable_init)
+	G_IMPLEMENT_INTERFACE (
 		E_TYPE_TIMEZONE_CACHE,
 		e_cal_client_timezone_cache_init))
 
 static void
+async_context_free (AsyncContext *async_context)
+{
+	if (async_context->client_view != NULL)
+		g_object_unref (async_context->client_view);
+
+	if (async_context->in_comp != NULL)
+		icalcomponent_free (async_context->in_comp);
+
+	if (async_context->out_comp != NULL)
+		icalcomponent_free (async_context->out_comp);
+
+	if (async_context->zone != NULL)
+		icaltimezone_free (async_context->zone, 1);
+
+	g_slist_free_full (
+		async_context->comp_list,
+		(GDestroyNotify) icalcomponent_free);
+
+	g_slist_free_full (
+		async_context->object_list,
+		(GDestroyNotify) g_object_unref);
+
+	g_slist_free_full (
+		async_context->string_list,
+		(GDestroyNotify) g_free);
+
+	g_free (async_context->sexp);
+	g_free (async_context->tzid);
+	g_free (async_context->uid);
+	g_free (async_context->rid);
+	g_free (async_context->auid);
+
+	g_slice_free (AsyncContext, async_context);
+}
+
+static void
+signal_closure_free (SignalClosure *signal_closure)
+{
+	g_object_unref (signal_closure->client);
+
+	g_free (signal_closure->property_name);
+	g_free (signal_closure->error_message);
+
+	g_strfreev (signal_closure->free_busy_data);
+
+	g_slice_free (SignalClosure, signal_closure);
+}
+
+static void
+run_in_thread_closure_free (RunInThreadClosure *run_in_thread_closure)
+{
+	if (run_in_thread_closure->simple != NULL)
+		g_object_unref (run_in_thread_closure->simple);
+
+	if (run_in_thread_closure->cancellable != NULL)
+		g_object_unref (run_in_thread_closure->cancellable);
+
+	g_slice_free (RunInThreadClosure, run_in_thread_closure);
+}
+
+static void
 free_zone_cb (gpointer zone)
 {
 	icaltimezone_free (zone, 1);
@@ -326,6 +439,107 @@ gdbus_cal_factory_activate (GCancellable *cancellable,
 	return TRUE;
 }
 
+static gpointer
+cal_client_dbus_thread (gpointer user_data)
+{
+	GMainContext *main_context = user_data;
+	GMainLoop *main_loop;
+
+	g_main_context_push_thread_default (main_context);
+
+	main_loop = g_main_loop_new (main_context, FALSE);
+	g_main_loop_run (main_loop);
+	g_main_loop_unref (main_loop);
+
+	g_main_context_pop_thread_default (main_context);
+
+	g_main_context_unref (main_context);
+
+	return NULL;
+}
+
+static gpointer
+cal_client_dbus_thread_init (gpointer unused)
+{
+	GMainContext *main_context;
+
+	main_context = g_main_context_new ();
+
+	/* This thread terminates when the process itself terminates, so
+	 * no need to worry about unreferencing the returned GThread. */
+	g_thread_new (
+		"cal-client-dbus-thread",
+		cal_client_dbus_thread,
+		g_main_context_ref (main_context));
+
+	return main_context;
+}
+
+static GMainContext *
+cal_client_ref_dbus_main_context (void)
+{
+	static GOnce cal_client_dbus_thread_once = G_ONCE_INIT;
+
+	g_once (
+		&cal_client_dbus_thread_once,
+		cal_client_dbus_thread_init, NULL);
+
+	return g_main_context_ref (cal_client_dbus_thread_once.retval);
+}
+
+static gboolean
+cal_client_run_in_dbus_thread_idle_cb (gpointer user_data)
+{
+	RunInThreadClosure *closure = user_data;
+	GObject *source_object;
+	GAsyncResult *result;
+
+	result = G_ASYNC_RESULT (closure->simple);
+	source_object = g_async_result_get_source_object (result);
+
+	closure->func (
+		closure->simple,
+		source_object,
+		closure->cancellable);
+
+	if (source_object != NULL)
+		g_object_unref (source_object);
+
+	g_simple_async_result_complete_in_idle (closure->simple);
+
+	return FALSE;
+}
+
+static void
+cal_client_run_in_dbus_thread (GSimpleAsyncResult *simple,
+                               GSimpleAsyncThreadFunc func,
+                               gint io_priority,
+                               GCancellable *cancellable)
+{
+	RunInThreadClosure *closure;
+	GMainContext *main_context;
+	GSource *idle_source;
+
+	main_context = cal_client_ref_dbus_main_context ();
+
+	closure = g_slice_new0 (RunInThreadClosure);
+	closure->func = func;
+	closure->simple = g_object_ref (simple);
+
+	if (G_IS_CANCELLABLE (cancellable))
+		closure->cancellable = g_object_ref (cancellable);
+
+	idle_source = g_idle_source_new ();
+	g_source_set_priority (idle_source, io_priority);
+	g_source_set_callback (
+		idle_source, cal_client_run_in_dbus_thread_idle_cb,
+		closure, (GDestroyNotify) run_in_thread_closure_free);
+	g_source_attach (idle_source, main_context);
+	g_source_unref (idle_source);
+
+	g_main_context_unref (main_context);
+}
+
 static void gdbus_cal_client_disconnect (ECalClient *client);
 
 /*
@@ -385,7 +599,8 @@ gdbus_cal_client_disconnect (ECalClient *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->dbus_proxy, NULL, NULL);
+		e_dbus_calendar_call_close_sync (
+			client->priv->dbus_proxy, NULL, NULL);
 		g_object_unref (client->priv->dbus_proxy);
 		client->priv->dbus_proxy = NULL;
 	}
@@ -393,151 +608,208 @@ gdbus_cal_client_disconnect (ECalClient *client)
 	UNLOCK_FACTORY ();
 }
 
-static void
-backend_error_cb (EGdbusCal *object,
-                  const gchar *message,
-                  ECalClient *client)
-{
-	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)
+static gboolean
+cal_client_emit_backend_error_idle_cb (gpointer user_data)
 {
-	g_return_if_fail (E_IS_CAL_CLIENT (client));
+	SignalClosure *signal_closure = user_data;
 
-	e_client_set_readonly (E_CLIENT (client), readonly);
-}
-
-static void
-online_cb (EGdbusCal *object,
-           gboolean is_online,
-           ECalClient *client)
-{
-	g_return_if_fail (E_IS_CAL_CLIENT (client));
+	g_signal_emit_by_name (
+		signal_closure->client,
+		"backend-error",
+		signal_closure->error_message);
 
-	e_client_set_online (E_CLIENT (client), is_online);
+	return FALSE;
 }
 
-static void
-opened_cb (EGdbusCal *object,
-           const gchar * const *error_strv,
-           ECalClient *client)
-{
-	GError *error = 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);
+static gboolean
+cal_client_emit_backend_property_changed_idle_cb (gpointer user_data)
+{
+	SignalClosure *signal_closure = user_data;
+	gchar *prop_value = NULL;
+
+	/* XXX Despite appearances, this function does not block. */
+	e_client_get_backend_property_sync (
+		signal_closure->client,
+		signal_closure->property_name,
+		&prop_value, NULL, NULL);
+
+	if (prop_value != NULL) {
+		g_signal_emit_by_name (
+			signal_closure->client,
+			"backend-property-changed",
+			signal_closure->property_name,
+			prop_value);
+		g_free (prop_value);
+	}
 
-	if (error)
-		g_error_free (error);
+	return FALSE;
 }
 
-static void
-free_busy_data_cb (EGdbusCal *object,
-                   const gchar * const *free_busy_strv,
-                   ECalClient *client)
+static gboolean
+cal_client_emit_free_busy_data_idle_cb (gpointer user_data)
 {
-	GSList *ecalcomps = NULL;
+	SignalClosure *signal_closure = user_data;
+	GSList *list = NULL;
+	gchar **strv;
 	gint ii;
 
-	g_return_if_fail (E_IS_CAL_CLIENT (client));
-	g_return_if_fail (free_busy_strv != NULL);
+	strv = signal_closure->free_busy_data;
 
-	for (ii = 0; free_busy_strv[ii]; ii++) {
+	for (ii = 0; strv[ii] != NULL; ii++) {
 		ECalComponent *comp;
 		icalcomponent *icalcomp;
 		icalcomponent_kind kind;
 
-		icalcomp = icalcomponent_new_from_string (free_busy_strv[ii]);
-		if (!icalcomp)
+		icalcomp = icalcomponent_new_from_string (strv[ii]);
+		if (icalcomp == NULL)
 			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;
-			}
+		if (kind != ICAL_VFREEBUSY_COMPONENT) {
+			icalcomponent_free (icalcomp);
+			continue;
+		}
 
-			ecalcomps = g_slist_prepend (ecalcomps, comp);
-		} else {
+		comp = e_cal_component_new ();
+		if (!e_cal_component_set_icalcomponent (comp, icalcomp)) {
 			icalcomponent_free (icalcomp);
+			g_object_unref (comp);
+			continue;
 		}
+
+		list = g_slist_prepend (list, comp);
 	}
 
-	ecalcomps = g_slist_reverse (ecalcomps);
+	list = g_slist_reverse (list);
+
+	g_signal_emit (
+		signal_closure->client,
+		signals[FREE_BUSY_DATA], 0, list);
 
-	g_signal_emit (client, signals[FREE_BUSY_DATA], 0, ecalcomps);
+	g_slist_free_full (list, (GDestroyNotify) g_object_unref);
 
-	e_client_util_free_object_slist (ecalcomps);
+	return FALSE;
 }
 
 static void
-backend_property_changed_cb (EGdbusCal *object,
-                             const gchar * const *name_value_strv,
-                             ECalClient *client)
+cal_client_dbus_proxy_error_cb (EDBusCalendar *dbus_proxy,
+                                const gchar *error_message,
+                                ECalClient *cal_client)
 {
-	gchar *prop_name = NULL, *prop_value = NULL;
-
-	g_return_if_fail (E_IS_CAL_CLIENT (client));
-	g_return_if_fail (name_value_strv != NULL);
-	g_return_if_fail (e_gdbus_templates_decode_two_strings (name_value_strv, &prop_name, &prop_value));
-	g_return_if_fail (prop_name != NULL);
-	g_return_if_fail (*prop_name);
-	g_return_if_fail (prop_value != NULL);
+	GSource *idle_source;
+	SignalClosure *signal_closure;
 
-	e_client_emit_backend_property_changed (E_CLIENT (client), prop_name, prop_value);
+	signal_closure = g_slice_new0 (SignalClosure);
+	signal_closure->client = g_object_ref (cal_client);
+	signal_closure->error_message = g_strdup (error_message);
 
-	g_free (prop_name);
-	g_free (prop_value);
+	idle_source = g_idle_source_new ();
+	g_source_set_callback (
+		idle_source,
+		cal_client_emit_backend_error_idle_cb,
+		signal_closure,
+		(GDestroyNotify) signal_closure_free);
+	g_source_attach (idle_source, cal_client->priv->main_context);
+	g_source_unref (idle_source);
 }
 
-/*
- * Converts a GSList of icalcomponents into a NULL-terminated array of
- * valid UTF-8 strings, suitable for sending over DBus.
- */
-static gchar **
-icalcomponent_slist_to_utf8_icomp_array (GSList *icalcomponents)
-{
-	gchar **array;
-	const GSList *l;
-	gint i = 0;
-
-	array = g_new0 (gchar *, g_slist_length (icalcomponents) + 1);
-	for (l = icalcomponents; l != NULL; l = l->next) {
-		gchar *comp_str = icalcomponent_as_ical_string_r ((icalcomponent *) l->data);
-		array[i++] = e_util_utf8_make_valid (comp_str);
-		g_free (comp_str);
+static void
+cal_client_dbus_proxy_notify_cb (EDBusCalendar *dbus_proxy,
+                                 GParamSpec *pspec,
+                                 ECalClient *cal_client)
+{
+	const gchar *backend_prop_name = NULL;
+
+	if (g_str_equal (pspec->name, "alarm-email-address")) {
+		backend_prop_name = CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS;
+	}
+
+	if (g_str_equal (pspec->name, "cache-dir")) {
+		backend_prop_name = CLIENT_BACKEND_PROPERTY_CACHE_DIR;
+	}
+
+	if (g_str_equal (pspec->name, "cal-email-address")) {
+		backend_prop_name = CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS;
+	}
+
+	if (g_str_equal (pspec->name, "capabilities")) {
+		gchar **strv;
+		gchar *csv;
+
+		backend_prop_name = CLIENT_BACKEND_PROPERTY_CAPABILITIES;
+
+		strv = e_dbus_calendar_dup_capabilities (dbus_proxy);
+		csv = g_strjoinv (",", strv);
+		e_client_set_capabilities (E_CLIENT (cal_client), csv);
+		g_free (csv);
+		g_free (strv);
+	}
+
+	if (g_str_equal (pspec->name, "default-object")) {
+		backend_prop_name = CAL_BACKEND_PROPERTY_DEFAULT_OBJECT;
+	}
+
+	if (g_str_equal (pspec->name, "online")) {
+		gboolean online;
+
+		backend_prop_name = CLIENT_BACKEND_PROPERTY_ONLINE;
+
+		online = e_dbus_calendar_get_online (dbus_proxy);
+		e_client_set_online (E_CLIENT (cal_client), online);
+	}
+
+	if (g_str_equal (pspec->name, "revision")) {
+		backend_prop_name = CLIENT_BACKEND_PROPERTY_REVISION;
+	}
+
+	if (g_str_equal (pspec->name, "writable")) {
+		gboolean writable;
+
+		backend_prop_name = CLIENT_BACKEND_PROPERTY_READONLY;
+
+		writable = e_dbus_calendar_get_writable (dbus_proxy);
+		e_client_set_readonly (E_CLIENT (cal_client), !writable);
 	}
 
-	return array;
+	if (backend_prop_name != NULL) {
+		GSource *idle_source;
+		SignalClosure *signal_closure;
+
+		signal_closure = g_slice_new0 (SignalClosure);
+		signal_closure->client = g_object_ref (cal_client);
+		signal_closure->property_name = g_strdup (backend_prop_name);
+
+		idle_source = g_idle_source_new ();
+		g_source_set_callback (
+			idle_source,
+			cal_client_emit_backend_property_changed_idle_cb,
+			signal_closure,
+			(GDestroyNotify) signal_closure_free);
+		g_source_attach (idle_source, cal_client->priv->main_context);
+		g_source_unref (idle_source);
+	}
 }
 
-/*
- * Converts a GSList of icalcomponents into a GSList of strings.
- */
-static GSList *
-icalcomponent_slist_to_string_slist (GSList *icalcomponents)
+static void
+cal_client_dbus_proxy_free_busy_data_cb (EDBusCalendar *dbus_proxy,
+                                         gchar **free_busy_data,
+                                         ECalClient *cal_client)
 {
-	GSList *strings = NULL;
-	const GSList *l;
+	GSource *idle_source;
+	SignalClosure *signal_closure;
 
-	for (l = icalcomponents; l != NULL; l = l->next) {
-		strings = g_slist_prepend (strings, icalcomponent_as_ical_string_r ((icalcomponent *) l->data));
-	}
+	signal_closure = g_slice_new0 (SignalClosure);
+	signal_closure->client = g_object_ref (cal_client);
+	signal_closure->free_busy_data = g_strdupv (free_busy_data);
 
-	return g_slist_reverse (strings);
+	idle_source = g_idle_source_new ();
+	g_source_set_callback (
+		idle_source,
+		cal_client_emit_free_busy_data_idle_cb,
+		signal_closure,
+		(GDestroyNotify) signal_closure_free);
+	g_source_attach (idle_source, cal_client->priv->main_context);
+	g_source_unref (idle_source);
 }
 
 static void
@@ -585,13 +857,39 @@ cal_client_get_property (GObject *object,
 static void
 cal_client_dispose (GObject *object)
 {
-	EClient *client;
+	ECalClientPrivate *priv;
 
-	client = E_CLIENT (object);
+	priv = E_CAL_CLIENT_GET_PRIVATE (object);
 
-	e_client_cancel_all (client);
+	e_client_cancel_all (E_CLIENT (object));
 
-	gdbus_cal_client_disconnect (E_CAL_CLIENT (client));
+	if (priv->dbus_proxy_error_handler_id > 0) {
+		g_signal_handler_disconnect (
+			priv->dbus_proxy,
+			priv->dbus_proxy_error_handler_id);
+		priv->dbus_proxy_error_handler_id = 0;
+	}
+
+	if (priv->dbus_proxy_notify_handler_id > 0) {
+		g_signal_handler_disconnect (
+			priv->dbus_proxy,
+			priv->dbus_proxy_notify_handler_id);
+		priv->dbus_proxy_notify_handler_id = 0;
+	}
+
+	if (priv->dbus_proxy_free_busy_data_handler_id > 0) {
+		g_signal_handler_disconnect (
+			priv->dbus_proxy,
+			priv->dbus_proxy_free_busy_data_handler_id);
+		priv->dbus_proxy_free_busy_data_handler_id = 0;
+	}
+
+	gdbus_cal_client_disconnect (E_CAL_CLIENT (object));
+
+	if (priv->main_context != NULL) {
+		g_main_context_unref (priv->main_context);
+		priv->main_context = NULL;
+	}
 
 	/* Chain up to parent's dispose() method. */
 	G_OBJECT_CLASS (e_cal_client_parent_class)->dispose (object);
@@ -607,17 +905,13 @@ cal_client_finalize (GObject *object)
 
 	priv = client->priv;
 
-	g_free (priv->cache_dir);
-	priv->cache_dir = NULL;
-
 	if (priv->default_zone && priv->default_zone != icaltimezone_get_utc_timezone ())
 		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_clear (&priv->zone_cache_lock);
 
 	/* Chain up to parent's finalize() method. */
@@ -637,7 +931,7 @@ cal_client_get_dbus_proxy (EClient *client)
 
 	priv = E_CAL_CLIENT_GET_PRIVATE (client);
 
-	return priv->dbus_proxy;
+	return G_DBUS_PROXY (priv->dbus_proxy);
 }
 
 static void
@@ -648,61 +942,15 @@ cal_client_unwrap_dbus_error (EClient *client,
 	unwrap_dbus_error (dbus_error, out_error);
 }
 
-static void
-cal_client_retrieve_capabilities (EClient *client,
-                                  GCancellable *cancellable,
-                                  GAsyncReadyCallback callback,
-                                  gpointer user_data)
-{
-	g_return_if_fail (E_IS_CAL_CLIENT (client));
-
-	e_client_get_backend_property (client, CLIENT_BACKEND_PROPERTY_CAPABILITIES, cancellable, callback, user_data);
-}
-
-static gboolean
-cal_client_retrieve_capabilities_finish (EClient *client,
-                                         GAsyncResult *result,
-                                         gchar **capabilities,
-                                         GError **error)
-{
-	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
-
-	return e_client_get_backend_property_finish (client, result, capabilities, error);
-}
-
 static gboolean
 cal_client_retrieve_capabilities_sync (EClient *client,
                                        gchar **capabilities,
                                        GCancellable *cancellable,
                                        GError **error)
 {
-	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
-
-	return e_client_get_backend_property_sync (client, CLIENT_BACKEND_PROPERTY_CAPABILITIES, capabilities, cancellable, error);
-}
-
-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_with_res_op_data (
-		client, prop_name, cancellable, callback, user_data, cal_client_get_backend_property, prop_name,
-		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)
-{
-	g_return_val_if_fail (prop_value != NULL, FALSE);
-
-	return e_client_proxy_call_finish_string (client, result, prop_value, error, cal_client_get_backend_property);
+	return e_client_get_backend_property_sync (
+		client, CLIENT_BACKEND_PROPERTY_CAPABILITIES,
+		capabilities, cancellable, error);
 }
 
 static gboolean
@@ -713,17 +961,72 @@ cal_client_get_backend_property_sync (EClient *client,
                                       GError **error)
 {
 	ECalClient *cal_client;
-
-	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+	EDBusCalendar *dbus_proxy;
+	gchar **strv;
 
 	cal_client = E_CAL_CLIENT (client);
+	dbus_proxy = cal_client->priv->dbus_proxy;
 
-	if (cal_client->priv->dbus_proxy == NULL) {
-		set_proxy_gone_error (error);
-		return FALSE;
+	if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_OPENED)) {
+		*prop_value = g_strdup ("TRUE");
+		return TRUE;
+	}
+
+	if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_OPENING)) {
+		*prop_value = g_strdup ("FALSE");
+		return TRUE;
+	}
+
+	if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_ONLINE)) {
+		if (e_dbus_calendar_get_online (dbus_proxy))
+			*prop_value = g_strdup ("TRUE");
+		else
+			*prop_value = g_strdup ("FALSE");
+		return TRUE;
+	}
+
+	if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_READONLY)) {
+		if (e_dbus_calendar_get_writable (dbus_proxy))
+			*prop_value = g_strdup ("FALSE");
+		else
+			*prop_value = g_strdup ("TRUE");
+		return TRUE;
+	}
+
+	if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CACHE_DIR)) {
+		*prop_value = e_dbus_calendar_dup_cache_dir (dbus_proxy);
+		return TRUE;
 	}
 
-	return e_client_proxy_call_sync_string__string (client, prop_name, prop_value, cancellable, error, e_gdbus_cal_call_get_backend_property_sync);
+	if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_REVISION)) {
+		*prop_value = e_dbus_calendar_dup_revision (dbus_proxy);
+		return TRUE;
+	}
+
+	if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
+		strv = e_dbus_calendar_dup_capabilities (dbus_proxy);
+		*prop_value = g_strjoinv (",", strv);
+		g_strfreev (strv);
+		return TRUE;
+	}
+
+	if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS)) {
+		*prop_value = e_dbus_calendar_dup_alarm_email_address (dbus_proxy);
+	}
+
+	if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS)) {
+		*prop_value = e_dbus_calendar_dup_cal_email_address (dbus_proxy);
+	}
+
+	if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_DEFAULT_OBJECT)) {
+		*prop_value = e_dbus_calendar_dup_default_object (dbus_proxy);
+	}
+
+	g_set_error (
+		error, E_CLIENT_ERROR, E_CLIENT_ERROR_NOT_SUPPORTED,
+		_("Unknown calendar property '%s'"), prop_name);
+
+	return FALSE;
 }
 
 static gboolean
@@ -742,27 +1045,6 @@ cal_client_set_backend_property_sync (EClient *client,
 	return FALSE;
 }
 
-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,
@@ -780,33 +1062,14 @@ cal_client_open_sync (EClient *client,
 		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_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);
+	return e_dbus_calendar_call_open_sync (
+		cal_client->priv->dbus_proxy, cancellable, error);
 }
 
 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)
+cal_client_refresh_sync (EClient *client,
+                         GCancellable *cancellable,
+                         GError **error)
 {
 	ECalClient *cal_client;
 
@@ -819,7 +1082,190 @@ cal_client_refresh_sync (EClient *client,
 		return FALSE;
 	}
 
-	return e_client_proxy_call_sync_void__void (client, cancellable, error, e_gdbus_cal_call_refresh_sync);
+	return e_dbus_calendar_call_refresh_sync (
+		cal_client->priv->dbus_proxy, cancellable, error);
+}
+
+static void
+cal_client_init_in_dbus_thread (GSimpleAsyncResult *simple,
+                                GObject *source_object,
+                                GCancellable *cancellable)
+{
+	ECalClientPrivate *priv;
+	EClient *client;
+	ESource *source;
+	GDBusConnection *connection;
+	const gchar *uid;
+	gchar *object_path = NULL;
+	gulong handler_id;
+	GError *error = NULL;
+
+	priv = E_CAL_CLIENT_GET_PRIVATE (source_object);
+
+	client = E_CLIENT (source_object);
+	source = e_client_get_source (client);
+	uid = e_source_get_uid (source);
+
+	LOCK_FACTORY ();
+	gdbus_cal_factory_activate (cancellable, &error);
+	UNLOCK_FACTORY ();
+
+	if (error != NULL) {
+		unwrap_dbus_error (error, &error);
+		g_simple_async_result_take_error (simple, error);
+		return;
+	}
+
+	switch (e_cal_client_get_source_type (E_CAL_CLIENT (client))) {
+		case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+			e_dbus_calendar_factory_call_open_calendar_sync (
+				cal_factory, uid, &object_path,
+				cancellable, &error);
+			break;
+		case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+			e_dbus_calendar_factory_call_open_task_list_sync (
+				cal_factory, uid, &object_path,
+				cancellable, &error);
+			break;
+		case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+			e_dbus_calendar_factory_call_open_memo_list_sync (
+				cal_factory, uid, &object_path,
+				cancellable, &error);
+			break;
+		default:
+			g_return_if_reached ();
+	}
+
+	/* Sanity check. */
+	g_return_if_fail (
+		((object_path != NULL) && (error == NULL)) ||
+		((object_path == NULL) && (error != NULL)));
+
+	if (object_path == NULL) {
+		unwrap_dbus_error (error, &error);
+		g_simple_async_result_take_error (simple, error);
+		return;
+	}
+
+	connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (cal_factory));
+
+	priv->dbus_proxy = e_dbus_calendar_proxy_new_sync (
+		connection,
+		G_DBUS_PROXY_FLAGS_NONE,
+		CALENDAR_DBUS_SERVICE_NAME,
+		object_path,
+		cancellable, &error);
+
+	g_free (object_path);
+
+	/* Sanity check. */
+	g_return_if_fail (
+		((priv->dbus_proxy != NULL) && (error == NULL)) ||
+		((priv->dbus_proxy == NULL) && (error != NULL)));
+
+	if (error != NULL) {
+		unwrap_dbus_error (error, &error);
+		g_simple_async_result_take_error (simple, error);
+		return;
+	}
+
+	g_dbus_proxy_set_default_timeout (
+		G_DBUS_PROXY (priv->dbus_proxy), DBUS_PROXY_TIMEOUT_MS);
+
+	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);
+
+	handler_id = g_signal_connect (
+		priv->dbus_proxy, "error",
+		G_CALLBACK (cal_client_dbus_proxy_error_cb), client);
+	priv->dbus_proxy_error_handler_id = handler_id;
+
+	handler_id = g_signal_connect (
+		priv->dbus_proxy, "notify",
+		G_CALLBACK (cal_client_dbus_proxy_notify_cb), client);
+	priv->dbus_proxy_notify_handler_id = handler_id;
+
+	handler_id = g_signal_connect (
+		priv->dbus_proxy, "free-busy-data",
+		G_CALLBACK (cal_client_dbus_proxy_free_busy_data_cb), client);
+	priv->dbus_proxy_free_busy_data_handler_id = handler_id;
+}
+
+static gboolean
+cal_client_initable_init (GInitable *initable,
+                          GCancellable *cancellable,
+                          GError **error)
+{
+	EAsyncClosure *closure;
+	GAsyncResult *result;
+	gboolean success;
+
+	closure = e_async_closure_new ();
+
+	g_async_initable_init_async (
+		G_ASYNC_INITABLE (initable),
+		G_PRIORITY_DEFAULT, cancellable,
+		e_async_closure_callback, closure);
+
+	result = e_async_closure_wait (closure);
+
+	success = g_async_initable_init_finish (
+		G_ASYNC_INITABLE (initable), result, error);
+
+	e_async_closure_free (closure);
+
+	return success;
+}
+
+static void
+cal_client_initable_init_async (GAsyncInitable *initable,
+                                gint io_priority,
+                                GCancellable *cancellable,
+                                GAsyncReadyCallback callback,
+                                gpointer user_data)
+{
+	GSimpleAsyncResult *simple;
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (initable), callback, user_data,
+		cal_client_initable_init_async);
+
+	g_simple_async_result_set_check_cancellable (simple, cancellable);
+
+	cal_client_run_in_dbus_thread (
+		simple, cal_client_init_in_dbus_thread,
+		io_priority, cancellable);
+
+	g_object_unref (simple);
+}
+
+static gboolean
+cal_client_initable_init_finish (GAsyncInitable *initable,
+                                 GAsyncResult *result,
+                                 GError **error)
+{
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (initable),
+		cal_client_initable_init_async), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
 }
 
 static void
@@ -977,21 +1423,13 @@ e_cal_client_class_init (ECalClientClass *class)
 	object_class->finalize = cal_client_finalize;
 
 	client_class = E_CLIENT_CLASS (class);
-	client_class->get_dbus_proxy			= cal_client_get_dbus_proxy;
-	client_class->unwrap_dbus_error			= cal_client_unwrap_dbus_error;
-	client_class->retrieve_capabilities		= cal_client_retrieve_capabilities;
-	client_class->retrieve_capabilities_finish	= cal_client_retrieve_capabilities_finish;
-	client_class->retrieve_capabilities_sync	= cal_client_retrieve_capabilities_sync;
-	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_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->refresh				= cal_client_refresh;
-	client_class->refresh_finish			= cal_client_refresh_finish;
-	client_class->refresh_sync			= cal_client_refresh_sync;
+	client_class->get_dbus_proxy = cal_client_get_dbus_proxy;
+	client_class->unwrap_dbus_error = cal_client_unwrap_dbus_error;
+	client_class->retrieve_capabilities_sync = cal_client_retrieve_capabilities_sync;
+	client_class->get_backend_property_sync = cal_client_get_backend_property_sync;
+	client_class->set_backend_property_sync = cal_client_set_backend_property_sync;
+	client_class->open_sync = cal_client_open_sync;
+	client_class->refresh_sync = cal_client_refresh_sync;
 
 	g_object_class_install_property (
 		object_class,
@@ -1018,6 +1456,19 @@ e_cal_client_class_init (ECalClientClass *class)
 }
 
 static void
+e_cal_client_initable_init (GInitableIface *interface)
+{
+	interface->init = cal_client_initable_init;
+}
+
+static void
+e_cal_client_async_initable_init (GAsyncInitableIface *interface)
+{
+	interface->init_async = cal_client_initable_init_async;
+	interface->init_finish = cal_client_initable_init_finish;
+}
+
+static void
 e_cal_client_timezone_cache_init (ETimezoneCacheInterface *interface)
 {
 	interface->add_timezone = cal_client_add_cached_timezone;
@@ -1045,6 +1496,10 @@ e_cal_client_init (ECalClient *client)
 	client->priv->default_zone = icaltimezone_get_utc_timezone ();
 	g_mutex_init (&client->priv->zone_cache_lock);
 	client->priv->zone_cache = zone_cache;
+
+	/* This is so the D-Bus thread can schedule signal emissions
+	 * on the thread-default context for this thread. */
+	client->priv->main_context = g_main_context_ref_thread_default ();
 }
 
 /**
@@ -1066,133 +1521,15 @@ e_cal_client_new (ESource *source,
                   ECalClientSourceType source_type,
                   GError **error)
 {
-	ECalClient *client;
-	GError *err = NULL;
-	GDBusConnection *connection;
-	const gchar *uid;
-	gchar *object_path = 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);
 
-	LOCK_FACTORY ();
-	/* XXX Oops, e_cal_client_new() forgot to take a GCancellable. */
-	if (!gdbus_cal_factory_activate (NULL, &err)) {
-		UNLOCK_FACTORY ();
-		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;
-	}
-
-	uid = e_source_get_uid (source);
-
-	client = g_object_new (
-		E_TYPE_CAL_CLIENT,
+	return g_initable_new (
+		E_TYPE_CAL_CLIENT, NULL, error,
 		"source", source, "source-type", source_type, NULL);
-
-	UNLOCK_FACTORY ();
-
-	switch (source_type) {
-		case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
-			e_dbus_calendar_factory_call_open_calendar_sync (
-				cal_factory, uid, &object_path, NULL, &err);
-			break;
-		case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
-			e_dbus_calendar_factory_call_open_task_list_sync (
-				cal_factory, uid, &object_path, NULL, &err);
-			break;
-		case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
-			e_dbus_calendar_factory_call_open_memo_list_sync (
-				cal_factory, uid, &object_path, NULL, &err);
-			break;
-		default:
-			g_return_val_if_reached (NULL);
-	}
-
-	/* Sanity check. */
-	g_return_val_if_fail (
-		((object_path != NULL) && (err == NULL)) ||
-		((object_path == NULL) && (err != NULL)), NULL);
-
-	if (err != NULL) {
-		unwrap_dbus_error (err, &err);
-		g_propagate_error (error, err);
-		g_object_unref (client);
-		return NULL;
-	}
-
-	connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (cal_factory));
-
-	client->priv->dbus_proxy = G_DBUS_PROXY (e_gdbus_cal_proxy_new_sync (
-		connection,
-		G_DBUS_PROXY_FLAGS_NONE,
-		CALENDAR_DBUS_SERVICE_NAME,
-		object_path,
-		NULL, &err));
-
-	g_free (object_path);
-
-	/* Sanity check. */
-	g_return_val_if_fail (
-		((object_path != NULL) && (err == NULL)) ||
-		((object_path == NULL) && (err != NULL)), NULL);
-
-	if (err != NULL) {
-		unwrap_dbus_error (err, &err);
-		g_propagate_error (error, err);
-		g_object_unref (client);
-		return NULL;
-	}
-
-	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->dbus_proxy, "backend_error",
-		G_CALLBACK (backend_error_cb), client);
-
-	g_signal_connect (
-		client->priv->dbus_proxy, "readonly",
-		G_CALLBACK (readonly_cb), client);
-
-	g_signal_connect (
-		client->priv->dbus_proxy, "online",
-		G_CALLBACK (online_cb), client);
-
-	g_signal_connect (
-		client->priv->dbus_proxy, "opened",
-		G_CALLBACK (opened_cb), client);
-
-	g_signal_connect (
-		client->priv->dbus_proxy, "free-busy-data",
-		G_CALLBACK (free_busy_data_cb), client);
-
-	g_signal_connect (
-		client->priv->dbus_proxy, "backend-property-changed",
-		G_CALLBACK (backend_property_changed_cb), client);
-
-	return client;
 }
 
 /**
@@ -1209,7 +1546,9 @@ e_cal_client_new (ESource *source,
 ECalClientSourceType
 e_cal_client_get_source_type (ECalClient *client)
 {
-	g_return_val_if_fail (E_IS_CAL_CLIENT (client), E_CAL_CLIENT_SOURCE_TYPE_LAST);
+	g_return_val_if_fail (
+		E_IS_CAL_CLIENT (client),
+		E_CAL_CLIENT_SOURCE_TYPE_LAST);
 
 	return client->priv->source_type;
 }
@@ -1232,25 +1571,9 @@ e_cal_client_get_source_type (ECalClient *client)
 const gchar *
 e_cal_client_get_local_attachment_store (ECalClient *client)
 {
-	gchar *cache_dir = NULL;
-	GError *error = NULL;
-
 	g_return_val_if_fail (E_IS_CAL_CLIENT (client), NULL);
 
-	if (client->priv->cache_dir || !client->priv->dbus_proxy)
-		return client->priv->cache_dir;
-
-	e_gdbus_cal_call_get_backend_property_sync (client->priv->dbus_proxy, 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;
+	return e_dbus_calendar_get_cache_dir (client->priv->dbus_proxy);
 }
 
 /* icaltimezone_copy does a shallow copy while icaltimezone_free tries to free the entire 
@@ -1292,7 +1615,8 @@ copy_timezone (icaltimezone *ozone)
  * Since: 3.2
  **/
 void
-e_cal_client_set_default_timezone (ECalClient *client, /* const */ icaltimezone *zone)
+e_cal_client_set_default_timezone (ECalClient *client,
+                                   icaltimezone *zone)
 {
 	g_return_if_fail (E_IS_CAL_CLIENT (client));
 	g_return_if_fail (zone != NULL);
@@ -1315,7 +1639,7 @@ e_cal_client_set_default_timezone (ECalClient *client, /* const */ icaltimezone
  *
  * Since: 3.2
  **/
-/* const */ icaltimezone *
+icaltimezone *
 e_cal_client_get_default_timezone (ECalClient *client)
 {
 	g_return_val_if_fail (E_IS_CAL_CLIENT (client), NULL);
@@ -1338,7 +1662,9 @@ e_cal_client_check_one_alarm_only (ECalClient *client)
 {
 	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);
+	return e_client_check_capability (
+		E_CLIENT (client),
+		CAL_STATIC_CAPABILITY_ONE_ALARM_ONLY);
 }
 
 /**
@@ -1356,7 +1682,9 @@ e_cal_client_check_save_schedules (ECalClient *client)
 {
 	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
 
-	return e_client_check_capability (E_CLIENT (client), CAL_STATIC_CAPABILITY_SAVE_SCHEDULES);
+	return e_client_check_capability (
+		E_CLIENT (client),
+		CAL_STATIC_CAPABILITY_SAVE_SCHEDULES);
 }
 
 /**
@@ -1375,7 +1703,9 @@ e_cal_client_check_organizer_must_attend (ECalClient *client)
 {
 	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);
+	return e_client_check_capability (
+		E_CLIENT (client),
+		CAL_STATIC_CAPABILITY_ORGANIZER_MUST_ATTEND);
 }
 
 /**
@@ -1395,7 +1725,9 @@ e_cal_client_check_organizer_must_accept (ECalClient *client)
 {
 	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);
+	return e_client_check_capability (
+		E_CLIENT (client),
+		CAL_STATIC_CAPABILITY_ORGANIZER_MUST_ACCEPT);
 }
 
 /**
@@ -1414,7 +1746,9 @@ e_cal_client_check_recurrences_no_master (ECalClient *client)
 {
 	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);
+	return e_client_check_capability (
+		E_CLIENT (client),
+		CAL_STATIC_CAPABILITY_RECURRENCES_NO_MASTER);
 }
 
 /**
@@ -2567,81 +2901,24 @@ e_cal_client_get_component_as_string (ECalClient *client,
 	return obj_string;
 }
 
-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_propagate_error (error, e_client_error_create (E_CLIENT_ERROR_INVALID_ARG, NULL));
-	}
-
-	return res;
-}
-
-static gboolean
-complete_strv_exchange (gboolean res,
-                        gchar **out_strings,
-                        GSList **result,
-                        GError **error)
-{
-	g_return_val_if_fail (result != NULL, FALSE);
-
-	if (res && out_strings) {
-		*result = e_client_util_strv_to_slist ((const gchar * const*) out_strings);
-	} else {
-		*result = NULL;
-		res = FALSE;
-
-		if (error && !*error)
-			g_propagate_error (error, e_client_error_create (E_CLIENT_ERROR_INVALID_ARG, NULL));
-	}
-
-	g_strfreev (out_strings);
-
-	return res;
-}
-
-static gboolean
-cal_client_get_default_object_from_cache_finish (EClient *client,
-                                                 GAsyncResult *result,
-                                                 gchar **prop_value,
-                                                 GError **error)
+/* Helper for e_cal_client_get_default_object() */
+static void
+cal_client_get_default_object_thread (GSimpleAsyncResult *simple,
+                                      GObject *source_object,
+                                      GCancellable *cancellable)
 {
-	GSimpleAsyncResult *simple;
-	GError *local_error = NULL;
-
-	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
-	g_return_val_if_fail (result != NULL, FALSE);
-	g_return_val_if_fail (prop_value != NULL, FALSE);
-	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (client), cal_client_get_default_object_from_cache_finish), FALSE);
-
-	simple = G_SIMPLE_ASYNC_RESULT (result);
+	AsyncContext *async_context;
+	GError *error = NULL;
 
-	if (g_simple_async_result_propagate_error (simple, &local_error)) {
-		e_client_unwrap_dbus_error (client, local_error, error);
-		return FALSE;
-	}
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
 
-	*prop_value = g_strdup (g_simple_async_result_get_op_res_gpointer (simple));
+	e_cal_client_get_default_object_sync (
+		E_CAL_CLIENT (source_object),
+		&async_context->out_comp,
+		cancellable, &error);
 
-	return *prop_value != NULL;
+	if (error != NULL)
+		g_simple_async_result_take_error (simple, error);
 }
 
 /**
@@ -2663,55 +2940,39 @@ e_cal_client_get_default_object (ECalClient *client,
                                  GAsyncReadyCallback callback,
                                  gpointer user_data)
 {
-	EClient *base_client = E_CLIENT (client);
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
 
-	e_client_proxy_call_string (
-		base_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);
-}
+	g_return_if_fail (E_IS_CAL_CLIENT (client));
 
-static gboolean
-complete_get_object (gboolean res,
-                     gchar *out_string,
-                     icalcomponent **icalcomp,
-                     gboolean ensure_unique_uid,
-                     GError **error)
-{
-	g_return_val_if_fail (icalcomp != NULL, FALSE);
+	async_context = g_slice_new0 (AsyncContext);
 
-	if (res && out_string) {
-		*icalcomp = icalparser_parse_string (out_string);
-		if (!*icalcomp) {
-			g_propagate_error (error, e_cal_client_error_create (E_CAL_CLIENT_ERROR_INVALID_OBJECT, NULL));
-			res = FALSE;
-		} else if (ensure_unique_uid && icalcomponent_get_uid (*icalcomp)) {
-			/* make sure the UID is always unique */
-			gchar *new_uid = e_cal_component_gen_uid ();
-
-			icalcomponent_set_uid (*icalcomp, new_uid);
-			g_free (new_uid);
-		}
-	} else {
-		*icalcomp = NULL;
-		res = FALSE;
-	}
+	simple = g_simple_async_result_new (
+		G_OBJECT (client), callback, user_data,
+		e_cal_client_get_default_object);
 
-	g_free (out_string);
+	g_simple_async_result_set_check_cancellable (simple, cancellable);
 
-	return res;
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, cal_client_get_default_object_thread,
+		G_PRIORITY_DEFAULT, cancellable);
+
+	g_object_unref (simple);
 }
 
 /**
  * e_cal_client_get_default_object_finish:
  * @client: an #ECalClient
  * @result: a #GAsyncResult
- * @icalcomp: (out): Return value for the default calendar object.
+ * @out_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
+ * sets @out_icalcomp to an #icalcomponent from the backend that contains
+ * the default values for properties needed. This @out_icalcomp should be
  * freed with icalcomponent_free().
  *
  * Returns: %TRUE if successful, %FALSE otherwise.
@@ -2721,32 +2982,42 @@ complete_get_object (gboolean res,
 gboolean
 e_cal_client_get_default_object_finish (ECalClient *client,
                                         GAsyncResult *result,
-                                        icalcomponent **icalcomp,
+                                        icalcomponent **out_icalcomp,
                                         GError **error)
 {
-	gboolean res;
-	gchar *out_string = NULL;
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
 
-	g_return_val_if_fail (icalcomp != NULL, FALSE);
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (client),
+		e_cal_client_get_default_object), FALSE);
 
-	if (g_simple_async_result_get_source_tag (G_SIMPLE_ASYNC_RESULT (result)) == cal_client_get_default_object_from_cache_finish) {
-		res = cal_client_get_default_object_from_cache_finish (E_CLIENT (client), result, &out_string, error);
-	} else {
-		res = e_client_proxy_call_finish_string (E_CLIENT (client), result, &out_string, error, e_cal_client_get_default_object);
-	}
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
 
-	return complete_get_object (res, out_string, icalcomp, TRUE, error);
+	if (g_simple_async_result_propagate_error (simple, error))
+		return FALSE;
+
+	g_return_val_if_fail (async_context->out_comp != NULL, FALSE);
+
+	if (out_icalcomp != NULL) {
+		*out_icalcomp = async_context->out_comp;
+		async_context->out_comp = NULL;
+	}
+
+	return TRUE;
 }
 
 /**
  * e_cal_client_get_default_object_sync:
  * @client: an #ECalClient
- * @icalcomp: (out): Return value for the default calendar object.
+ * @out_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
+ * values for properties needed. This @out_icalcomp should be freed with
  * icalcomponent_free().
  *
  * Returns: %TRUE if successful, %FALSE otherwise.
@@ -2755,95 +3026,68 @@ e_cal_client_get_default_object_finish (ECalClient *client,
  **/
 gboolean
 e_cal_client_get_default_object_sync (ECalClient *client,
-                                      icalcomponent **icalcomp,
+                                      icalcomponent **out_icalcomp,
                                       GCancellable *cancellable,
                                       GError **error)
 {
-	gboolean res;
-	gchar *out_string = NULL;
+	icalcomponent *icalcomp = NULL;
+	gchar *string;
 
 	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
-	g_return_val_if_fail (icalcomp != NULL, FALSE);
+	g_return_val_if_fail (out_icalcomp != NULL, FALSE);
 
 	if (client->priv->dbus_proxy == NULL) {
 		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);
+	string = e_dbus_calendar_dup_default_object (client->priv->dbus_proxy);
+	if (string != NULL) {
+		icalcomp = icalparser_parse_string (string);
+		g_free (string);
+	}
 
-	return complete_get_object (res, out_string, icalcomp, TRUE, error);
-}
+	if (icalcomp == NULL) {
+		g_propagate_error (
+			error, e_cal_client_error_create (
+			E_CAL_CLIENT_ERROR_INVALID_OBJECT, NULL));
+		return FALSE;
+	}
 
-static gboolean
-complete_get_object_master (ECalClientSourceType source_type,
-                            gboolean res,
-                            gchar *out_string,
-                            icalcomponent **icalcomp,
-                            GError **error)
-{
-	g_return_val_if_fail (icalcomp != NULL, FALSE);
+	if (icalcomponent_get_uid (icalcomp) != NULL) {
+		gchar *new_uid;
 
-	if (res && out_string) {
-		icalcomponent *tmp_comp = icalparser_parse_string (out_string);
-		if (!tmp_comp) {
-			*icalcomp = NULL;
-			g_propagate_error (error, e_cal_client_error_create (E_CAL_CLIENT_ERROR_INVALID_OBJECT, NULL));
-			res = FALSE;
-		} else {
-			icalcomponent_kind kind;
-			icalcomponent *master_comp = NULL;
-
-			switch (source_type) {
-			case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
-				kind = ICAL_VEVENT_COMPONENT;
-				break;
-			case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
-				kind = ICAL_VTODO_COMPONENT;
-				break;
-			case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
-				kind = ICAL_VJOURNAL_COMPONENT;
-				break;
-			default:
-				icalcomponent_free (tmp_comp);
-				*icalcomp = NULL;
-				res = FALSE;
+		/* Make sure the UID is always unique. */
+		new_uid = e_cal_component_gen_uid ();
+		icalcomponent_set_uid (icalcomp, new_uid);
+		g_free (new_uid);
+	}
 
-				g_warn_if_reached ();
-			}
+	*out_icalcomp = icalcomp;
 
-			if (res && icalcomponent_isa (tmp_comp) == kind) {
-				*icalcomp = tmp_comp;
-				tmp_comp = NULL;
-			} else if (res && icalcomponent_isa (tmp_comp) == ICAL_VCALENDAR_COMPONENT) {
-				for (master_comp = icalcomponent_get_first_component (tmp_comp, kind);
-				     master_comp;
-				     master_comp = icalcomponent_get_next_component (tmp_comp, kind)) {
-					if (!icalcomponent_get_uid (master_comp))
-						continue;
+	return TRUE;
+}
 
-					if (icaltime_is_null_time (icalcomponent_get_recurrenceid (master_comp)) ||
-					    !icaltime_is_valid_time (icalcomponent_get_recurrenceid (master_comp)))
-						break;
-				}
+/* Helper for e_cal_client_get_object() */
+static void
+cal_client_get_object_thread (GSimpleAsyncResult *simple,
+                              GObject *source_object,
+                              GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
 
-				if (!master_comp)
-					master_comp = icalcomponent_get_first_component (tmp_comp, kind);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
 
-				*icalcomp = master_comp ? icalcomponent_new_clone (master_comp) : NULL;
-			}
+	e_cal_client_get_object_sync (
+		E_CAL_CLIENT (source_object),
+		async_context->uid,
+		async_context->rid,
+		&async_context->out_comp,
+		cancellable, &error);
 
-			if (tmp_comp)
-				icalcomponent_free (tmp_comp);
-		}
-	} else {
-		*icalcomp = NULL;
-		res = FALSE;
-	}
-
-	g_free (out_string);
-
-	return res && *icalcomp;
+	if (error != NULL)
+		g_simple_async_result_take_error (simple, error);
 }
 
 /**
@@ -2873,29 +3117,42 @@ e_cal_client_get_object (ECalClient *client,
                          GAsyncReadyCallback callback,
                          gpointer user_data)
 {
-	gchar **strv;
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
 
+	g_return_if_fail (E_IS_CAL_CLIENT (client));
 	g_return_if_fail (uid != NULL);
+	/* rid is optional */
 
-	strv = e_gdbus_cal_encode_get_object (uid, rid);
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->uid = g_strdup (uid);
+	async_context->rid = g_strdup (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);
+	simple = g_simple_async_result_new (
+		G_OBJECT (client), callback, user_data,
+		e_cal_client_get_object);
 
-	g_strfreev (strv);
+	g_simple_async_result_set_check_cancellable (simple, cancellable);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, cal_client_get_object_thread,
+		G_PRIORITY_DEFAULT, cancellable);
+
+	g_object_unref (simple);
 }
 
 /**
  * e_cal_client_get_object_finish:
  * @client: an #ECalClient
  * @result: a #GAsyncResult
- * @icalcomp: (out): Return value for the calendar component object.
+ * @out_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 function always returns
+ * sets @out_icalcomp to queried component. This function always returns
  * master object for a case of @rid being NULL or an empty string.
  * This component should be freed with icalcomponent_free().
  *
@@ -2910,17 +3167,31 @@ e_cal_client_get_object (ECalClient *client,
 gboolean
 e_cal_client_get_object_finish (ECalClient *client,
                                 GAsyncResult *result,
-                                icalcomponent **icalcomp,
+                                icalcomponent **out_icalcomp,
                                 GError **error)
 {
-	gboolean res;
-	gchar *out_string = NULL;
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
 
-	g_return_val_if_fail (icalcomp != NULL, FALSE);
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (client),
+		e_cal_client_get_object), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	if (g_simple_async_result_propagate_error (simple, error))
+		return FALSE;
+
+	g_return_val_if_fail (async_context->out_comp != NULL, FALSE);
 
-	res = e_client_proxy_call_finish_string (E_CLIENT (client), result, &out_string, error, e_cal_client_get_object);
+	if (out_icalcomp != NULL) {
+		*out_icalcomp = async_context->out_comp;
+		async_context->out_comp = NULL;
+	}
 
-	return complete_get_object_master (e_cal_client_get_source_type (client), res, out_string, icalcomp, error);
+	return TRUE;
 }
 
 /**
@@ -2928,7 +3199,7 @@ e_cal_client_get_object_finish (ECalClient *client,
  * @client: an #ECalClient
  * @uid: Unique identifier for a calendar component.
  * @rid: Recurrence identifier.
- * @icalcomp: (out): Return value for the calendar component object.
+ * @out_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
  *
@@ -2949,27 +3220,131 @@ gboolean
 e_cal_client_get_object_sync (ECalClient *client,
                               const gchar *uid,
                               const gchar *rid,
-                              icalcomponent **icalcomp,
+                              icalcomponent **out_icalcomp,
                               GCancellable *cancellable,
                               GError **error)
 {
-	gboolean res;
-	gchar *out_string = NULL, **strv;
+	icalcomponent *icalcomp = NULL;
+	icalcomponent_kind kind;
+	gchar *utf8_uid;
+	gchar *utf8_rid;
+	gchar *string = NULL;
+	gboolean success;
 
 	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
 	g_return_val_if_fail (uid != NULL, FALSE);
-	g_return_val_if_fail (icalcomp != NULL, FALSE);
+	g_return_val_if_fail (out_icalcomp != NULL, FALSE);
+
+	if (rid == NULL)
+		rid = "";
 
 	if (client->priv->dbus_proxy == NULL) {
 		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);
+	utf8_uid = e_util_utf8_make_valid (uid);
+	utf8_rid = e_util_utf8_make_valid (rid);
+
+	success = e_dbus_calendar_call_get_object_sync (
+		client->priv->dbus_proxy, utf8_uid, utf8_rid,
+		&string, cancellable, error);
+
+	g_free (utf8_uid);
+	g_free (utf8_rid);
+
+	/* Sanity check. */
+	g_return_val_if_fail (
+		(success && (string != NULL)) ||
+		(!success && (string == NULL)), FALSE);
+
+	if (!success)
+		return FALSE;
+
+	icalcomp = icalparser_parse_string (string);
+
+	g_free (string);
+
+	if (icalcomp == NULL) {
+		g_propagate_error (
+			error, e_cal_client_error_create (
+			E_CAL_CLIENT_ERROR_INVALID_OBJECT, NULL));
+		return FALSE;
+	}
+
+	switch (e_cal_client_get_source_type (client)) {
+		case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+			kind = ICAL_VEVENT_COMPONENT;
+			break;
+		case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+			kind = ICAL_VTODO_COMPONENT;
+			break;
+		case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+			kind = ICAL_VJOURNAL_COMPONENT;
+			break;
+		default:
+			g_warn_if_reached ();
+			kind = ICAL_VEVENT_COMPONENT;
+			break;
+	}
+
+	if (icalcomponent_isa (icalcomp) == kind) {
+		*out_icalcomp = icalcomp;
 
-	return complete_get_object_master (e_cal_client_get_source_type (client), res, out_string, icalcomp, error);
+	} else if (icalcomponent_isa (icalcomp) == ICAL_VCALENDAR_COMPONENT) {
+		icalcomponent *subcomponent;
+
+		for (subcomponent = icalcomponent_get_first_component (icalcomp, kind);
+			subcomponent != NULL;
+			subcomponent = icalcomponent_get_next_component (icalcomp, kind)) {
+			struct icaltimetype recurrenceid;
+
+			if (icalcomponent_get_uid (subcomponent) == NULL)
+				continue;
+
+			recurrenceid =
+				icalcomponent_get_recurrenceid (subcomponent);
+
+			if (icaltime_is_null_time (recurrenceid))
+				break;
+
+			if (!icaltime_is_valid_time (recurrenceid))
+				break;
+		}
+
+		if (subcomponent == NULL)
+			subcomponent = icalcomponent_get_first_component (icalcomp, kind);
+		if (subcomponent != NULL)
+			subcomponent = icalcomponent_new_clone (subcomponent);
+
+		/* XXX Shouldn't we set an error is this is still NULL? */
+		*out_icalcomp = subcomponent;
+
+		icalcomponent_free (icalcomp);
+	}
+
+	return TRUE;
+}
+
+/* Helper for e_cal_client_get_objects_for_uid() */
+static void
+cal_client_get_objects_for_uid_thread (GSimpleAsyncResult *simple,
+                                       GObject *source_object,
+                                       GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	e_cal_client_get_objects_for_uid_sync (
+		E_CAL_CLIENT (source_object),
+		async_context->uid,
+		&async_context->object_list,
+		cancellable, &error);
+
+	if (error != NULL)
+		g_simple_async_result_take_error (simple, error);
 }
 
 /**
@@ -2995,86 +3370,42 @@ e_cal_client_get_objects_for_uid (ECalClient *client,
                                   GAsyncReadyCallback callback,
                                   gpointer user_data)
 {
-	gchar **strv;
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
 
+	g_return_if_fail (E_IS_CAL_CLIENT (client));
 	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);
-}
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->uid = g_strdup (uid);
 
-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;
+	simple = g_simple_async_result_new (
+		G_OBJECT (client), callback, user_data,
+		e_cal_client_get_objects_for_uid);
 
-	res = complete_get_object (res, out_string, &icalcomp, FALSE, error);
-	if (!res || !icalcomp)
-		return FALSE;
+	g_simple_async_result_set_check_cancellable (simple, cancellable);
 
-	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;
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
 
-		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;
-		}
+	g_simple_async_result_run_in_thread (
+		simple, cal_client_get_objects_for_uid_thread,
+		G_PRIORITY_DEFAULT, cancellable);
 
-		*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;
+	g_object_unref (simple);
 }
 
 /**
  * e_cal_client_get_objects_for_uid_finish:
  * @client: an #ECalClient
  * @result: a #GAsyncResult
- * @ecalcomps: (out) (transfer full) (element-type ECalComponent): Return value
- * for the list of objects obtained from the backend
+ * @out_ecalcomps: (out) (transfer full) (element-type ECalComponent):
+ *                 Return location 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
+ * sets @out_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().
  *
@@ -3085,25 +3416,38 @@ complete_get_objects_for_uid (ECalClientSourceType source_type,
 gboolean
 e_cal_client_get_objects_for_uid_finish (ECalClient *client,
                                          GAsyncResult *result,
-                                         GSList **ecalcomps,
+                                         GSList **out_ecalcomps,
                                          GError **error)
 {
-	gboolean res;
-	gchar *out_string = NULL;
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
 
-	g_return_val_if_fail (ecalcomps != NULL, FALSE);
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (client),
+		e_cal_client_get_objects_for_uid), FALSE);
 
-	res = e_client_proxy_call_finish_string (E_CLIENT (client), result, &out_string, error, e_cal_client_get_objects_for_uid);
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
 
-	return complete_get_objects_for_uid (e_cal_client_get_source_type (client), res, out_string, ecalcomps, error);
+	if (g_simple_async_result_propagate_error (simple, error))
+		return FALSE;
+
+	if (out_ecalcomps != NULL) {
+		*out_ecalcomps = async_context->object_list;
+		async_context->object_list = NULL;
+	}
+
+	return TRUE;
 }
 
 /**
  * e_cal_client_get_objects_for_uid_sync:
  * @client: an #ECalClient
  * @uid: Unique identifier for a calendar component
- * @ecalcomps: (out) (transfer full) (element-type ECalComponent): Return value
- * for the list of objects obtained from the backend
+ * @out_ecalcomps: (out) (transfer full) (element-type ECalComponent):
+ *                 Return location for the list of objects obtained from the
+ *                 backend
  * @cancellable: (allow-none): a #GCancellable; can be %NULL
  * @error: (out): a #GError to set an error, if any
  *
@@ -3119,27 +3463,119 @@ e_cal_client_get_objects_for_uid_finish (ECalClient *client,
 gboolean
 e_cal_client_get_objects_for_uid_sync (ECalClient *client,
                                        const gchar *uid,
-                                       GSList **ecalcomps,
+                                       GSList **out_ecalcomps,
                                        GCancellable *cancellable,
                                        GError **error)
 {
-	gboolean res;
-	gchar *out_string = NULL, **strv = NULL;
+	icalcomponent *icalcomp;
+	icalcomponent_kind kind;
+	gchar *utf8_uid;
+	gchar *string = NULL;
+	gboolean success;
 
 	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
 	g_return_val_if_fail (uid != NULL, FALSE);
-	g_return_val_if_fail (ecalcomps != NULL, FALSE);
+	g_return_val_if_fail (out_ecalcomps != NULL, FALSE);
 
 	if (client->priv->dbus_proxy == NULL) {
 		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);
+	utf8_uid = e_util_utf8_make_valid (uid);
 
-	return complete_get_objects_for_uid (e_cal_client_get_source_type (client), res, out_string, ecalcomps, error);
+	success = e_dbus_calendar_call_get_object_sync (
+		client->priv->dbus_proxy, utf8_uid, "",
+		&string, cancellable, error);
+
+	g_free (utf8_uid);
+
+	/* Sanity check. */
+	g_return_val_if_fail (
+		(success && (string != NULL)) ||
+		(!success && (string == NULL)), FALSE);
+
+	icalcomp = icalparser_parse_string (string);
+
+	g_free (string);
+
+	if (icalcomp == NULL) {
+		g_propagate_error (
+			error, e_cal_client_error_create (
+			E_CAL_CLIENT_ERROR_INVALID_OBJECT, NULL));
+		return FALSE;
+	}
+
+	switch (e_cal_client_get_source_type (client)) {
+		case E_CAL_CLIENT_SOURCE_TYPE_EVENTS:
+			kind = ICAL_VEVENT_COMPONENT;
+			break;
+		case E_CAL_CLIENT_SOURCE_TYPE_TASKS:
+			kind = ICAL_VTODO_COMPONENT;
+			break;
+		case E_CAL_CLIENT_SOURCE_TYPE_MEMOS:
+			kind = ICAL_VJOURNAL_COMPONENT;
+			break;
+		default:
+			g_warn_if_reached ();
+			kind = ICAL_VEVENT_COMPONENT;
+			break;
+	}
+
+	if (icalcomponent_isa (icalcomp) == kind) {
+		ECalComponent *comp;
+
+		comp = e_cal_component_new ();
+		e_cal_component_set_icalcomponent (comp, icalcomp);
+		*out_ecalcomps = g_slist_append (NULL, comp);
+
+	} else if (icalcomponent_isa (icalcomp) == ICAL_VCALENDAR_COMPONENT) {
+		GSList *tmp = NULL;
+		icalcomponent *subcomponent;
+
+		subcomponent = icalcomponent_get_first_component (
+			icalcomp, kind);
+
+		while (subcomponent != NULL) {
+			ECalComponent *comp;
+			icalcomponent *clone;
+
+			comp = e_cal_component_new ();
+			clone = icalcomponent_new_clone (subcomponent);
+			e_cal_component_set_icalcomponent (comp, clone);
+			tmp = g_slist_prepend (tmp, comp);
+
+			subcomponent = icalcomponent_get_next_component (
+				icalcomp, kind);
+		}
+
+		*out_ecalcomps = g_slist_reverse (tmp);
+
+		icalcomponent_free (icalcomp);
+	}
+
+	return TRUE;
+}
+
+/* Helper for e_cal_client_get_object_list() */
+static void
+cal_client_get_object_list_thread (GSimpleAsyncResult *simple,
+                                   GObject *source_object,
+                                   GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	e_cal_client_get_object_list_sync (
+		E_CAL_CLIENT (source_object),
+		async_context->sexp,
+		&async_context->comp_list,
+		cancellable, &error);
+
+	if (error != NULL)
+		g_simple_async_result_take_error (simple, error);
 }
 
 /**
@@ -3164,61 +3600,41 @@ e_cal_client_get_object_list (ECalClient *client,
                               GAsyncReadyCallback callback,
                               gpointer user_data)
 {
-	gchar *gdbus_sexp = NULL;
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
 
+	g_return_if_fail (E_IS_CAL_CLIENT (client));
 	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);
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->sexp = g_strdup (sexp);
 
-	g_free (gdbus_sexp);
-}
+	simple = g_simple_async_result_new (
+		G_OBJECT (client), callback, user_data,
+		e_cal_client_get_object_list);
 
-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]);
+	g_simple_async_result_set_check_cancellable (simple, cancellable);
 
-			if (!icalcomp)
-				continue;
-
-			*icalcomps = g_slist_prepend (*icalcomps, icalcomp);
-		}
-
-		*icalcomps = g_slist_reverse (*icalcomps);
-	} else {
-		res = FALSE;
-	}
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
 
-	g_strfreev (out_strv);
+	g_simple_async_result_run_in_thread (
+		simple, cal_client_get_object_list_thread,
+		G_PRIORITY_DEFAULT, cancellable);
 
-	return res;
+	g_object_unref (simple);
 }
 
 /**
  * e_cal_client_get_object_list_finish:
  * @client: an #ECalClient
  * @result: a #GAsyncResult
- * @icalcomps: (out) (element-type icalcomponent): list of matching
- * #icalcomponent<!-- -->s
+ * @out_icalcomps: (out) (element-type icalcomponent): 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.
+ * sets @out_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.
@@ -3228,30 +3644,42 @@ complete_get_object_list (gboolean res,
 gboolean
 e_cal_client_get_object_list_finish (ECalClient *client,
                                      GAsyncResult *result,
-                                     GSList **icalcomps,
+                                     GSList **out_icalcomps,
                                      GError **error)
 {
-	gboolean res;
-	gchar **out_strv = NULL;
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
 
-	g_return_val_if_fail (icalcomps != NULL, FALSE);
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (client),
+		e_cal_client_get_object_list), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	if (g_simple_async_result_propagate_error (simple, error))
+		return FALSE;
 
-	res = e_client_proxy_call_finish_strv (E_CLIENT (client), result, &out_strv, error, e_cal_client_get_object_list);
+	if (out_icalcomps != NULL) {
+		*out_icalcomps = async_context->comp_list;
+		async_context->comp_list = NULL;
+	}
 
-	return complete_get_object_list (res, out_strv, icalcomps, error);
+	return TRUE;
 }
 
 /**
  * e_cal_client_get_object_list_sync:
  * @client: an #ECalClient
  * @sexp: an S-expression representing the query
- * @icalcomps: (out) (element-type icalcomponent): list of matching
- * #icalcomponent<!-- -->s
+ * @out_icalcomps: (out) (element-type icalcomponent): list of matching
+ *                 #icalcomponent<!-- -->s
  * @cancellable: (allow-none): 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
+ * by the @sexp argument. The objects will be returned in the @out_icalcomps
  * argument, which is a list of #icalcomponent.
  * This list should be freed with e_cal_client_free_icalcomp_slist().
  *
@@ -3262,26 +3690,75 @@ e_cal_client_get_object_list_finish (ECalClient *client,
 gboolean
 e_cal_client_get_object_list_sync (ECalClient *client,
                                    const gchar *sexp,
-                                   GSList **icalcomps,
+                                   GSList **out_icalcomps,
                                    GCancellable *cancellable,
                                    GError **error)
 {
-	gboolean res;
-	gchar **out_strv = NULL, *gdbus_sexp = NULL;
+	GSList *tmp = NULL;
+	gchar *utf8_sexp;
+	gchar **strv = NULL;
+	gboolean success;
+	gint ii;
 
 	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
 	g_return_val_if_fail (sexp != NULL, FALSE);
-	g_return_val_if_fail (icalcomps != NULL, FALSE);
+	g_return_val_if_fail (out_icalcomps != NULL, FALSE);
 
 	if (client->priv->dbus_proxy == NULL) {
 		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);
+	utf8_sexp = e_util_utf8_make_valid (sexp);
+
+	success = e_dbus_calendar_call_get_object_list_sync (
+		client->priv->dbus_proxy, utf8_sexp,
+		&strv, cancellable, error);
+
+	g_free (utf8_sexp);
+
+	/* Sanity check. */
+	g_return_val_if_fail (
+		(success && (strv != NULL)) ||
+		(!success && (strv == NULL)), FALSE);
+
+	if (!success)
+		return FALSE;
+
+	for (ii = 0; strv[ii] != NULL; ii++) {
+		icalcomponent *icalcomp;
+
+		icalcomp = icalcomponent_new_from_string (strv[ii]);
+		if (icalcomp == NULL)
+			continue;
+
+		tmp = g_slist_prepend (tmp, icalcomp);
+	}
+
+	*out_icalcomps = g_slist_reverse (tmp);
+
+	return TRUE;
+}
+
+/* Helper for e_cal_client_get_object_list_as_comps() */
+static void
+cal_client_get_object_list_as_comps_thread (GSimpleAsyncResult *simple,
+                                            GObject *source_object,
+                                            GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
 
-	return complete_get_object_list (res, out_strv, icalcomps, error);
+	e_cal_client_get_object_list_as_comps_sync (
+		E_CAL_CLIENT (source_object),
+		async_context->sexp,
+		&async_context->object_list,
+		cancellable, &error);
+
+	if (error != NULL)
+		g_simple_async_result_take_error (simple, error);
 }
 
 /**
@@ -3299,73 +3776,48 @@ e_cal_client_get_object_list_sync (ECalClient *client,
  *
  * 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)
+void
+e_cal_client_get_object_list_as_comps (ECalClient *client,
+                                       const gchar *sexp,
+                                       GCancellable *cancellable,
+                                       GAsyncReadyCallback callback,
+                                       gpointer user_data)
 {
-	GSList *icalcomps = NULL;
-
-	g_return_val_if_fail (ecalcomps != NULL, FALSE);
-
-	*ecalcomps = NULL;
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
 
-	res = complete_get_object_list (res, out_strv, &icalcomps, error);
+	g_return_if_fail (E_IS_CAL_CLIENT (client));
+	g_return_if_fail (sexp != NULL);
 
-	if (res) {
-		GSList *iter;
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->sexp = g_strdup (sexp);
 
-		for (iter = icalcomps; iter; iter = iter->next) {
-			ECalComponent *comp;
+	simple = g_simple_async_result_new (
+		G_OBJECT (client), callback, user_data,
+		e_cal_client_get_object_list_as_comps);
 
-			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_simple_async_result_set_check_cancellable (simple, cancellable);
 
-		g_slist_free (icalcomps);
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
 
-		*ecalcomps = g_slist_reverse (*ecalcomps);
-	} else {
-		e_cal_client_free_icalcomp_slist (icalcomps);
-	}
+	g_simple_async_result_run_in_thread (
+		simple, cal_client_get_object_list_as_comps_thread,
+		G_PRIORITY_DEFAULT, cancellable);
 
-	return res;
+	g_object_unref (simple);
 }
 
 /**
  * e_cal_client_get_object_list_as_comps_finish:
  * @client: an #ECalClient
  * @result: a #GAsyncResult
- * @ecalcomps: (out) (element-type ECalComponent): list of matching
- * #ECalComponent<!-- -->s
+ * @out_ecalcomps: (out) (element-type ECalComponent): 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.
+ * sets @out_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.
@@ -3375,30 +3827,42 @@ complete_get_object_list_as_comps (gboolean res,
 gboolean
 e_cal_client_get_object_list_as_comps_finish (ECalClient *client,
                                               GAsyncResult *result,
-                                              GSList **ecalcomps,
+                                              GSList **out_ecalcomps,
                                               GError **error)
 {
-	gboolean res;
-	gchar **out_strv = NULL;
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (client),
+		e_cal_client_get_object_list), FALSE);
 
-	g_return_val_if_fail (ecalcomps != NULL, FALSE);
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	if (g_simple_async_result_propagate_error (simple, error))
+		return FALSE;
 
-	res = e_client_proxy_call_finish_strv (E_CLIENT (client), result, &out_strv, error, e_cal_client_get_object_list_as_comps);
+	if (out_ecalcomps != NULL) {
+		*out_ecalcomps = async_context->object_list;
+		async_context->object_list = NULL;
+	}
 
-	return complete_get_object_list_as_comps (res, out_strv, ecalcomps, error);
+	return TRUE;
 }
 
 /**
  * e_cal_client_get_object_list_as_comps_sync:
  * @client: an #ECalClient
  * @sexp: an S-expression representing the query
- * @ecalcomps: (out) (element-type ECalComponent): list of matching
- * #ECalComponent<!-- -->s
+ * @out_ecalcomps: (out) (element-type ECalComponent): list of matching
+ *                 #ECalComponent<!-- -->s
  * @cancellable: (allow-none): 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
+ * by the @sexp argument. The objects will be returned in the @out_ecalcomps
  * argument, which is a list of #ECalComponent.
  * This list should be freed with e_cal_client_free_ecalcomp_slist().
  *
@@ -3409,26 +3873,77 @@ e_cal_client_get_object_list_as_comps_finish (ECalClient *client,
 gboolean
 e_cal_client_get_object_list_as_comps_sync (ECalClient *client,
                                             const gchar *sexp,
-                                            GSList **ecalcomps,
+                                            GSList **out_ecalcomps,
                                             GCancellable *cancellable,
                                             GError **error)
 {
-	gboolean res;
-	gchar **out_strv = NULL, *gdbus_sexp = NULL;
+	GSList *list = NULL;
+	GSList *link;
+	GQueue trash = G_QUEUE_INIT;
+	gboolean success;
 
 	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
 	g_return_val_if_fail (sexp != NULL, FALSE);
-	g_return_val_if_fail (ecalcomps != NULL, FALSE);
+	g_return_val_if_fail (out_ecalcomps != NULL, FALSE);
 
-	if (client->priv->dbus_proxy == NULL) {
-		set_proxy_gone_error (error);
+	success = e_cal_client_get_object_list_sync (
+		client, sexp, &list, cancellable, error);
+
+	if (!success) {
+		g_warn_if_fail (list == NULL);
 		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);
+	/* Convert the icalcomponent list to an ECalComponent list. */
+	for (link = list; link != NULL; link = g_slist_next (link)) {
+		ECalComponent *comp;
+		icalcomponent *icalcomp = link->data;
+
+		comp = e_cal_component_new ();
+
+		/* This takes ownership of the icalcomponent, if it works. */
+		if (e_cal_component_set_icalcomponent (comp, icalcomp)) {
+			link->data = g_object_ref (comp);
+		} else {
+			/* On failure, free resources and add
+			 * the GSList link to the trash queue. */
+			icalcomponent_free (icalcomp);
+			g_queue_push_tail (&trash, link);
+			link->data = NULL;
+		}
+
+		g_object_unref (comp);
+	}
+
+	/* Delete GSList links we failed to convert. */
+	while ((link = g_queue_pop_head (&trash)) != NULL)
+		list = g_slist_delete_link (list, link);
+
+	*out_ecalcomps = list;
+
+	return TRUE;
+}
+
+/* Helper for e_cal_client_get_free_busy() */
+static void
+cal_client_get_free_busy_thread (GSimpleAsyncResult *simple,
+                                 GObject *source_object,
+                                 GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	e_cal_client_get_free_busy_sync (
+		E_CAL_CLIENT (source_object),
+		async_context->start,
+		async_context->end,
+		async_context->string_list,
+		cancellable, &error);
 
-	return complete_get_object_list_as_comps (res, out_strv, ecalcomps, error);
+	if (error != NULL)
+		g_simple_async_result_take_error (simple, error);
 }
 
 /**
@@ -3458,19 +3973,33 @@ e_cal_client_get_free_busy (ECalClient *client,
                             GAsyncReadyCallback callback,
                             gpointer user_data)
 {
-	gchar **strv;
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
 
+	g_return_if_fail (E_IS_CAL_CLIENT (client));
 	g_return_if_fail (start > 0);
 	g_return_if_fail (end > 0);
 
-	strv = e_gdbus_cal_encode_get_free_busy (start, end, users);
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->start = start;
+	async_context->end = end;
+	async_context->string_list = g_slist_copy_deep (
+		(GSList *) users, (GCopyFunc) g_strdup, NULL);
 
-	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);
+	simple = g_simple_async_result_new (
+		G_OBJECT (client), callback, user_data,
+		e_cal_client_get_free_busy);
 
-	g_strfreev (strv);
+	g_simple_async_result_set_check_cancellable (simple, cancellable);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, cal_client_get_free_busy_thread,
+		G_PRIORITY_DEFAULT, cancellable);
+
+	g_object_unref (simple);
 }
 
 /**
@@ -3491,7 +4020,17 @@ 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);
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (client),
+		e_cal_client_get_free_busy), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
 }
 
 /**
@@ -3518,21 +4057,55 @@ e_cal_client_get_free_busy_sync (ECalClient *client,
                                  GCancellable *cancellable,
                                  GError **error)
 {
-	gboolean res;
 	gchar **strv;
+	gboolean success;
+	gint ii = 0;
 
 	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+	g_return_val_if_fail (start > 0, FALSE);
+	g_return_val_if_fail (end > 0, FALSE);
 
 	if (client->priv->dbus_proxy == NULL) {
 		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);
+	strv = g_new0 (gchar *, g_slist_length ((GSList *) users) + 1);
+	while (users != NULL) {
+		strv[ii++] = e_util_utf8_make_valid (users->data);
+		users = g_slist_next (users);
+	}
+
+	success = e_dbus_calendar_call_get_free_busy_sync (
+		client->priv->dbus_proxy,
+		(gint64) start, (gint64) end,
+		(const gchar * const *) strv,
+		cancellable, error);
+
 	g_strfreev (strv);
 
-	return res;
+	return success;
+}
+
+/* Helper for e_cal_client_create_object() */
+static void
+cal_client_create_object_thread (GSimpleAsyncResult *simple,
+                                 GObject *source_object,
+                                 GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	e_cal_client_create_object_sync (
+		E_CAL_CLIENT (source_object),
+		async_context->in_comp,
+		&async_context->uid,
+		cancellable, &error);
+
+	if (error != NULL)
+		g_simple_async_result_take_error (simple, error);
 }
 
 /**
@@ -3553,41 +4126,45 @@ e_cal_client_get_free_busy_sync (ECalClient *client,
  **/
 void
 e_cal_client_create_object (ECalClient *client,
-                            /* const */ icalcomponent *icalcomp,
+                            icalcomponent *icalcomp,
                             GCancellable *cancellable,
                             GAsyncReadyCallback callback,
                             gpointer user_data)
 {
-	gchar *comp_str, *gdbus_comp = NULL;
-	const gchar *strv[2];
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
 
+	g_return_if_fail (E_IS_CAL_CLIENT (client));
 	g_return_if_fail (icalcomp != NULL);
 
-	comp_str = icalcomponent_as_ical_string_r (icalcomp);
-	strv[0] = e_util_ensure_gdbus_string (comp_str, &gdbus_comp);
-	strv[1] = NULL;
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->in_comp = icalcomponent_new_clone (icalcomp);
 
-	g_return_if_fail (strv[0] != NULL);
+	simple = g_simple_async_result_new (
+		G_OBJECT (client), callback, user_data,
+		e_cal_client_create_object);
 
-	e_client_proxy_call_strv (
-		E_CLIENT (client), strv, cancellable, callback, user_data, e_cal_client_create_object,
-		e_gdbus_cal_call_create_objects,
-		NULL, NULL, NULL, e_gdbus_cal_call_create_objects_finish, NULL);
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
 
-	g_free (comp_str);
-	g_free (gdbus_comp);
+	g_simple_async_result_run_in_thread (
+		simple, cal_client_create_object_thread,
+		G_PRIORITY_DEFAULT, cancellable);
+
+	g_object_unref (simple);
 }
 
 /**
  * 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
+ * @out_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().
+ * sets @out_uid to newly assigned UID for the created object.
+ * This @out_uid should be freed with g_free().
  *
  * Returns: %TRUE if successful, %FALSE otherwise.
  *
@@ -3596,38 +4173,47 @@ e_cal_client_create_object (ECalClient *client,
 gboolean
 e_cal_client_create_object_finish (ECalClient *client,
                                    GAsyncResult *result,
-                                   gchar **uid,
+                                   gchar **out_uid,
                                    GError **error)
 {
-	gboolean res;
-	gchar **out_strings = NULL;
-	gchar *out_string = NULL;
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
 
-	g_return_val_if_fail (uid != NULL, FALSE);
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (client),
+		e_cal_client_create_object), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
 
-	res = e_client_proxy_call_finish_strv (E_CLIENT (client), result, &out_strings, error, e_cal_client_create_object);
+	if (g_simple_async_result_propagate_error (simple, error))
+		return FALSE;
+
+	g_return_val_if_fail (async_context->uid != NULL, FALSE);
 
-	if (res && out_strings) {
-		out_string = g_strdup (out_strings[0]);
-		g_strfreev (out_strings);
+	if (out_uid != NULL) {
+		*out_uid = async_context->uid;
+		async_context->uid = NULL;
 	}
 
-	return complete_string_exchange (res, out_string, uid, error);
+	return TRUE;
 }
 
 /**
  * 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
+ * @out_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().
+ * 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 @out_uid
+ * argument. This function does not modify the original @icalcomp if its UID
+ * changes.  Returned @out_uid should be freed with g_free().
  *
  * Returns: %TRUE if successful, %FALSE otherwise.
  *
@@ -3635,43 +4221,53 @@ e_cal_client_create_object_finish (ECalClient *client,
  **/
 gboolean
 e_cal_client_create_object_sync (ECalClient *client,
-                                 /* const */ icalcomponent *icalcomp,
-                                 gchar **uid,
+                                 icalcomponent *icalcomp,
+                                 gchar **out_uid,
                                  GCancellable *cancellable,
                                  GError **error)
 {
-	gboolean res;
-	gchar *comp_str, *gdbus_comp = NULL;
-	const gchar *strv[2];
-	gchar **out_strings = NULL;
-	gchar *out_string = NULL;
+	GSList link = { icalcomp, NULL };
+	GSList *string_list = NULL;
+	gboolean success;
 
 	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
 	g_return_val_if_fail (icalcomp != NULL, FALSE);
-	g_return_val_if_fail (uid != NULL, FALSE);
 
-	if (client->priv->dbus_proxy == NULL) {
-		set_proxy_gone_error (error);
-		return FALSE;
-	}
+	success = e_cal_client_create_objects_sync (
+		client, &link, &string_list, cancellable, error);
+
+	/* Sanity check. */
+	g_return_val_if_fail (
+		(success && (string_list != NULL)) ||
+		(!success && (string_list == NULL)), FALSE);
 
-	comp_str = icalcomponent_as_ical_string_r (icalcomp);
-	strv[0] = e_util_ensure_gdbus_string (comp_str, &gdbus_comp);
-	strv[1] = NULL;
+	if (out_uid != NULL && string_list != NULL)
+		*out_uid = g_strdup (string_list->data);
 
-	g_return_val_if_fail (strv[0] != NULL, FALSE);
+	g_slist_free_full (string_list, (GDestroyNotify) g_free);
+
+	return success;
+}
 
-	res = e_client_proxy_call_sync_strv__strv (E_CLIENT (client), strv, &out_strings, cancellable, error, e_gdbus_cal_call_create_objects_sync);
+/* Helper for e_cal_client_create_objects() */
+static void
+cal_client_create_objects_thread (GSimpleAsyncResult *simple,
+                                  GObject *source_object,
+                                  GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
 
-	g_free (comp_str);
-	g_free (gdbus_comp);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
 
-	if (res && out_strings) {
-		out_string = g_strdup (out_strings[0]);
-		g_strfreev (out_strings);
-	}
+	e_cal_client_create_objects_sync (
+		E_CAL_CLIENT (source_object),
+		async_context->comp_list,
+		&async_context->string_list,
+		cancellable, &error);
 
-	return complete_string_exchange (res, out_string, uid, error);
+	if (error != NULL)
+		g_simple_async_result_take_error (simple, error);
 }
 
 /**
@@ -3697,32 +4293,43 @@ e_cal_client_create_objects (ECalClient *client,
                              GAsyncReadyCallback callback,
                              gpointer user_data)
 {
-	gchar **array;
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
 
 	g_return_if_fail (E_IS_CAL_CLIENT (client));
 	g_return_if_fail (icalcomps != NULL);
 
-	array = icalcomponent_slist_to_utf8_icomp_array (icalcomps);
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->comp_list = g_slist_copy_deep (
+		icalcomps, (GCopyFunc) icalcomponent_new_clone, NULL);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (client), callback, user_data,
+		e_cal_client_create_objects);
+
+	g_simple_async_result_set_check_cancellable (simple, cancellable);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
 
-	e_client_proxy_call_strv (
-		E_CLIENT (client), (const gchar * const *) array, cancellable, callback, user_data, e_cal_client_create_objects,
-		e_gdbus_cal_call_create_objects,
-		NULL, NULL, NULL, e_gdbus_cal_call_create_objects_finish, NULL);
+	g_simple_async_result_run_in_thread (
+		simple, cal_client_create_objects_thread,
+		G_PRIORITY_DEFAULT, cancellable);
 
-	g_strfreev (array);
+	g_object_unref (simple);
 }
 
 /**
  * e_cal_client_create_objects_finish:
  * @client: an #ECalClient
  * @result: a #GAsyncResult
- * @uids: (out) (element-type utf8): Return value for the UIDs assigned to the
- * new components by the calendar backend
+ * @out_uids: (out) (element-type utf8): Return value for the UIDs assigned
+ *            to the new components by the calendar backend
  * @error: (out): a #GError to set an error, if any
  *
  * Finishes previous call of e_cal_client_create_objects() and
- * sets @uids to newly assigned UIDs for the created objects.
- * This @uids should be freed with e_client_util_free_string_slist().
+ * sets @out_uids to newly assigned UIDs for the created objects.
+ * This @out_uids should be freed with e_client_util_free_string_slist().
  *
  * Returns: %TRUE if successful, %FALSE otherwise.
  *
@@ -3731,34 +4338,46 @@ e_cal_client_create_objects (ECalClient *client,
 gboolean
 e_cal_client_create_objects_finish (ECalClient *client,
                                     GAsyncResult *result,
-                                    GSList **uids,
+                                    GSList **out_uids,
                                     GError **error)
 {
-	gboolean res;
-	gchar **out_strings = NULL;
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
 
-	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
-	g_return_val_if_fail (uids != NULL, FALSE);
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (client),
+		e_cal_client_create_objects), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	if (g_simple_async_result_propagate_error (simple, error))
+		return FALSE;
 
-	res = e_client_proxy_call_finish_strv (E_CLIENT (client), result, &out_strings, error, e_cal_client_create_objects);
+	if (out_uids != NULL) {
+		*out_uids = async_context->string_list;
+		async_context->string_list = NULL;
+	}
 
-	return complete_strv_exchange (res, out_strings, uids, error);
+	return TRUE;
 }
 
 /**
  * e_cal_client_create_objects_sync:
  * @client: an #ECalClient
  * @icalcomps: (element-type icalcomponent): The components to create
- * @uids: (out) (element-type utf8): Return value for the UIDs assigned to the
- * new components by the calendar backend
+ * @out_uids: (out) (element-type utf8): Return value for the UIDs assigned
+ *            to the new components by the calendar backend
  * @cancellable: (allow-none): a #GCancellable; can be %NULL
  * @error: (out): a #GError to set an error, if any
  *
- * Requests the calendar backend to create the objects specified by the @icalcomps
- * argument. Some backends would assign a specific UID to the newly created objects,
- * in those cases these UIDs would be returned in the @uids argument. This function
- * does not modify the original @icalcomps if their UID changes.
- * Returned @uid should be freed with e_client_util_free_string_slist().
+ * Requests the calendar backend to create the objects specified by the
+ * @icalcomps argument. Some backends would assign a specific UID to the
+ * newly created objects, in those cases these UIDs would be returned in
+ * the @out_uids argument. This function does not modify the original
+ * @icalcomps if their UID changes.  Returned @out_uids should be freed
+ * with e_client_util_free_string_slist().
  *
  * Returns: %TRUE if successful, %FALSE otherwise.
  *
@@ -3767,27 +4386,83 @@ e_cal_client_create_objects_finish (ECalClient *client,
 gboolean
 e_cal_client_create_objects_sync (ECalClient *client,
                                   GSList *icalcomps,
-                                  GSList **uids,
+                                  GSList **out_uids,
                                   GCancellable *cancellable,
                                   GError **error)
 {
-	gboolean res;
-	gchar **array, **out_strings = NULL;
+	gchar **strv;
+	gchar **uids = NULL;
+	gboolean success;
+	gint ii = 0;
 
 	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
 	g_return_val_if_fail (icalcomps != NULL, FALSE);
-	g_return_val_if_fail (uids != NULL, FALSE);
+	g_return_val_if_fail (out_uids != NULL, FALSE);
 
 	if (client->priv->dbus_proxy == NULL) {
 		set_proxy_gone_error (error);
 		return FALSE;
 	}
 
-	array = icalcomponent_slist_to_utf8_icomp_array (icalcomps);
+	strv = g_new0 (gchar *, g_slist_length (icalcomps) + 1);
+	while (icalcomps != NULL) {
+		gchar *ical_string;
+
+		ical_string = icalcomponent_as_ical_string_r (icalcomps->data);
+		strv[ii++] = e_util_utf8_make_valid (ical_string);
+		g_free (ical_string);
+
+		icalcomps = g_slist_next (icalcomps);
+	}
+
+	success = e_dbus_calendar_call_create_objects_sync (
+		client->priv->dbus_proxy,
+		(const gchar * const *) strv,
+		&uids, cancellable, error);
+
+	g_strfreev (strv);
+
+	/* Sanity check. */
+	g_return_val_if_fail (
+		(success && (uids != NULL)) ||
+		(!success && (uids == NULL)), FALSE);
+
+	if (uids != NULL) {
+		GSList *tmp = NULL;
+
+		/* Steal the string array elements. */
+		for (ii = 0; uids[ii] != NULL; ii++) {
+			tmp = g_slist_prepend (tmp, uids[ii]);
+			uids[ii] = NULL;
+		}
+
+		*out_uids = g_slist_reverse (tmp);
+	}
+
+	g_strfreev (uids);
+
+	return success;
+}
+
+/* Helper for e_cal_client_modify_object() */
+static void
+cal_client_modify_object_thread (GSimpleAsyncResult *simple,
+                                 GObject *source_object,
+                                 GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
 
-	res = e_client_proxy_call_sync_strv__strv (E_CLIENT (client), (const gchar * const *) array, &out_strings, cancellable, error, e_gdbus_cal_call_create_objects_sync);
+	e_cal_client_modify_object_sync (
+		E_CAL_CLIENT (source_object),
+		async_context->in_comp,
+		async_context->mod,
+		cancellable, &error);
 
-	return complete_strv_exchange (res, out_strings, uids, error);
+	if (error != NULL)
+		g_simple_async_result_take_error (simple, error);
 }
 
 /**
@@ -3814,28 +4489,36 @@ e_cal_client_create_objects_sync (ECalClient *client,
  **/
 void
 e_cal_client_modify_object (ECalClient *client,
-                            /* const */ icalcomponent *icalcomp,
+                            icalcomponent *icalcomp,
                             ECalObjModType mod,
                             GCancellable *cancellable,
                             GAsyncReadyCallback callback,
                             gpointer user_data)
 {
-	gchar *comp_str, **strv;
-	GSList comp_strings = {0,};
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
 
+	g_return_if_fail (E_IS_CAL_CLIENT (client));
 	g_return_if_fail (icalcomp != NULL);
 
-	comp_str = icalcomponent_as_ical_string_r (icalcomp);
-	comp_strings.data = comp_str;
-	strv = e_gdbus_cal_encode_modify_objects (&comp_strings, mod);
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->in_comp = icalcomponent_new_clone (icalcomp);
+	async_context->mod = 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_objects,
-		e_gdbus_cal_call_modify_objects_finish, NULL, NULL, NULL, NULL);
+	simple = g_simple_async_result_new (
+		G_OBJECT (client), callback, user_data,
+		e_cal_client_modify_object);
 
-	g_strfreev (strv);
-	g_free (comp_str);
+	g_simple_async_result_set_check_cancellable (simple, cancellable);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, cal_client_modify_object_thread,
+		G_PRIORITY_DEFAULT, cancellable);
+
+	g_object_unref (simple);
 }
 
 /**
@@ -3855,7 +4538,17 @@ 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);
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (client),
+		e_cal_client_modify_object), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
 }
 
 /**
@@ -3880,33 +4573,39 @@ e_cal_client_modify_object_finish (ECalClient *client,
  **/
 gboolean
 e_cal_client_modify_object_sync (ECalClient *client,
-                                 /* const */ icalcomponent *icalcomp,
+                                 icalcomponent *icalcomp,
                                  ECalObjModType mod,
                                  GCancellable *cancellable,
                                  GError **error)
 {
-	gboolean res;
-	gchar *comp_str, **strv;
-	GSList comp_strings = {0,};
+	GSList link = { icalcomp, NULL };
 
 	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
 	g_return_val_if_fail (icalcomp != NULL, FALSE);
 
-	if (client->priv->dbus_proxy == NULL) {
-		set_proxy_gone_error (error);
-		return FALSE;
-	}
+	return e_cal_client_modify_objects_sync (
+		client, &link, mod, cancellable, error);
+}
 
-	comp_str = icalcomponent_as_ical_string_r (icalcomp);
-	comp_strings.data = comp_str;
-	strv = e_gdbus_cal_encode_modify_objects (&comp_strings, mod);
+/* Helper for e_cal_client_modify_objects() */
+static void
+cal_client_modify_objects_thread (GSimpleAsyncResult *simple,
+                                  GObject *source_object,
+                                  GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
 
-	res = e_client_proxy_call_sync_strv__void (E_CLIENT (client), (const gchar * const *) strv, cancellable, error, e_gdbus_cal_call_modify_objects_sync);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
 
-	g_strfreev (strv);
-	g_free (comp_str);
+	e_cal_client_modify_objects_sync (
+		E_CAL_CLIENT (source_object),
+		async_context->comp_list,
+		async_context->mod,
+		cancellable, &error);
 
-	return res;
+	if (error != NULL)
+		g_simple_async_result_take_error (simple, error);
 }
 
 /**
@@ -3933,28 +4632,37 @@ e_cal_client_modify_object_sync (ECalClient *client,
  **/
 void
 e_cal_client_modify_objects (ECalClient *client,
-                             /* const */ GSList *comps,
+                             GSList *comps,
                              ECalObjModType mod,
                              GCancellable *cancellable,
                              GAsyncReadyCallback callback,
                              gpointer user_data)
 {
-	GSList *comp_strings;
-	gchar **strv;
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
 
 	g_return_if_fail (E_IS_CAL_CLIENT (client));
 	g_return_if_fail (comps != NULL);
 
-	comp_strings = icalcomponent_slist_to_string_slist (comps);
-	strv = e_gdbus_cal_encode_modify_objects (comp_strings, mod);
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->comp_list = g_slist_copy_deep (
+		comps, (GCopyFunc) icalcomponent_new_clone, NULL);
+	async_context->mod = mod;
 
-	e_client_proxy_call_strv (
-		E_CLIENT (client), (const gchar * const *) strv, cancellable, callback, user_data, e_cal_client_modify_objects,
-		e_gdbus_cal_call_modify_objects,
-		e_gdbus_cal_call_modify_objects_finish, NULL, NULL, NULL, NULL);
+	simple = g_simple_async_result_new (
+		G_OBJECT (client), callback, user_data,
+		e_cal_client_modify_objects);
 
-	g_strfreev (strv);
-	e_client_util_free_string_slist (comp_strings);
+	g_simple_async_result_set_check_cancellable (simple, cancellable);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, cal_client_modify_objects_thread,
+		G_PRIORITY_DEFAULT, cancellable);
+
+	g_object_unref (simple);
 }
 
 /**
@@ -3974,9 +4682,17 @@ e_cal_client_modify_objects_finish (ECalClient *client,
                                     GAsyncResult *result,
                                     GError **error)
 {
-	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (client),
+		e_cal_client_modify_objects), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
 
-	return e_client_proxy_call_finish_void (E_CLIENT (client), result, error, e_cal_client_modify_objects);
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
 }
 
 /**
@@ -4001,14 +4717,16 @@ e_cal_client_modify_objects_finish (ECalClient *client,
  **/
 gboolean
 e_cal_client_modify_objects_sync (ECalClient *client,
-                                  /* const */ GSList *comps,
+                                  GSList *comps,
                                   ECalObjModType mod,
                                   GCancellable *cancellable,
                                   GError **error)
 {
-	gboolean res;
+	GEnumClass *enum_class;
+	GEnumValue *enum_value;
+	gboolean success;
 	gchar **strv;
-	GSList *comp_strings;
+	gint ii = 0;
 
 	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
 	g_return_val_if_fail (comps != NULL, FALSE);
@@ -4018,15 +4736,52 @@ e_cal_client_modify_objects_sync (ECalClient *client,
 		return FALSE;
 	}
 
-	comp_strings = icalcomponent_slist_to_string_slist (comps);
-	strv = e_gdbus_cal_encode_modify_objects (comp_strings, mod);
+	enum_class = g_type_class_ref (E_TYPE_CAL_OBJ_MOD_TYPE);
+	enum_value = g_enum_get_value (enum_class, mod);
+	g_return_val_if_fail (enum_value != NULL, FALSE);
 
-	res = e_client_proxy_call_sync_strv__void (E_CLIENT (client), (const gchar * const *) strv, cancellable, error, e_gdbus_cal_call_modify_objects_sync);
+	strv = g_new0 (gchar *, g_slist_length (comps) + 1);
+	while (comps != NULL) {
+		gchar *ical_string;
+
+		ical_string = icalcomponent_as_ical_string_r (comps->data);
+		strv[ii++] = e_util_utf8_make_valid (ical_string);
+		g_free (ical_string);
+	}
+
+	success = e_dbus_calendar_call_modify_objects_sync (
+		client->priv->dbus_proxy,
+		(const gchar * const *) strv,
+		enum_value->value_nick,
+		cancellable, error);
 
 	g_strfreev (strv);
-	e_client_util_free_string_slist (comp_strings);
 
-	return res;
+	g_type_class_unref (enum_class);
+
+	return success;
+}
+
+/* Helper for e_cal_client_remove_object() */
+static void
+cal_client_remove_object_thread (GSimpleAsyncResult *simple,
+                                 GObject *source_object,
+                                 GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	e_cal_client_remove_object_sync (
+		E_CAL_CLIENT (source_object),
+		async_context->uid,
+		async_context->rid,
+		async_context->mod,
+		cancellable, &error);
+
+	if (error != NULL)
+		g_simple_async_result_take_error (simple, error);
 }
 
 /**
@@ -4059,23 +4814,32 @@ e_cal_client_remove_object (ECalClient *client,
                             GAsyncReadyCallback callback,
                             gpointer user_data)
 {
-	gchar **strv;
-	GSList ids = {0,};
-	ECalComponentId id;
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
 
+	g_return_if_fail (E_IS_CAL_CLIENT (client));
 	g_return_if_fail (uid != NULL);
+	/* rid is optional */
 
-	id.uid = (gchar *) uid;
-	id.rid = (gchar *) rid;
-	ids.data = &id;
-	strv = e_gdbus_cal_encode_remove_objects (&ids, mod);
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->uid = g_strdup (uid);
+	async_context->rid = g_strdup (rid);
+	async_context->mod = 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_objects,
-		e_gdbus_cal_call_remove_objects_finish, NULL, NULL, NULL, NULL);
+	simple = g_simple_async_result_new (
+		G_OBJECT (client), callback, user_data,
+		e_cal_client_remove_object);
 
-	g_strfreev (strv);
+	g_simple_async_result_set_check_cancellable (simple, cancellable);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, cal_client_remove_object_thread,
+		G_PRIORITY_DEFAULT, cancellable);
+
+	g_object_unref (simple);
 }
 
 /**
@@ -4095,7 +4859,17 @@ 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);
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (client),
+		e_cal_client_remove_object), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
 }
 
 /**
@@ -4125,10 +4899,8 @@ e_cal_client_remove_object_sync (ECalClient *client,
                                  GCancellable *cancellable,
                                  GError **error)
 {
-	gboolean res;
-	gchar **strv;
-	GSList ids = {0,};
-	ECalComponentId id;
+	ECalComponentId id = { (gchar *) uid, (gchar *) rid };
+	GSList link = { &id, NULL };
 
 	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
 	g_return_val_if_fail (uid != NULL, FALSE);
@@ -4138,16 +4910,29 @@ e_cal_client_remove_object_sync (ECalClient *client,
 		return FALSE;
 	}
 
-	id.uid = (gchar *) uid;
-	id.rid = (gchar *) rid;
-	ids.data = &id;
-	strv = e_gdbus_cal_encode_remove_objects (&ids, mod);
+	return e_cal_client_remove_objects_sync (
+		client, &link, mod, cancellable, error);
+}
 
-	res = e_client_proxy_call_sync_strv__void (E_CLIENT (client), (const gchar * const *) strv, cancellable, error, e_gdbus_cal_call_remove_objects_sync);
+/* Helper for e_cal_client_remove_objects() */
+static void
+cal_client_remove_objects_thread (GSimpleAsyncResult *simple,
+                                  GObject *source_object,
+                                  GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
 
-	g_strfreev (strv);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
 
-	return res;
+	e_cal_client_remove_objects_sync (
+		E_CAL_CLIENT (source_object),
+		async_context->string_list,
+		async_context->mod,
+		cancellable, &error);
+
+	if (error != NULL)
+		g_simple_async_result_take_error (simple, error);
 }
 
 /**
@@ -4178,18 +4963,31 @@ e_cal_client_remove_objects (ECalClient *client,
                              GAsyncReadyCallback callback,
                              gpointer user_data)
 {
-	gchar **strv;
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
 
+	g_return_if_fail (E_IS_CAL_CLIENT (client));
 	g_return_if_fail (ids != NULL);
 
-	strv = e_gdbus_cal_encode_remove_objects (ids, mod);
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->string_list = g_slist_copy_deep (
+		(GSList *) ids, (GCopyFunc) g_strdup, NULL);
+	async_context->mod = mod;
 
-	e_client_proxy_call_strv (
-		E_CLIENT (client), (const gchar * const *) strv, cancellable, callback, user_data, e_cal_client_remove_objects,
-		e_gdbus_cal_call_remove_objects,
-		e_gdbus_cal_call_remove_objects_finish, NULL, NULL, NULL, NULL);
+	simple = g_simple_async_result_new (
+		G_OBJECT (client), callback, user_data,
+		e_cal_client_remove_objects);
 
-	g_strfreev (strv);
+	g_simple_async_result_set_check_cancellable (simple, cancellable);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, cal_client_remove_objects_thread,
+		G_PRIORITY_DEFAULT, cancellable);
+
+	g_object_unref (simple);
 }
 
 /**
@@ -4209,22 +5007,32 @@ e_cal_client_remove_objects_finish (ECalClient *client,
                                     GAsyncResult *result,
                                     GError **error)
 {
-	return e_client_proxy_call_finish_void (E_CLIENT (client), result, error, e_cal_client_remove_objects);
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (client),
+		e_cal_client_remove_objects), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
 }
 
 /**
  * e_cal_client_remove_objects_sync:
  * @client: an #ECalClient
- * @ids: (element-type ECalComponentId): A list of #ECalComponentId objects
- * identifying the objects to remove
+ * @ids: (element-type ECalComponentId): a list of #ECalComponentId objects
+ *       identifying the objects to remove
  * @mod: Type of the removal
  * @cancellable: (allow-none): a #GCancellable; can be %NULL
  * @error: (out): a #GError to set an error, if any
  *
  * This function allows the removal of instances of recurrent
- * appointments. #ECalComponentId objects can identify specific instances (if rid is not NULL).
- * If what you want is to remove all instances, use a #NULL rid in the #ECalComponentId and E_CAL_OBJ_MOD_ALL
- * for the @mod.
+ * appointments. #ECalComponentId objects can identify specific instances
+ * (if rid is not %NULL).  If what you want is to remove all instances, use
+ * a %NULL rid in the #ECalComponentId and E_CAL_OBJ_MOD_ALL for the @mod.
  *
  * Returns: %TRUE if successful, %FALSE otherwise.
  *
@@ -4237,8 +5045,10 @@ e_cal_client_remove_objects_sync (ECalClient *client,
                                   GCancellable *cancellable,
                                   GError **error)
 {
-	gboolean res;
-	gchar **strv;
+	GVariantBuilder builder;
+	GEnumClass *enum_class;
+	GEnumValue *enum_value;
+	gboolean success;
 
 	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
 	g_return_val_if_fail (ids != NULL, FALSE);
@@ -4248,13 +5058,60 @@ e_cal_client_remove_objects_sync (ECalClient *client,
 		return FALSE;
 	}
 
-	strv = e_gdbus_cal_encode_remove_objects (ids, mod);
+	enum_class = g_type_class_ref (E_TYPE_CAL_OBJ_MOD_TYPE);
+	enum_value = g_enum_get_value (enum_class, mod);
+	g_return_val_if_fail (enum_value != NULL, FALSE);
 
-	res = e_client_proxy_call_sync_strv__void (E_CLIENT (client), (const gchar * const *) strv, cancellable, error, e_gdbus_cal_call_remove_objects_sync);
+	g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
+	while (ids != NULL) {
+		ECalComponentId *id = ids->data;
+		gchar *utf8_uid;
+		gchar *utf8_rid;
 
-	g_strfreev (strv);
+		if (id->uid == NULL || *id->uid == '\0')
+			continue;
+
+		utf8_uid = e_util_utf8_make_valid (id->uid);
+		if (id->rid != NULL)
+			utf8_rid = e_util_utf8_make_valid (id->rid);
+		else
+			utf8_rid = g_strdup ("");
+
+		g_variant_builder_add (&builder, "(ss)", utf8_uid, utf8_rid);
+
+		g_free (utf8_uid);
+		g_free (utf8_rid);
+	}
+
+	success = e_dbus_calendar_call_remove_objects_sync (
+		client->priv->dbus_proxy,
+		g_variant_builder_end (&builder),
+		enum_value->value_nick,
+		cancellable, error);
+
+	g_type_class_unref (enum_class);
+
+	return success;
+}
+
+/* Helper for e_cal_client_receive_objects() */
+static void
+cal_client_receive_objects_thread (GSimpleAsyncResult *simple,
+                                   GObject *source_object,
+                                   GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
 
-	return res;
+	e_cal_client_receive_objects_sync (
+		E_CAL_CLIENT (source_object),
+		async_context->in_comp,
+		cancellable, &error);
+
+	if (error != NULL)
+		g_simple_async_result_take_error (simple, error);
 }
 
 /**
@@ -4276,24 +5133,34 @@ e_cal_client_remove_objects_sync (ECalClient *client,
  **/
 void
 e_cal_client_receive_objects (ECalClient *client,
-                              /* const */ icalcomponent *icalcomp,
+                              icalcomponent *icalcomp,
                               GCancellable *cancellable,
                               GAsyncReadyCallback callback,
                               gpointer user_data)
 {
-	gchar *comp_str, *gdbus_comp = NULL;
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
 
+	g_return_if_fail (E_IS_CAL_CLIENT (client));
 	g_return_if_fail (icalcomp != NULL);
 
-	comp_str = icalcomponent_as_ical_string_r (icalcomp);
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->in_comp = icalcomponent_new_clone (icalcomp);
+
+	simple = g_simple_async_result_new (
+		G_OBJECT (client), callback, user_data,
+		e_cal_client_receive_objects);
+
+	g_simple_async_result_set_check_cancellable (simple, cancellable);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
 
-	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_simple_async_result_run_in_thread (
+		simple, cal_client_receive_objects_thread,
+		G_PRIORITY_DEFAULT, cancellable);
 
-	g_free (comp_str);
-	g_free (gdbus_comp);
+	g_object_unref (simple);
 }
 
 /**
@@ -4313,7 +5180,17 @@ 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);
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (client),
+		e_cal_client_receive_objects), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
 }
 
 /**
@@ -4333,12 +5210,13 @@ e_cal_client_receive_objects_finish (ECalClient *client,
  **/
 gboolean
 e_cal_client_receive_objects_sync (ECalClient *client,
-                                   /* const */ icalcomponent *icalcomp,
+                                   icalcomponent *icalcomp,
                                    GCancellable *cancellable,
                                    GError **error)
 {
-	gboolean res;
-	gchar *comp_str, *gdbus_comp = NULL;
+	gchar *ical_string;
+	gchar *utf8_ical_string;
+	gboolean success;
 
 	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
 
@@ -4347,14 +5225,39 @@ e_cal_client_receive_objects_sync (ECalClient *client,
 		return FALSE;
 	}
 
-	comp_str = icalcomponent_as_ical_string_r (icalcomp);
+	ical_string = icalcomponent_as_ical_string_r (icalcomp);
+	utf8_ical_string = e_util_utf8_make_valid (ical_string);
+
+	success = e_dbus_calendar_call_receive_objects_sync (
+		client->priv->dbus_proxy,
+		utf8_ical_string, cancellable, error);
+
+	g_free (utf8_ical_string);
+	g_free (ical_string);
+
+	return success;
+}
+
+/* Helper for e_cal_client_send_objects() */
+static void
+cal_client_send_objects_thread (GSimpleAsyncResult *simple,
+                                GObject *source_object,
+                                GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
 
-	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);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
 
-	g_free (comp_str);
-	g_free (gdbus_comp);
+	e_cal_client_send_objects_sync (
+		E_CAL_CLIENT (source_object),
+		async_context->in_comp,
+		&async_context->string_list,
+		&async_context->out_comp,
+		cancellable, &error);
 
-	return res;
+	if (error != NULL)
+		g_simple_async_result_take_error (simple, error);
 }
 
 /**
@@ -4374,80 +5277,50 @@ e_cal_client_receive_objects_sync (ECalClient *client,
  **/
 void
 e_cal_client_send_objects (ECalClient *client,
-                           /* const */ icalcomponent *icalcomp,
+                           icalcomponent *icalcomp,
                            GCancellable *cancellable,
                            GAsyncReadyCallback callback,
                            gpointer user_data)
 {
-	gchar *comp_str, *gdbus_comp = NULL;
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
 
+	g_return_if_fail (E_IS_CAL_CLIENT (client));
 	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);
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->in_comp = icalcomponent_new_clone (icalcomp);
 
-	g_free (comp_str);
-	g_free (gdbus_comp);
-}
+	simple = g_simple_async_result_new (
+		G_OBJECT (client), callback, user_data,
+		e_cal_client_send_objects);
 
-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_propagate_error (error, e_cal_client_error_create (E_CAL_CLIENT_ERROR_INVALID_OBJECT, NULL));
-				e_client_util_free_string_slist (*users);
-				*users = NULL;
-				res = FALSE;
-			}
-		} else {
-			g_propagate_error (error, e_client_error_create (E_CLIENT_ERROR_INVALID_ARG, NULL));
-			e_client_util_free_string_slist (*users);
-			*users = NULL;
-			res = FALSE;
-		}
+	g_simple_async_result_set_check_cancellable (simple, cancellable);
 
-		g_free (calobj);
-	} else {
-		res = FALSE;
-	}
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
 
-	g_strfreev (out_strv);
+	g_simple_async_result_run_in_thread (
+		simple, cal_client_send_objects_thread,
+		G_PRIORITY_DEFAULT, cancellable);
 
-	return res;
+	g_object_unref (simple);
 }
 
 /**
  * e_cal_client_send_objects_finish:
  * @client: an #ECalClient
  * @result: a #GAsyncResult
- * @users: (out) (element-type utf8): List of users to send
- * the @modified_icalcomp to
- * @modified_icalcomp: (out): Return value for the icalcomponent to be sent
+ * @out_users: (out) (element-type utf8): List of users to send
+ *             the @out_modified_icalcomp to
+ * @out_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().
+ * populates @out_users with a list of users to send @out_modified_icalcomp to.
+ *
+ * The @out_users list should be freed with e_client_util_free_string_slist()
+ * and the @out_modified_icalcomp should be freed with icalcomponent_free().
  *
  * Returns: %TRUE if successful, %FALSE otherwise.
  *
@@ -4456,35 +5329,55 @@ complete_send_objects (gboolean res,
 gboolean
 e_cal_client_send_objects_finish (ECalClient *client,
                                   GAsyncResult *result,
-                                  GSList **users,
-                                  icalcomponent **modified_icalcomp,
+                                  GSList **out_users,
+                                  icalcomponent **out_modified_icalcomp,
                                   GError **error)
 {
-	gboolean res;
-	gchar **out_strv = NULL;
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (client),
+		e_cal_client_send_objects), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	if (g_simple_async_result_propagate_error (simple, error))
+		return FALSE;
+
+	g_return_val_if_fail (async_context->out_comp != NULL, FALSE);
 
-	g_return_val_if_fail (users != NULL, FALSE);
-	g_return_val_if_fail (modified_icalcomp != NULL, FALSE);
+	if (out_users != NULL) {
+		*out_users = async_context->string_list;
+		async_context->string_list = NULL;
+	}
 
-	res = e_client_proxy_call_finish_strv (E_CLIENT (client), result, &out_strv, error, e_cal_client_send_objects);
+	if (out_modified_icalcomp != NULL) {
+		*out_modified_icalcomp = async_context->out_comp;
+		async_context->out_comp = NULL;
+	}
 
-	return complete_send_objects (res, out_strv, users, modified_icalcomp, error);
+	return TRUE;
 }
 
 /**
  * e_cal_client_send_objects_sync:
  * @client: an #ECalClient
  * @icalcomp: An icalcomponent to be sent
- * @users: (out) (element-type utf8): List of users to send
- * the @modified_icalcomp to
- * @modified_icalcomp: (out): Return value for the icalcomponent to be sent
+ * @out_users: (out) (element-type utf8): List of users to send the
+ *             @out_modified_icalcomp to
+ * @out_modified_icalcomp: (out): Return value for the icalcomponent to be sent
  * @cancellable: (allow-none): 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().
+ * The backend can modify this component and request a send to users in the
+ * @out_users list.
+ *
+ * The @out_users list should be freed with e_client_util_free_string_slist()
+ * and the @out_modified_icalcomp should be freed with icalcomponent_free().
  *
  * Returns: %TRUE if successful, %FALSE otherwise.
  *
@@ -4492,33 +5385,99 @@ e_cal_client_send_objects_finish (ECalClient *client,
  **/
 gboolean
 e_cal_client_send_objects_sync (ECalClient *client,
-                                /* const */ icalcomponent *icalcomp,
-                                GSList **users,
-                                icalcomponent **modified_icalcomp,
+                                icalcomponent *icalcomp,
+                                GSList **out_users,
+                                icalcomponent **out_modified_icalcomp,
                                 GCancellable *cancellable,
                                 GError **error)
 {
-	gboolean res;
-	gchar **out_strv = NULL, *comp_str, *gdbus_comp = NULL;
+	gchar *ical_string;
+	gchar *utf8_ical_string;
+	gchar **users = NULL;
+	gchar *out_ical_string = NULL;
+	gboolean success;
 
 	g_return_val_if_fail (E_IS_CAL_CLIENT (client), 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);
+	g_return_val_if_fail (out_users != NULL, FALSE);
+	g_return_val_if_fail (out_modified_icalcomp != NULL, FALSE);
 
 	if (client->priv->dbus_proxy == NULL) {
 		set_proxy_gone_error (error);
 		return FALSE;
 	}
 
-	comp_str = icalcomponent_as_ical_string_r (icalcomp);
+	ical_string = icalcomponent_as_ical_string_r (icalcomp);
+	utf8_ical_string = e_util_utf8_make_valid (ical_string);
+
+	success = e_dbus_calendar_call_send_objects_sync (
+		client->priv->dbus_proxy, utf8_ical_string,
+		&users, &out_ical_string, cancellable, error);
+
+	g_free (utf8_ical_string);
+	g_free (ical_string);
+
+	/* Sanity check. */
+	g_return_val_if_fail (
+		(success && (out_ical_string != NULL)) ||
+		(!success && (out_ical_string == NULL)), FALSE);
+
+	if (!success) {
+		g_warn_if_fail (users == NULL);
+		return FALSE;
+	}
+
+	icalcomp = icalparser_parse_string (out_ical_string);
+
+	g_free (out_ical_string);
+
+	if (icalcomp != NULL) {
+		*out_modified_icalcomp = icalcomp;
+	} else {
+		g_propagate_error (
+			error, e_cal_client_error_create (
+			E_CAL_CLIENT_ERROR_INVALID_OBJECT, NULL));
+		g_strfreev (users);
+		return FALSE;
+	}
+
+	if (users != NULL) {
+		GSList *tmp = NULL;
+		gint ii;
+
+		for (ii = 0; users[ii] != NULL; ii++) {
+			tmp = g_slist_prepend (tmp, users[ii]);
+			users[ii] = NULL;
+		}
+
+		*out_users = g_slist_reverse (tmp);
+	}
+
+	g_strfreev (users);
+
+	return TRUE;
+}
+
+/* Helper for e_cal_client_get_attachment_uris() */
+static void
+cal_client_get_attachment_uris_thread (GSimpleAsyncResult *simple,
+                                       GObject *source_object,
+                                       GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
 
-	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);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
 
-	g_free (comp_str);
-	g_free (gdbus_comp);
+	e_cal_client_get_attachment_uris_sync (
+		E_CAL_CLIENT (source_object),
+		async_context->uid,
+		async_context->rid,
+		&async_context->string_list,
+		cancellable, &error);
 
-	return complete_send_objects (res, out_strv, users, modified_icalcomp, error);
+	if (error != NULL)
+		g_simple_async_result_take_error (simple, error);
 }
 
 /**
@@ -4544,30 +5503,40 @@ e_cal_client_get_attachment_uris (ECalClient *client,
                                   GAsyncReadyCallback callback,
                                   gpointer user_data)
 {
-	gchar **strv;
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
 
+	g_return_if_fail (E_CAL_CLIENT (client));
 	g_return_if_fail (uid != NULL);
+	/* rid is optional */
 
-	strv = e_gdbus_cal_encode_get_attachment_uris (uid, rid);
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->uid = g_strdup (uid);
+	async_context->rid = g_strdup (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);
+	simple = g_simple_async_result_new (
+		G_OBJECT (client), callback, user_data,
+		e_cal_client_get_attachment_uris);
 
-	g_strfreev (strv);
+	g_simple_async_result_set_check_cancellable (simple, cancellable);
+
+	g_simple_async_result_run_in_thread (
+		simple, cal_client_get_attachment_uris_thread,
+		G_PRIORITY_DEFAULT, cancellable);
+
+	g_object_unref (simple);
 }
 
 /**
  * e_cal_client_get_attachment_uris_finish:
  * @client: an #ECalClient
  * @result: a #GAsyncResult
- * @attachment_uris: (out) (element-type utf8): Return the list of attachment
- * URIs
+ * @out_attachment_uris: (out) (element-type utf8): Return location for 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.
+ * sets @out_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.
@@ -4577,25 +5546,29 @@ e_cal_client_get_attachment_uris (ECalClient *client,
 gboolean
 e_cal_client_get_attachment_uris_finish (ECalClient *client,
                                          GAsyncResult *result,
-                                         GSList **attachment_uris,
+                                         GSList **out_attachment_uris,
                                          GError **error)
 {
-	gboolean res;
-	gchar **out_strv = NULL;
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (client),
+		e_cal_client_get_attachment_uris), FALSE);
 
-	g_return_val_if_fail (attachment_uris != NULL, FALSE);
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
 
-	res = e_client_proxy_call_finish_strv (E_CLIENT (client), result, &out_strv, error, e_cal_client_get_attachment_uris);
+	if (g_simple_async_result_propagate_error (simple, error))
+		return FALSE;
 
-	if (res && out_strv) {
-		*attachment_uris = e_client_util_strv_to_slist ((const gchar * const *) out_strv);
-	} else {
-		*attachment_uris = NULL;
+	if (out_attachment_uris != NULL) {
+		*out_attachment_uris = async_context->string_list;
+		async_context->string_list = NULL;
 	}
 
-	g_strfreev (out_strv);
-
-	return res;
+	return TRUE;
 }
 
 /**
@@ -4603,8 +5576,8 @@ e_cal_client_get_attachment_uris_finish (ECalClient *client,
  * @client: an #ECalClient
  * @uid: Unique identifier for a calendar component
  * @rid: Recurrence identifier
- * @attachment_uris: (out) (element-type utf8): Return the list of attachment
- * URIs
+ * @out_attachment_uris: (out) (element-type utf8): Return location for the
+ *                       list of attachment URIs
  * @cancellable: (allow-none): a #GCancellable; can be %NULL
  * @error: (out): a #GError to set an error, if any
  *
@@ -4619,37 +5592,77 @@ gboolean
 e_cal_client_get_attachment_uris_sync (ECalClient *client,
                                        const gchar *uid,
                                        const gchar *rid,
-                                       GSList **attachment_uris,
+                                       GSList **out_attachment_uris,
                                        GCancellable *cancellable,
                                        GError **error)
 {
-	gboolean res;
-	gchar **strv, **out_strv = NULL;
+	gchar *utf8_uid;
+	gchar *utf8_rid;
+	gchar **uris = NULL;
+	gboolean success;
 
 	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
 	g_return_val_if_fail (uid != NULL, FALSE);
-	g_return_val_if_fail (attachment_uris != NULL, FALSE);
+	g_return_val_if_fail (out_attachment_uris != NULL, FALSE);
+
+	if (rid == NULL)
+		rid = "";
 
 	if (client->priv->dbus_proxy == NULL) {
 		set_proxy_gone_error (error);
 		return FALSE;
 	}
 
-	strv = e_gdbus_cal_encode_get_attachment_uris (uid, rid);
+	utf8_uid = e_util_utf8_make_valid (uid);
+	utf8_rid = e_util_utf8_make_valid (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);
+	success = e_dbus_calendar_call_get_attachment_uris_sync (
+		client->priv->dbus_proxy, utf8_uid,
+		utf8_rid, &uris, cancellable, error);
 
-	g_strfreev (strv);
+	g_free (utf8_uid);
+	g_free (utf8_rid);
 
-	if (res && out_strv) {
-		*attachment_uris = e_client_util_strv_to_slist ((const gchar * const *) out_strv);
-	} else {
-		*attachment_uris = NULL;
+	/* Sanity check. */
+	g_return_val_if_fail (
+		(success && (uris != NULL)) ||
+		(!success && (uris == NULL)), FALSE);
+
+	if (uris != NULL) {
+		GSList *tmp;
+		gint ii;
+
+		for (ii = 0; uris[ii] != NULL; ii++) {
+			tmp = g_slist_prepend (tmp, uris[ii]);
+			uris[ii] = NULL;
+		}
+
+		*out_attachment_uris = g_slist_reverse (tmp);
 	}
 
-	g_strfreev (out_strv);
+	return success;
+}
+
+/* Helper for e_cal_client_discard_alarm() */
+static void
+cal_client_discard_alarm_thread (GSimpleAsyncResult *simple,
+                                 GObject *source_object,
+                                 GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
 
-	return res;
+	e_cal_client_discard_alarm_sync (
+		E_CAL_CLIENT (source_object),
+		async_context->uid,
+		async_context->rid,
+		async_context->auid,
+		cancellable, &error);
+
+	if (error != NULL)
+		g_simple_async_result_take_error (simple, error);
 }
 
 /**
@@ -4677,19 +5690,33 @@ e_cal_client_discard_alarm (ECalClient *client,
                             GAsyncReadyCallback callback,
                             gpointer user_data)
 {
-	gchar **strv;
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
 
+	g_return_if_fail (E_IS_CAL_CLIENT (client));
 	g_return_if_fail (uid != NULL);
+	/* rid is optional */
 	g_return_if_fail (auid != NULL);
 
-	strv = e_gdbus_cal_encode_discard_alarm (uid, rid, auid);
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->uid = g_strdup (uid);
+	async_context->rid = NULL;
+	async_context->auid = g_strdup (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);
+	simple = g_simple_async_result_new (
+		G_OBJECT (client), callback, user_data,
+		e_cal_client_discard_alarm);
 
-	g_strfreev (strv);
+	g_simple_async_result_set_check_cancellable (simple, cancellable);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	g_simple_async_result_run_in_thread (
+		simple, cal_client_discard_alarm_thread,
+		G_PRIORITY_DEFAULT, cancellable);
+
+	g_object_unref (simple);
 }
 
 /**
@@ -4709,7 +5736,17 @@ 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);
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (client),
+		e_cal_client_discard_alarm), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
 }
 
 /**
@@ -4735,25 +5772,57 @@ e_cal_client_discard_alarm_sync (ECalClient *client,
                                  GCancellable *cancellable,
                                  GError **error)
 {
-	gboolean res;
-	gchar **strv;
+	gchar *utf8_uid;
+	gchar *utf8_rid;
+	gchar *utf8_auid;
+	gboolean success;
 
 	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
 	g_return_val_if_fail (uid != NULL, FALSE);
 	g_return_val_if_fail (auid != NULL, FALSE);
 
+	if (rid == NULL)
+		rid = "";
+
 	if (client->priv->dbus_proxy == NULL) {
 		set_proxy_gone_error (error);
 		return FALSE;
 	}
 
-	strv = e_gdbus_cal_encode_discard_alarm (uid, rid, auid);
+	utf8_uid = e_util_utf8_make_valid (uid);
+	utf8_rid = e_util_utf8_make_valid (rid);
+	utf8_auid = e_util_utf8_make_valid (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);
+	success = e_dbus_calendar_call_discard_alarm_sync (
+		client->priv->dbus_proxy, utf8_uid,
+		utf8_rid, utf8_auid, cancellable, error);
 
-	g_strfreev (strv);
+	g_free (utf8_uid);
+	g_free (utf8_rid);
+	g_free (utf8_auid);
 
-	return res;
+	return success;
+}
+
+/* Helper for e_cal_client_get_view() */
+static void
+cal_client_get_view_thread (GSimpleAsyncResult *simple,
+                            GObject *source_object,
+                            GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	e_cal_client_get_view_sync (
+		E_CAL_CLIENT (source_object),
+		async_context->sexp,
+		&async_context->client_view,
+		cancellable, &error);
+
+	if (error != NULL)
+		g_simple_async_result_take_error (simple, error);
 }
 
 /**
@@ -4777,68 +5846,40 @@ e_cal_client_get_view (ECalClient *client,
                        GAsyncReadyCallback callback,
                        gpointer user_data)
 {
-	gchar *gdbus_sexp = NULL;
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
 
+	g_return_if_fail (E_IS_CAL_CLIENT (client));
 	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) {
-		GDBusConnection *connection;
-		GError *local_error = NULL;
-
-		connection = g_dbus_proxy_get_connection (
-			G_DBUS_PROXY (cal_factory));
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->sexp = g_strdup (sexp);
 
-		*view = g_initable_new (
-			E_TYPE_CAL_CLIENT_VIEW,
-			NULL, &local_error,
-			"client", client,
-			"connection", connection,
-			"object-path", view_path,
-			NULL);
+	simple = g_simple_async_result_new (
+		G_OBJECT (client), callback, user_data,
+		e_cal_client_get_view);
 
-		if (local_error != NULL) {
-			unwrap_dbus_error (local_error, error);
-			res = FALSE;
-		}
-	} else {
-		*view = NULL;
-		res = FALSE;
-	}
+	g_simple_async_result_set_check_cancellable (simple, cancellable);
 
-	if (!*view && error && !*error)
-		g_set_error_literal (error, E_CLIENT_ERROR, E_CLIENT_ERROR_DBUS_ERROR, _("Cannot get connection to view"));
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
 
-	g_free (view_path);
+	g_simple_async_result_run_in_thread (
+		simple, cal_client_get_view_thread,
+		G_PRIORITY_DEFAULT, cancellable);
 
-	return res;
+	g_object_unref (simple);
 }
 
 /**
  * e_cal_client_get_view_finish:
  * @client: an #ECalClient
  * @result: a #GAsyncResult
- * @view: (out) an #ECalClientView
+ * @out_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,
+ * If successful, then the @out_view is set to newly allocated #ECalClientView,
  * which should be freed with g_object_unref().
  *
  * Returns: %TRUE if successful, %FALSE otherwise.
@@ -4848,29 +5889,41 @@ complete_get_view (ECalClient *client,
 gboolean
 e_cal_client_get_view_finish (ECalClient *client,
                               GAsyncResult *result,
-                              ECalClientView **view,
+                              ECalClientView **out_view,
                               GError **error)
 {
-	gboolean res;
-	gchar *view_path = NULL;
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (client),
+		e_cal_client_get_view), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	if (g_simple_async_result_propagate_error (simple, error))
+		return FALSE;
 
-	g_return_val_if_fail (view != NULL, FALSE);
+	g_return_val_if_fail (async_context->client_view != NULL, FALSE);
 
-	res = e_client_proxy_call_finish_string (E_CLIENT (client), result, &view_path, error, e_cal_client_get_view);
+	if (out_view != NULL)
+		*out_view = g_object_ref (async_context->client_view);
 
-	return complete_get_view (client, res, view_path, view, error);
+	return TRUE;
 }
 
 /**
  * e_cal_client_get_view_sync:
  * @client: an #ECalClient
  * @sexp: an S-expression representing the query.
- * @view: (out) an #ECalClientView
+ * @out_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,
+ * If successful, then the @out_view is set to newly allocated #ECalClientView,
  * which should be freed with g_object_unref().
  *
  * Returns: %TRUE if successful, %FALSE otherwise.
@@ -4880,54 +5933,84 @@ e_cal_client_get_view_finish (ECalClient *client,
 gboolean
 e_cal_client_get_view_sync (ECalClient *client,
                             const gchar *sexp,
-                            ECalClientView **view,
+                            ECalClientView **out_view,
                             GCancellable *cancellable,
                             GError **error)
 {
-	gboolean res;
-	gchar *gdbus_sexp = NULL;
-	gchar *view_path = NULL;
+	gchar *utf8_sexp;
+	gchar *object_path = NULL;
+	gboolean success;
 
 	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
 	g_return_val_if_fail (sexp != NULL, FALSE);
-	g_return_val_if_fail (view != NULL, FALSE);
+	g_return_val_if_fail (out_view != NULL, FALSE);
 
 	if (client->priv->dbus_proxy == NULL) {
 		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);
+	utf8_sexp = e_util_utf8_make_valid (sexp);
 
-	g_free (gdbus_sexp);
+	success = e_dbus_calendar_call_get_view_sync (
+		client->priv->dbus_proxy, utf8_sexp,
+		&object_path, cancellable, error);
 
-	return complete_get_view (client, res, view_path, view, error);
-}
+	g_free (utf8_sexp);
 
-static gboolean
-cal_client_get_timezone_from_cache_finish (ECalClient *client,
-                                           GAsyncResult *result,
-                                           icaltimezone **zone,
-                                           GError **error)
-{
-	GSimpleAsyncResult *simple;
-	GError *local_error = NULL;
+	/* Sanity check. */
+	g_return_val_if_fail (
+		(success && (object_path != NULL)) ||
+		(!success && (object_path == 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), e_timezone_cache_get_timezone), FALSE);
+	if (object_path != NULL) {
+		GDBusConnection *connection;
+		ECalClientView *client_view;
 
-	simple = G_SIMPLE_ASYNC_RESULT (result);
+		connection = g_dbus_proxy_get_connection (
+			G_DBUS_PROXY (client->priv->dbus_proxy));
 
-	if (g_simple_async_result_propagate_error (simple, &local_error)) {
-		e_client_unwrap_dbus_error (E_CLIENT (client), local_error, error);
-		return FALSE;
+		client_view = g_initable_new (
+			E_TYPE_CAL_CLIENT_VIEW,
+			cancellable, error,
+			"client", client,
+			"connection", connection,
+			"object-path", object_path,
+			NULL);
+
+		/* XXX Would have been easier to return the
+		 *     EBookClientView directly rather than
+		 *     through an "out" parameter. */
+		if (client_view != NULL)
+			*out_view = client_view;
+		else
+			success = FALSE;
+
+		g_free (object_path);
 	}
 
-	*zone = g_simple_async_result_get_op_res_gpointer (simple);
+	return success;
+}
+
+/* Helper for e_cal_client_get_timezone() */
+static void
+cal_client_get_timezone_thread (GSimpleAsyncResult *simple,
+                                GObject *source_object,
+                                GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
+
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	e_cal_client_get_timezone_sync (
+		E_CAL_CLIENT (source_object),
+		async_context->tzid,
+		&async_context->zone,
+		cancellable, &error);
 
-	return *zone != NULL;
+	if (error != NULL)
+		g_simple_async_result_take_error (simple, error);
 }
 
 /**
@@ -4951,83 +6034,40 @@ e_cal_client_get_timezone (ECalClient *client,
                            GAsyncReadyCallback callback,
                            gpointer user_data)
 {
-	gchar *gdbus_tzid = NULL;
-	icaltimezone *zone;
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
 
+	g_return_if_fail (E_IS_CAL_CLIENT (client));
 	g_return_if_fail (tzid != NULL);
 
-	zone = e_timezone_cache_get_timezone (
-		E_TIMEZONE_CACHE (client), tzid);
-	if (zone) {
-		e_client_finish_async_without_dbus (E_CLIENT (client), cancellable, callback, user_data, e_timezone_cache_get_timezone, zone, NULL);
-	} 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);
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->tzid = g_strdup (tzid);
 
-	*zone = NULL;
+	simple = g_simple_async_result_new (
+		G_OBJECT (client), callback, user_data,
+		e_cal_client_get_timezone);
 
-	if (res && out_string) {
-		icalcomponent *icalcomp;
+	g_simple_async_result_set_check_cancellable (simple, cancellable);
 
-		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_propagate_error (error, e_cal_client_error_create (E_CAL_CLIENT_ERROR_INVALID_OBJECT, NULL));
-			} else {
-				const gchar *tzid;
-
-				tzid = icaltimezone_get_tzid (*zone);
-
-				/* Add the timezone to the cache directly,
-				 * otherwise we'd have to free this struct
-				 * and fetch the cached copy. */
-				g_mutex_lock (&client->priv->zone_cache_lock);
-				g_hash_table_insert (
-					client->priv->zone_cache,
-					g_strdup (tzid), *zone);
-				g_mutex_unlock (&client->priv->zone_cache_lock);
-			}
-		} else {
-			res = FALSE;
-			g_propagate_error (error, e_cal_client_error_create (E_CAL_CLIENT_ERROR_INVALID_OBJECT, NULL));
-		}
-	} else {
-		res = FALSE;
-	}
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
 
-	g_free (out_string);
+	g_simple_async_result_run_in_thread (
+		simple, cal_client_get_timezone_thread,
+		G_PRIORITY_DEFAULT, cancellable);
 
-	return res;
+	g_object_unref (simple);
 }
 
 /**
  * e_cal_client_get_timezone_finish:
  * @client: an #ECalClient
  * @result: a #GAsyncResult
- * @zone: (out): Return value for the timezone
+ * @out_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.
+ * sets @out_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.
@@ -5037,29 +6077,38 @@ complete_get_timezone (ECalClient *client,
 gboolean
 e_cal_client_get_timezone_finish (ECalClient *client,
                                   GAsyncResult *result,
-                                  icaltimezone **zone,
+                                  icaltimezone **out_zone,
                                   GError **error)
 {
-	gboolean res;
-	gchar *out_string = NULL;
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
 
-	g_return_val_if_fail (zone != NULL, FALSE);
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (client),
+		e_cal_client_get_timezone), FALSE);
 
-	if (g_simple_async_result_get_source_tag (G_SIMPLE_ASYNC_RESULT (result)) == e_timezone_cache_get_timezone) {
-		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);
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
+
+	if (g_simple_async_result_propagate_error (simple, error))
+		return FALSE;
+
+	g_return_val_if_fail (async_context->zone != NULL, FALSE);
+
+	if (out_zone != NULL) {
+		*out_zone = async_context->zone;
+		async_context->zone = NULL;
 	}
 
-	return res;
+	return TRUE;
 }
 
 /**
  * e_cal_client_get_timezone_sync:
  * @client: an #ECalClient
  * @tzid: ID of the timezone to retrieve
- * @zone: (out): Return value for the timezone
+ * @out_zone: (out): Return value for the timezone
  * @cancellable: a #GCancellable; can be %NULL
  * @error: (out): a #GError to set an error, if any
  *
@@ -5073,32 +6122,100 @@ e_cal_client_get_timezone_finish (ECalClient *client,
 gboolean
 e_cal_client_get_timezone_sync (ECalClient *client,
                                 const gchar *tzid,
-                                icaltimezone **zone,
+                                icaltimezone **out_zone,
                                 GCancellable *cancellable,
                                 GError **error)
 {
-	gboolean res;
-	gchar *gdbus_tzid = NULL, *out_string = NULL;
+	icalcomponent *icalcomp;
+	icaltimezone *zone;
+	gchar *utf8_tzid;
+	gchar *string = NULL;
+	gboolean success;
 
 	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
 	g_return_val_if_fail (tzid != NULL, FALSE);
-	g_return_val_if_fail (zone != NULL, FALSE);
+	g_return_val_if_fail (out_zone != NULL, FALSE);
 
 	if (client->priv->dbus_proxy == NULL) {
 		set_proxy_gone_error (error);
 		return FALSE;
 	}
 
-	*zone = e_timezone_cache_get_timezone (
+	zone = e_timezone_cache_get_timezone (
 		E_TIMEZONE_CACHE (client), tzid);
-	if (*zone)
+	if (zone != NULL) {
+		*out_zone = zone;
 		return TRUE;
+	}
+
+	utf8_tzid = e_util_utf8_make_valid (tzid);
+
+	success = e_dbus_calendar_call_get_timezone_sync (
+		client->priv->dbus_proxy, utf8_tzid,
+		&string, cancellable, error);
+
+	g_free (utf8_tzid);
+
+	/* Sanity check. */
+	g_return_val_if_fail (
+		(success && (string != NULL)) ||
+		(!success && (string == NULL)), FALSE);
+
+	if (!success)
+		return FALSE;
+
+	icalcomp = icalparser_parse_string (string);
+
+	g_free (string);
+
+	if (icalcomp == NULL) {
+		g_propagate_error (
+			error, e_cal_client_error_create (
+			E_CAL_CLIENT_ERROR_INVALID_OBJECT, NULL));
+		return FALSE;
+	}
+
+	zone = icaltimezone_new ();
+	if (!icaltimezone_set_component (zone, icalcomp)) {
+		g_propagate_error (
+			error, e_cal_client_error_create (
+			E_CAL_CLIENT_ERROR_INVALID_OBJECT, NULL));
+		icalcomponent_free (icalcomp);
+		icaltimezone_free (zone, 1);
+		return FALSE;
+	}
+
+	/* Add the timezone to the cache directly,
+	 * otherwise we'd have to free this struct
+	 * and fetch the cached copy. */
+	g_mutex_lock (&client->priv->zone_cache_lock);
+	g_hash_table_insert (
+		client->priv->zone_cache, g_strdup (tzid), zone);
+	g_mutex_unlock (&client->priv->zone_cache_lock);
+
+	*out_zone = zone;
+
+	return TRUE;
+}
+
+/* Helper for e_cal_client_add_timezone() */
+static void
+cal_client_add_timezone_thread (GSimpleAsyncResult *simple,
+                                GObject *source_object,
+                                GCancellable *cancellable)
+{
+	AsyncContext *async_context;
+	GError *error = NULL;
 
-	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);
+	async_context = g_simple_async_result_get_op_res_gpointer (simple);
 
-	g_free (gdbus_tzid);
+	e_cal_client_add_timezone_sync (
+		E_CAL_CLIENT (source_object),
+		async_context->zone,
+		cancellable, &error);
 
-	return complete_get_timezone (client, res, out_string, zone, error);
+	if (error != NULL)
+		g_simple_async_result_take_error (simple, error);
 }
 
 /**
@@ -5117,31 +6234,44 @@ e_cal_client_get_timezone_sync (ECalClient *client,
  **/
 void
 e_cal_client_add_timezone (ECalClient *client,
-                           /* const */ icaltimezone *zone,
+                           icaltimezone *zone,
                            GCancellable *cancellable,
                            GAsyncReadyCallback callback,
                            gpointer user_data)
 {
+	GSimpleAsyncResult *simple;
+	AsyncContext *async_context;
 	icalcomponent *icalcomp;
-	gchar *zone_str, *gdbus_zone = NULL;
 
+	g_return_if_fail (E_IS_CAL_CLIENT (client));
 	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);
+	async_context = g_slice_new0 (AsyncContext);
+	async_context->zone = icaltimezone_new ();
+
+	icalcomp = icalcomponent_new_clone (icalcomp);
+	icaltimezone_set_component (async_context->zone, 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);
+	simple = g_simple_async_result_new (
+		G_OBJECT (client), callback, user_data,
+		e_cal_client_add_timezone);
 
-	g_free (zone_str);
-	g_free (gdbus_zone);
+	g_simple_async_result_set_check_cancellable (simple, cancellable);
+
+	g_simple_async_result_set_op_res_gpointer (
+		simple, async_context, (GDestroyNotify) async_context_free);
+
+	if (zone == icaltimezone_get_utc_timezone ())
+		g_simple_async_result_complete_in_idle (simple);
+	else
+		g_simple_async_result_run_in_thread (
+			simple, cal_client_add_timezone_thread,
+			G_PRIORITY_DEFAULT, cancellable);
+
+	g_object_unref (simple);
 }
 
 /**
@@ -5161,7 +6291,17 @@ 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);
+	GSimpleAsyncResult *simple;
+
+	g_return_val_if_fail (
+		g_simple_async_result_is_valid (
+		result, G_OBJECT (client),
+		e_cal_client_add_timezone), FALSE);
+
+	simple = G_SIMPLE_ASYNC_RESULT (result);
+
+	/* Assume success unless a GError is set. */
+	return !g_simple_async_result_propagate_error (simple, error);
 }
 
 /**
@@ -5179,13 +6319,14 @@ e_cal_client_add_timezone_finish (ECalClient *client,
  **/
 gboolean
 e_cal_client_add_timezone_sync (ECalClient *client,
-                                /* const */ icaltimezone *zone,
+                                icaltimezone *zone,
                                 GCancellable *cancellable,
                                 GError **error)
 {
-	gboolean res;
 	icalcomponent *icalcomp;
-	gchar *zone_str, *gdbus_zone = NULL;
+	gchar *zone_str;
+	gchar *utf8_zone_str;
+	gboolean success;
 
 	g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
 	g_return_val_if_fail (zone != NULL, FALSE);
@@ -5194,8 +6335,10 @@ e_cal_client_add_timezone_sync (ECalClient *client,
 		return TRUE;
 
 	icalcomp = icaltimezone_get_component (zone);
-	if (!icalcomp) {
-		g_propagate_error (error, e_client_error_create (E_CLIENT_ERROR_INVALID_ARG, NULL));
+	if (icalcomp == NULL) {
+		g_propagate_error (
+			error, e_client_error_create (
+			E_CLIENT_ERROR_INVALID_ARG, NULL));
 		return FALSE;
 	}
 
@@ -5205,12 +6348,14 @@ e_cal_client_add_timezone_sync (ECalClient *client,
 	}
 
 	zone_str = icalcomponent_as_ical_string_r (icalcomp);
+	utf8_zone_str = e_util_utf8_make_valid (zone_str);
 
-	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);
+	success = e_dbus_calendar_call_add_timezone_sync (
+		client->priv->dbus_proxy, utf8_zone_str, cancellable, error);
 
 	g_free (zone_str);
-	g_free (gdbus_zone);
+	g_free (utf8_zone_str);
 
-	return res;
+	return success;
 }
 
diff --git a/calendar/libecal/e-cal-client.h b/calendar/libecal/e-cal-client.h
index 8c02e7f..731c695 100644
--- a/calendar/libecal/e-cal-client.h
+++ b/calendar/libecal/e-cal-client.h
@@ -207,11 +207,11 @@ void		e_cal_client_get_default_object	(ECalClient *client,
 gboolean	e_cal_client_get_default_object_finish
 						(ECalClient *client,
 						 GAsyncResult *result,
-						 icalcomponent **icalcomp,
+						 icalcomponent **out_icalcomp,
 						 GError **error);
 gboolean	e_cal_client_get_default_object_sync
 						(ECalClient *client,
-						 icalcomponent **icalcomp,
+						 icalcomponent **out_icalcomp,
 						 GCancellable *cancellable,
 						 GError **error);
 void		e_cal_client_get_object		(ECalClient *client,
@@ -222,12 +222,12 @@ void		e_cal_client_get_object		(ECalClient *client,
 						 gpointer user_data);
 gboolean	e_cal_client_get_object_finish	(ECalClient *client,
 						 GAsyncResult *result,
-						 icalcomponent **icalcomp,
+						 icalcomponent **out_icalcomp,
 						 GError **error);
 gboolean	e_cal_client_get_object_sync	(ECalClient *client,
 						 const gchar *uid,
 						 const gchar *rid,
-						 icalcomponent **icalcomp,
+						 icalcomponent **out_icalcomp,
 						 GCancellable *cancellable,
 						 GError **error);
 void		e_cal_client_get_objects_for_uid
@@ -239,12 +239,12 @@ void		e_cal_client_get_objects_for_uid
 gboolean	e_cal_client_get_objects_for_uid_finish
 						(ECalClient *client,
 						 GAsyncResult *result,
-						 GSList **ecalcomps,
+						 GSList **out_ecalcomps,
 						 GError **error);
 gboolean	e_cal_client_get_objects_for_uid_sync
 						(ECalClient *client,
 						 const gchar *uid,
-						 GSList **ecalcomps,
+						 GSList **out_ecalcomps,
 						 GCancellable *cancellable,
 						 GError **error);
 void		e_cal_client_get_object_list	(ECalClient *client,
@@ -255,12 +255,12 @@ void		e_cal_client_get_object_list	(ECalClient *client,
 gboolean	e_cal_client_get_object_list_finish
 						(ECalClient *client,
 						 GAsyncResult *result,
-						 GSList **icalcomps,
+						 GSList **out_icalcomps,
 						 GError **error);
 gboolean	e_cal_client_get_object_list_sync
 						(ECalClient *client,
 						 const gchar *sexp,
-						 GSList **icalcomps,
+						 GSList **out_icalcomps,
 						 GCancellable *cancellable,
 						 GError **error);
 void		e_cal_client_get_object_list_as_comps
@@ -272,12 +272,12 @@ void		e_cal_client_get_object_list_as_comps
 gboolean	e_cal_client_get_object_list_as_comps_finish
 						(ECalClient *client,
 						 GAsyncResult *result,
-						 GSList **ecalcomps,
+						 GSList **out_ecalcomps,
 						 GError **error);
 gboolean	e_cal_client_get_object_list_as_comps_sync
 						(ECalClient *client,
 						 const gchar *sexp,
-						 GSList **ecalcomps,
+						 GSList **out_ecalcomps,
 						 GCancellable *cancellable,
 						 GError **error);
 void		e_cal_client_get_free_busy	(ECalClient *client,
@@ -305,11 +305,11 @@ void		e_cal_client_create_object	(ECalClient *client,
 gboolean	e_cal_client_create_object_finish
 						(ECalClient *client,
 						 GAsyncResult *result,
-						 gchar **uid,
+						 gchar **out_uid,
 						 GError **error);
 gboolean	e_cal_client_create_object_sync	(ECalClient *client,
 						 icalcomponent *icalcomp,
-						 gchar **uid,
+						 gchar **out_uid,
 						 GCancellable *cancellable,
 						 GError **error);
 void		e_cal_client_create_objects	(ECalClient *client,
@@ -320,12 +320,12 @@ void		e_cal_client_create_objects	(ECalClient *client,
 gboolean	e_cal_client_create_objects_finish
 						(ECalClient *client,
 						 GAsyncResult *result,
-						 GSList **uids,
+						 GSList **out_uids,
 						 GError **error);
 gboolean	e_cal_client_create_objects_sync
 						(ECalClient *client,
 						 GSList *icalcomps,
-						 GSList **uids,
+						 GSList **out_uids,
 						 GCancellable *cancellable,
 						 GError **error);
 void		e_cal_client_modify_object	(ECalClient *client,
@@ -414,13 +414,13 @@ void		e_cal_client_send_objects	(ECalClient *client,
 gboolean	e_cal_client_send_objects_finish
 						(ECalClient *client,
 						 GAsyncResult *result,
-						 GSList **users,
-						 icalcomponent **modified_icalcomp,
+						 GSList **out_users,
+						 icalcomponent **out_modified_icalcomp,
 						 GError **error);
 gboolean	e_cal_client_send_objects_sync	(ECalClient *client,
 						 icalcomponent *icalcomp,
-						 GSList **users,
-						 icalcomponent **modified_icalcomp,
+						 GSList **out_users,
+						 icalcomponent **out_modified_icalcomp,
 						 GCancellable *cancellable,
 						 GError **error);
 void		e_cal_client_get_attachment_uris
@@ -433,13 +433,13 @@ void		e_cal_client_get_attachment_uris
 gboolean	e_cal_client_get_attachment_uris_finish
 						(ECalClient *client,
 						 GAsyncResult *result,
-						 GSList **attachment_uris,
+						 GSList **out_attachment_uris,
 						 GError **error);
 gboolean	e_cal_client_get_attachment_uris_sync
 						(ECalClient *client,
 						 const gchar *uid,
 						 const gchar *rid,
-						 GSList **attachment_uris,
+						 GSList **out_attachment_uris,
 						 GCancellable *cancellable,
 						 GError **error);
 void		e_cal_client_discard_alarm	(ECalClient *client,
@@ -466,11 +466,11 @@ void		e_cal_client_get_view		(ECalClient *client,
 						 gpointer user_data);
 gboolean	e_cal_client_get_view_finish	(ECalClient *client,
 						 GAsyncResult *result,
-						 ECalClientView **view,
+						 ECalClientView **out_view,
 						 GError **error);
 gboolean	e_cal_client_get_view_sync	(ECalClient *client,
 						 const gchar *sexp,
-						 ECalClientView **view,
+						 ECalClientView **out_view,
 						 GCancellable *cancellable,
 						 GError **error);
 void		e_cal_client_get_timezone	(ECalClient *client,
@@ -481,11 +481,11 @@ void		e_cal_client_get_timezone	(ECalClient *client,
 gboolean	e_cal_client_get_timezone_finish
 						(ECalClient *client,
 						 GAsyncResult *result,
-						 icaltimezone **zone,
+						 icaltimezone **out_zone,
 						 GError **error);
 gboolean	e_cal_client_get_timezone_sync	(ECalClient *client,
 						 const gchar *tzid,
-						 icaltimezone **zone,
+						 icaltimezone **out_zone,
 						 GCancellable *cancellable,
 						 GError **error);
 void		e_cal_client_add_timezone	(ECalClient *client,
diff --git a/calendar/libedata-cal/e-cal-backend.c b/calendar/libedata-cal/e-cal-backend.c
index a2ce503..dba3098 100644
--- a/calendar/libedata-cal/e-cal-backend.c
+++ b/calendar/libedata-cal/e-cal-backend.c
@@ -147,6 +147,8 @@ cal_backend_get_backend_property (ECalBackend *backend,
 		e_data_cal_respond_get_backend_property (cal, opid, NULL, "TRUE");
 	} else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_OPENING)) {
 		e_data_cal_respond_get_backend_property (cal, opid, NULL, "FALSE");
+	} else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_REVISION)) {
+		e_data_cal_respond_get_backend_property (cal, opid, NULL, "0");
 	} else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_ONLINE)) {
 		e_data_cal_respond_get_backend_property (cal, opid, NULL, e_backend_get_online (E_BACKEND (backend)) ? "TRUE" : "FALSE");
 	} else if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_READONLY)) {
@@ -1158,17 +1160,8 @@ e_cal_backend_open (ECalBackend *backend,
 	g_mutex_lock (&backend->priv->clients_mutex);
 
 	if (e_cal_backend_is_opened (backend)) {
-		gboolean online;
-		gboolean writable;
-
 		g_mutex_unlock (&backend->priv->clients_mutex);
 
-		online = e_backend_get_online (E_BACKEND (backend));
-		writable = e_cal_backend_get_writable (backend);
-
-		e_data_cal_report_online (cal, online);
-		e_data_cal_report_readonly (cal, !writable);
-
 		e_data_cal_respond_open (cal, opid, NULL);
 	} else {
 		g_mutex_unlock (&backend->priv->clients_mutex);
@@ -1840,28 +1833,16 @@ e_cal_backend_notify_error (ECalBackend *backend,
  *
  * Notifies all backend's clients about the current readonly state.
  * Meant to be used by backend implementations.
+ *
+ * Deprecated: 3.8: Use e_cal_backend_set_writable() instead.
  **/
 void
 e_cal_backend_notify_readonly (ECalBackend *backend,
                                gboolean is_readonly)
 {
-	ECalBackendPrivate *priv;
-	GList *l;
+	g_return_if_fail (E_IS_CAL_BACKEND (backend));
 
-	priv = backend->priv;
 	e_cal_backend_set_writable (backend, !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);
 }
 
 /**
@@ -1873,27 +1854,16 @@ e_cal_backend_notify_readonly (ECalBackend *backend,
  * Meant to be used by backend implementations.
  *
  * Since: 3.2
+ *
+ * Deprecated: 3.8: Use e_backend_set_online() instead.
  **/
 void
 e_cal_backend_notify_online (ECalBackend *backend,
                              gboolean is_online)
 {
-	ECalBackendPrivate *priv;
-	GList *clients;
-
-	priv = backend->priv;
-
-	if (priv->notification_proxy) {
-		e_cal_backend_notify_online (priv->notification_proxy, is_online);
-		return;
-	}
-
-	g_mutex_lock (&priv->clients_mutex);
-
-	for (clients = priv->clients; clients != NULL; clients = g_list_next (clients))
-		e_data_cal_report_online (E_DATA_CAL (clients->data), is_online);
+	g_return_if_fail (E_IS_CAL_BACKEND (backend));
 
-	g_mutex_unlock (&priv->clients_mutex);
+	e_backend_set_online (E_BACKEND (backend), is_online);
 }
 
 /**
diff --git a/calendar/libedata-cal/e-cal-backend.h b/calendar/libedata-cal/e-cal-backend.h
index 507e08f..ccd3d99 100644
--- a/calendar/libedata-cal/e-cal-backend.h
+++ b/calendar/libedata-cal/e-cal-backend.h
@@ -382,10 +382,6 @@ void		e_cal_backend_notify_component_removed
 
 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_property_changed
 						(ECalBackend *backend,
 						 const gchar *prop_name,
@@ -437,6 +433,10 @@ void		e_cal_backend_foreach_view	(ECalBackend *backend,
 								       gpointer user_data);
 void		e_cal_backend_notify_opened	(ECalBackend *backend,
 						 GError *error);
+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_respond_opened	(ECalBackend *backend,
 						 EDataCal *cal,
 						 guint32 opid,
diff --git a/calendar/libedata-cal/e-data-cal.c b/calendar/libedata-cal/e-data-cal.c
index 3ed1b84..0bb0672 100644
--- a/calendar/libedata-cal/e-data-cal.c
+++ b/calendar/libedata-cal/e-data-cal.c
@@ -30,10 +30,12 @@
 #include <glib/gi18n-lib.h>
 #include <unistd.h>
 
+/* Private D-Bus classes. */
+#include <e-dbus-calendar.h>
+
 #include <libedataserver/libedataserver.h>
 
 #include "e-data-cal.h"
-#include "e-gdbus-cal.h"
 #include "e-cal-backend.h"
 #include "e-cal-backend-sexp.h"
 
@@ -46,7 +48,7 @@
 
 struct _EDataCalPrivate {
 	GDBusConnection *connection;
-	EGdbusCal *dbus_interface;
+	EDBusCalendar *dbus_interface;
 	ECalBackend *backend;
 	gchar *object_path;
 
@@ -100,8 +102,6 @@ typedef struct {
 	guint watcher_id;
 
 	union {
-		/* OP_OPEN */
-		gboolean only_if_exists;
 		/* OP_GET_OBJECT */
 		/* OP_GET_ATTACHMENT_URIS */
 		struct _ur {
@@ -144,7 +144,7 @@ typedef struct {
 		/* OP_ADD_TIMEZONE */
 		gchar *tzobject;
 		/* OP_GET_BACKEND_PROPERTY */
-		gchar *prop_name;
+		const gchar *prop_name;
 
 		/* OP_REFRESH */
 		/* OP_CLOSE */
@@ -203,6 +203,7 @@ op_new (OperationID op,
 	data->cal = g_object_ref (cal);
 	data->cancellable = g_cancellable_new ();
 
+	/* This is optional so we can fake client requests. */
 	if (invocation != NULL) {
 		GDBusConnection *connection;
 		const gchar *sender;
@@ -284,9 +285,6 @@ op_unref (OperationData *data)
 			case OP_ADD_TIMEZONE:
 				g_free (data->d.tzobject);
 				break;
-			case OP_GET_BACKEND_PROPERTY:
-				g_free (data->d.prop_name);
-				break;
 			default:
 				break;
 		}
@@ -323,11 +321,36 @@ op_dispatch (EDataCal *cal,
 	g_mutex_unlock (&cal->priv->open_lock);
 }
 
+static OperationData *
+op_claim (EDataCal *cal,
+          guint32 opid)
+{
+	OperationData *data;
+
+	g_return_val_if_fail (E_IS_DATA_CAL (cal), NULL);
+
+	e_operation_pool_release_opid (ops_pool, opid);
+
+	g_rec_mutex_lock (&cal->priv->pending_ops_lock);
+	data = g_hash_table_lookup (
+		cal->priv->pending_ops,
+		GUINT_TO_POINTER (opid));
+	if (data != NULL) {
+		/* Steal the hash table's reference. */
+		g_hash_table_steal (
+			cal->priv->pending_ops,
+			GUINT_TO_POINTER (opid));
+	}
+	g_rec_mutex_unlock (&cal->priv->pending_ops_lock);
+
+	return data;
+}
+
 static void
 op_complete (EDataCal *cal,
              guint32 opid)
 {
-	g_return_if_fail (cal != NULL);
+	g_return_if_fail (E_IS_DATA_CAL (cal));
 
 	e_operation_pool_release_opid (ops_pool, opid);
 
@@ -339,11 +362,137 @@ op_complete (EDataCal *cal,
 }
 
 static void
+data_cal_convert_to_client_error (GError *error)
+{
+	g_return_if_fail (error != NULL);
+
+	if (error->domain != E_DATA_CAL_ERROR)
+		return;
+
+	switch (error->code) {
+		case RepositoryOffline:
+			error->domain = E_CLIENT_ERROR;
+			error->code = E_CLIENT_ERROR_REPOSITORY_OFFLINE;
+			break;
+
+		case PermissionDenied:
+			error->domain = E_CLIENT_ERROR;
+			error->code = E_CLIENT_ERROR_PERMISSION_DENIED;
+			break;
+
+		case InvalidRange:
+			error->domain = E_CAL_CLIENT_ERROR;
+			error->code = E_CAL_CLIENT_ERROR_INVALID_RANGE;
+			break;
+
+		case ObjectNotFound:
+			error->domain = E_CAL_CLIENT_ERROR;
+			error->code = E_CAL_CLIENT_ERROR_OBJECT_NOT_FOUND;
+			break;
+
+		case InvalidObject:
+			error->domain = E_CAL_CLIENT_ERROR;
+			error->code = E_CAL_CLIENT_ERROR_INVALID_OBJECT;
+			break;
+
+		case ObjectIdAlreadyExists:
+			error->domain = E_CAL_CLIENT_ERROR;
+			error->code = E_CAL_CLIENT_ERROR_OBJECT_ID_ALREADY_EXISTS;
+			break;
+
+		case AuthenticationFailed:
+			error->domain = E_CLIENT_ERROR;
+			error->code = E_CLIENT_ERROR_AUTHENTICATION_FAILED;
+			break;
+
+		case AuthenticationRequired:
+			error->domain = E_CLIENT_ERROR;
+			error->code = E_CLIENT_ERROR_AUTHENTICATION_REQUIRED;
+			break;
+
+		case UnsupportedAuthenticationMethod:
+			error->domain = E_CLIENT_ERROR;
+			error->code = E_CLIENT_ERROR_UNSUPPORTED_AUTHENTICATION_METHOD;
+			break;
+
+		case TLSNotAvailable:
+			error->domain = E_CLIENT_ERROR;
+			error->code = E_CLIENT_ERROR_TLS_NOT_AVAILABLE;
+			break;
+
+		case NoSuchCal:
+			error->domain = E_CAL_CLIENT_ERROR;
+			error->code = E_CAL_CLIENT_ERROR_NO_SUCH_CALENDAR;
+			break;
+
+		case UnknownUser:
+			error->domain = E_CAL_CLIENT_ERROR;
+			error->code = E_CAL_CLIENT_ERROR_UNKNOWN_USER;
+			break;
+
+		case OfflineUnavailable:
+			error->domain = E_CLIENT_ERROR;
+			error->code = E_CLIENT_ERROR_OFFLINE_UNAVAILABLE;
+			break;
+
+		case SearchSizeLimitExceeded:
+			error->domain = E_CLIENT_ERROR;
+			error->code = E_CLIENT_ERROR_SEARCH_SIZE_LIMIT_EXCEEDED;
+			break;
+
+		case SearchTimeLimitExceeded:
+			error->domain = E_CLIENT_ERROR;
+			error->code = E_CLIENT_ERROR_SEARCH_TIME_LIMIT_EXCEEDED;
+			break;
+
+		case InvalidQuery:
+			error->domain = E_CLIENT_ERROR;
+			error->code = E_CLIENT_ERROR_INVALID_QUERY;
+			break;
+
+		case QueryRefused:
+			error->domain = E_CLIENT_ERROR;
+			error->code = E_CLIENT_ERROR_QUERY_REFUSED;
+			break;
+
+		case CouldNotCancel:
+			error->domain = E_CLIENT_ERROR;
+			error->code = E_CLIENT_ERROR_COULD_NOT_CANCEL;
+			break;
+
+		case InvalidArg:
+			error->domain = E_CLIENT_ERROR;
+			error->code = E_CLIENT_ERROR_INVALID_ARG;
+			break;
+
+		case NotSupported:
+			error->domain = E_CLIENT_ERROR;
+			error->code = E_CLIENT_ERROR_NOT_SUPPORTED;
+			break;
+
+		case NotOpened:
+			error->domain = E_CLIENT_ERROR;
+			error->code = E_CLIENT_ERROR_NOT_OPENED;
+			break;
+
+		case UnsupportedField:
+		case UnsupportedMethod:
+		case OtherError:
+		case InvalidServerVersion:
+			error->domain = E_CLIENT_ERROR;
+			error->code = E_CLIENT_ERROR_OTHER_ERROR;
+			break;
+
+		default:
+			g_warn_if_reached ();
+	}
+}
+
+static void
 operation_thread (gpointer data,
                   gpointer user_data)
 {
 	OperationData *op = data;
-	OperationData *cancel_op;
 	ECalBackend *backend;
 	GHashTableIter iter;
 	gpointer value;
@@ -354,7 +503,7 @@ operation_thread (gpointer data,
 	case OP_OPEN:
 		e_cal_backend_open (
 			backend, op->cal, op->id,
-			op->cancellable, op->d.only_if_exists);
+			op->cancellable, FALSE);
 		break;
 
 	case OP_REFRESH:
@@ -456,8 +605,13 @@ operation_thread (gpointer data,
 
 			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);
+				g_dbus_method_invocation_return_error_literal (
+					op->invocation,
+					E_CLIENT_ERROR,
+					E_CLIENT_ERROR_INVALID_QUERY,
+					_("Invalid query"));
+
+				op_complete (op->cal, op->id);
 				break;
 			}
 
@@ -476,17 +630,26 @@ operation_thread (gpointer data,
 				((view == NULL) && (error != NULL)));
 
 			if (error != NULL) {
-				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);
+				/* Translators: This is a prefix to a detailed error message *
+ */
+				g_prefix_error (&error, "%s", _("Invalid query: "));
+				data_cal_convert_to_client_error (error);
+				g_dbus_method_invocation_take_error (
+					op->invocation, error);
+
+				op_complete (op->cal, op->id);
 				g_free (object_path);
 				break;
 			}
 
 			e_cal_backend_add_view (backend, view);
 
-			e_data_cal_respond_get_view (op->cal, op->id, EDC_ERROR (Success), object_path);
+			e_dbus_calendar_complete_get_view (
+				op->cal->priv->dbus_interface,
+				op->invocation,
+				object_path);
 
+			op_complete (op->cal, op->id);
 			g_free (object_path);
 		}
 		break;
@@ -511,11 +674,17 @@ operation_thread (gpointer data,
 
 		g_hash_table_iter_init (&iter, op->cal->priv->pending_ops);
 		while (g_hash_table_iter_next (&iter, NULL, &value)) {
-			cancel_op = (OperationData *) value;
+			OperationData *cancel_op = value;
 			g_cancellable_cancel (cancel_op->cancellable);
 		}
 
 		g_rec_mutex_unlock (&op->cal->priv->pending_ops_lock);
+
+		e_dbus_calendar_complete_close (
+			op->cal->priv->dbus_interface,
+			op->invocation);
+
+		op_complete (op->cal, op->id);
 		break;
 	}
 
@@ -672,17 +841,13 @@ e_data_cal_create_error_fmt (EDataCalCallStatus status,
 }
 
 static gboolean
-data_cal_handle_open_cb (EGdbusCal *interface,
+data_cal_handle_open_cb (EDBusCalendar *interface,
                          GDBusMethodInvocation *invocation,
-                         gboolean in_only_if_exists,
                          EDataCal *cal)
 {
 	OperationData *op;
 
 	op = op_new (OP_OPEN, cal, invocation);
-	op->d.only_if_exists = in_only_if_exists;
-
-	e_gdbus_cal_complete_open (interface, invocation, op->id);
 
 	op_dispatch (cal, op);
 
@@ -690,7 +855,7 @@ data_cal_handle_open_cb (EGdbusCal *interface,
 }
 
 static gboolean
-data_cal_handle_refresh_cb (EGdbusCal *interface,
+data_cal_handle_refresh_cb (EDBusCalendar *interface,
                             GDBusMethodInvocation *invocation,
                             EDataCal *cal)
 {
@@ -698,44 +863,28 @@ data_cal_handle_refresh_cb (EGdbusCal *interface,
 
 	op = op_new (OP_REFRESH, cal, invocation);
 
-	e_gdbus_cal_complete_refresh (interface, invocation, op->id);
-
 	op_dispatch (cal, op);
 
 	return TRUE;
 }
 
 static gboolean
-data_cal_handle_get_backend_property_cb (EGdbusCal *interface,
-                                         GDBusMethodInvocation *invocation,
-                                         const gchar *in_prop_name,
-                                         EDataCal *cal)
-{
-	OperationData *op;
-
-	op = op_new (OP_GET_BACKEND_PROPERTY, cal, invocation);
-	op->d.prop_name = g_strdup (in_prop_name);
-
-	e_gdbus_cal_complete_get_backend_property (interface, invocation, op->id);
-
-	/* This operation is never queued. */
-	e_operation_pool_push (ops_pool, op);
-
-	return TRUE;
-}
-
-static gboolean
-data_cal_handle_get_object_cb (EGdbusCal *interface,
+data_cal_handle_get_object_cb (EDBusCalendar *interface,
                                GDBusMethodInvocation *invocation,
-                               const gchar * const *in_uid_rid,
+                               const gchar *in_uid,
+                               const gchar *in_rid,
                                EDataCal *cal)
 {
 	OperationData *op;
 
-	op = op_new (OP_GET_OBJECT, cal, invocation);
-	g_return_val_if_fail (e_gdbus_cal_decode_get_object (in_uid_rid, &op->d.ur.uid, &op->d.ur.rid), FALSE);
+	/* Recurrence ID is optional.  Its omission is denoted
+	 * via D-Bus by an emptry string.  Convert it to NULL. */
+	if (in_rid != NULL && *in_rid == '\0')
+		in_rid = NULL;
 
-	e_gdbus_cal_complete_get_object (interface, invocation, op->id);
+	op = op_new (OP_GET_OBJECT, cal, invocation);
+	op->d.ur.uid = g_strdup (in_uid);
+	op->d.ur.rid = g_strdup (in_rid);
 
 	op_dispatch (cal, op);
 
@@ -743,7 +892,7 @@ data_cal_handle_get_object_cb (EGdbusCal *interface,
 }
 
 static gboolean
-data_cal_handle_get_object_list_cb (EGdbusCal *interface,
+data_cal_handle_get_object_list_cb (EDBusCalendar *interface,
                                     GDBusMethodInvocation *invocation,
                                     const gchar *in_sexp,
                                     EDataCal *cal)
@@ -753,29 +902,30 @@ data_cal_handle_get_object_list_cb (EGdbusCal *interface,
 	op = op_new (OP_GET_OBJECT_LIST, cal, invocation);
 	op->d.sexp = g_strdup (in_sexp);
 
-	e_gdbus_cal_complete_get_object_list (interface, invocation, op->id);
-
 	op_dispatch (cal, op);
 
 	return TRUE;
 }
 
 static gboolean
-data_cal_handle_get_free_busy_cb (EGdbusCal *interface,
+data_cal_handle_get_free_busy_cb (EDBusCalendar *interface,
                                   GDBusMethodInvocation *invocation,
-                                  const gchar * const *in_start_end_userlist,
+                                  gint64 in_start,
+                                  gint64 in_end,
+                                  const gchar **in_users,
                                   EDataCal *cal)
 {
 	OperationData *op;
-	guint start, end;
+	GSList *tmp = NULL;
+	gint ii;
 
-	op = op_new (OP_GET_FREE_BUSY, cal, invocation);
-	g_return_val_if_fail (e_gdbus_cal_decode_get_free_busy (in_start_end_userlist, &start, &end, &op->d.fb.users), FALSE);
-
-	op->d.fb.start = (time_t) start;
-	op->d.fb.end = (time_t) end;
+	for (ii = 0; in_users[ii] != NULL; ii++)
+		tmp = g_slist_prepend (tmp, g_strdup (in_users[ii]));
 
-	e_gdbus_cal_complete_get_free_busy (interface, invocation, op->id);
+	op = op_new (OP_GET_FREE_BUSY, cal, invocation);
+	op->d.fb.start = (time_t) in_start;
+	op->d.fb.end = (time_t) in_end;
+	op->d.fb.users = g_slist_reverse (tmp);
 
 	op_dispatch (cal, op);
 
@@ -783,17 +933,20 @@ data_cal_handle_get_free_busy_cb (EGdbusCal *interface,
 }
 
 static gboolean
-data_cal_handle_create_objects_cb (EGdbusCal *interface,
+data_cal_handle_create_objects_cb (EDBusCalendar *interface,
                                    GDBusMethodInvocation *invocation,
-                                   const gchar * const *in_calobjs,
+                                   const gchar **in_calobjs,
                                    EDataCal *cal)
 {
 	OperationData *op;
+	GSList *tmp = NULL;
+	gint ii;
 
-	op = op_new (OP_CREATE_OBJECTS, cal, invocation);
-	op->d.calobjs = e_util_strv_to_slist (in_calobjs);
+	for (ii = 0; in_calobjs[ii] != NULL; ii++)
+		tmp = g_slist_prepend (tmp, g_strdup (in_calobjs[ii]));
 
-	e_gdbus_cal_complete_create_objects (interface, invocation, op->id);
+	op = op_new (OP_CREATE_OBJECTS, cal, invocation);
+	op->d.calobjs = g_slist_reverse (tmp);
 
 	op_dispatch (cal, op);
 
@@ -801,39 +954,83 @@ data_cal_handle_create_objects_cb (EGdbusCal *interface,
 }
 
 static gboolean
-data_cal_handle_modify_objects_cb (EGdbusCal *interface,
+data_cal_handle_modify_objects_cb (EDBusCalendar *interface,
                                    GDBusMethodInvocation *invocation,
-                                   const gchar * const *in_mod_calobjs,
+                                   const gchar **in_ics_objects,
+                                   const gchar *in_mod_type,
                                    EDataCal *cal)
 {
+	GEnumClass *enum_class;
+	GEnumValue *enum_value;
 	OperationData *op;
-	guint mod;
+	GSList *tmp = NULL;
+	gint ii;
 
-	op = op_new (OP_MODIFY_OBJECTS, cal, invocation);
-	g_return_val_if_fail (e_gdbus_cal_decode_modify_objects (in_mod_calobjs, &op->d.mo.calobjs, &mod), FALSE);
-	op->d.mo.mod = mod;
+	enum_class = g_type_class_ref (E_TYPE_CAL_OBJ_MOD_TYPE);
+	enum_value = g_enum_get_value_by_nick (enum_class, in_mod_type);
+	g_return_val_if_fail (enum_value != NULL, FALSE);
 
-	e_gdbus_cal_complete_modify_objects (interface, invocation, op->id);
+	for (ii = 0; in_ics_objects[ii] != NULL; ii++)
+		tmp = g_slist_prepend (tmp, g_strdup (in_ics_objects[ii]));
+
+	op = op_new (OP_MODIFY_OBJECTS, cal, invocation);
+	op->d.mo.calobjs = g_slist_reverse (tmp);
+	op->d.mo.mod = enum_value->value;
 
 	op_dispatch (cal, op);
 
+	g_type_class_unref (enum_class);
+
 	return TRUE;
 }
 
 static gboolean
-data_cal_handle_remove_objects_cb (EGdbusCal *interface,
+data_cal_handle_remove_objects_cb (EDBusCalendar *interface,
                                    GDBusMethodInvocation *invocation,
-                                   const gchar * const *in_mod_ids,
+                                   GVariant *in_uid_rid_array,
+                                   const gchar *in_mod_type,
                                    EDataCal *cal)
 {
+	GEnumClass *enum_class;
+	GEnumValue *enum_value;
 	OperationData *op;
-	guint mod = 0;
+	GSList *tmp = NULL;
+	gsize n_children, ii;
 
-	op = op_new (OP_REMOVE_OBJECTS, cal, invocation);
-	g_return_val_if_fail (e_gdbus_cal_decode_remove_objects (in_mod_ids, &op->d.ro.ids, &mod), FALSE);
-	op->d.ro.mod = mod;
+	enum_class = g_type_class_ref (E_TYPE_CAL_OBJ_MOD_TYPE);
+	enum_value = g_enum_get_value_by_nick (enum_class, in_mod_type);
+	g_return_val_if_fail (enum_value != NULL, FALSE);
+
+	n_children = g_variant_n_children (in_uid_rid_array);
+	for (ii = 0; ii < n_children; ii++) {
+		ECalComponentId *id;
+
+		/* e_cal_component_free_id() uses g_free(),
+		 * not g_slice_free().  Therefore allocate
+		 * with g_malloc(), not g_slice_new(). */
+		id = g_malloc (sizeof (ECalComponentId));
+
+		g_variant_get_child (
+			in_uid_rid_array, ii, "ss", &id->uid, &id->rid);
+
+		if (id->uid != NULL && *id->uid == '\0') {
+			e_cal_component_free_id (id);
+			continue;
+		}
 
-	e_gdbus_cal_complete_remove_objects (interface, invocation, op->id);
+		/* Recurrence ID is optional.  Its omission is denoted
+		 * via D-Bus by an empty string.  Convert it to NULL. */
+		if (id->rid != NULL && *id->rid == '\0') {
+			g_free (id->rid);
+			id->rid = NULL;
+		}
+
+		tmp = g_slist_prepend (tmp, id);
+	}
+
+	op = op_new (OP_REMOVE_OBJECTS, cal, invocation);
+	op->d.ro.ids = g_slist_reverse (tmp);
+	op->d.ro.mod = enum_value->value;
 
 	op_dispatch (cal, op);
 
@@ -841,7 +1038,7 @@ data_cal_handle_remove_objects_cb (EGdbusCal *interface,
 }
 
 static gboolean
-data_cal_handle_receive_objects_cb (EGdbusCal *interface,
+data_cal_handle_receive_objects_cb (EDBusCalendar *interface,
                                     GDBusMethodInvocation *invocation,
                                     const gchar *in_calobj,
                                     EDataCal *cal)
@@ -851,15 +1048,13 @@ data_cal_handle_receive_objects_cb (EGdbusCal *interface,
 	op = op_new (OP_RECEIVE_OBJECTS, cal, invocation);
 	op->d.co.calobj = g_strdup (in_calobj);
 
-	e_gdbus_cal_complete_receive_objects (interface, invocation, op->id);
-
 	op_dispatch (cal, op);
 
 	return TRUE;
 }
 
 static gboolean
-data_cal_handle_send_objects_cb (EGdbusCal *interface,
+data_cal_handle_send_objects_cb (EDBusCalendar *interface,
                                  GDBusMethodInvocation *invocation,
                                  const gchar *in_calobj,
                                  EDataCal *cal)
@@ -869,25 +1064,28 @@ data_cal_handle_send_objects_cb (EGdbusCal *interface,
 	op = op_new (OP_SEND_OBJECTS, cal, invocation);
 	op->d.co.calobj = g_strdup (in_calobj);
 
-	e_gdbus_cal_complete_send_objects (interface, invocation, op->id);
-
 	op_dispatch (cal, op);
 
 	return TRUE;
 }
 
 static gboolean
-data_cal_handle_get_attachment_uris_cb (EGdbusCal *interface,
+data_cal_handle_get_attachment_uris_cb (EDBusCalendar *interface,
                                         GDBusMethodInvocation *invocation,
-                                        const gchar * const *in_uid_rid,
+                                        const gchar *in_uid,
+                                        const gchar *in_rid,
                                         EDataCal *cal)
 {
 	OperationData *op;
 
-	op = op_new (OP_GET_ATTACHMENT_URIS, cal, invocation);
-	g_return_val_if_fail (e_gdbus_cal_decode_get_attachment_uris (in_uid_rid, &op->d.ur.uid, &op->d.ur.rid), FALSE);
+	/* Recurrence ID is optional.  Its omission is denoted
+	 * via D-Bus by an empty string.  Convert it to NULL. */
+	if (in_rid != NULL && *in_rid == '\0')
+		in_rid = NULL;
 
-	e_gdbus_cal_complete_get_attachment_uris (interface, invocation, op->id);
+	op = op_new (OP_GET_ATTACHMENT_URIS, cal, invocation);
+	op->d.ur.uid = g_strdup (in_uid);
+	op->d.ur.rid = g_strdup (in_rid);
 
 	op_dispatch (cal, op);
 
@@ -895,17 +1093,24 @@ data_cal_handle_get_attachment_uris_cb (EGdbusCal *interface,
 }
 
 static gboolean
-data_cal_handle_discard_alarm_cb (EGdbusCal *interface,
+data_cal_handle_discard_alarm_cb (EDBusCalendar *interface,
                                   GDBusMethodInvocation *invocation,
-                                  const gchar * const *in_uid_rid_auid,
+                                  const gchar *in_uid,
+                                  const gchar *in_rid,
+                                  const gchar *in_alarm_uid,
                                   EDataCal *cal)
 {
 	OperationData *op;
 
-	op = op_new (OP_DISCARD_ALARM, cal, invocation);
-	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);
+	/* Recurrence ID is optional.  Its omission is denoted
+	 * via D-Bus by an empty string.  Convert it to NULL. */
+	if (in_rid != NULL && *in_rid == '\0')
+		in_rid = NULL;
 
-	e_gdbus_cal_complete_discard_alarm (interface, invocation, op->id);
+	op = op_new (OP_DISCARD_ALARM, cal, invocation);
+	op->d.ura.uid = g_strdup (in_uid);
+	op->d.ura.rid = g_strdup (in_rid);
+	op->d.ura.auid = g_strdup (in_alarm_uid);
 
 	op_dispatch (cal, op);
 
@@ -913,7 +1118,7 @@ data_cal_handle_discard_alarm_cb (EGdbusCal *interface,
 }
 
 static gboolean
-data_cal_handle_get_view_cb (EGdbusCal *interface,
+data_cal_handle_get_view_cb (EDBusCalendar *interface,
                              GDBusMethodInvocation *invocation,
                              const gchar *in_sexp,
                              EDataCal *cal)
@@ -923,8 +1128,6 @@ data_cal_handle_get_view_cb (EGdbusCal *interface,
 	op = op_new (OP_GET_VIEW, cal, invocation);
 	op->d.sexp = g_strdup (in_sexp);
 
-	e_gdbus_cal_complete_get_view (interface, invocation, op->id);
-
 	/* This operation is never queued. */
 	e_operation_pool_push (ops_pool, op);
 
@@ -932,7 +1135,7 @@ data_cal_handle_get_view_cb (EGdbusCal *interface,
 }
 
 static gboolean
-data_cal_handle_get_timezone_cb (EGdbusCal *interface,
+data_cal_handle_get_timezone_cb (EDBusCalendar *interface,
                                  GDBusMethodInvocation *invocation,
                                  const gchar *in_tzid,
                                  EDataCal *cal)
@@ -942,15 +1145,13 @@ data_cal_handle_get_timezone_cb (EGdbusCal *interface,
 	op = op_new (OP_GET_TIMEZONE, cal, invocation);
 	op->d.tzid = g_strdup (in_tzid);
 
-	e_gdbus_cal_complete_get_timezone (interface, invocation, op->id);
-
 	op_dispatch (cal, op);
 
 	return TRUE;
 }
 
 static gboolean
-data_cal_handle_add_timezone_cb (EGdbusCal *interface,
+data_cal_handle_add_timezone_cb (EDBusCalendar *interface,
                                  GDBusMethodInvocation *invocation,
                                  const gchar *in_tzobject,
                                  EDataCal *cal)
@@ -960,15 +1161,13 @@ data_cal_handle_add_timezone_cb (EGdbusCal *interface,
 	op = op_new (OP_ADD_TIMEZONE, cal, invocation);
 	op->d.tzobject = g_strdup (in_tzobject);
 
-	e_gdbus_cal_complete_add_timezone (interface, invocation, op->id);
-
 	op_dispatch (cal, op);
 
 	return TRUE;
 }
 
 static gboolean
-data_cal_handle_close_cb (EGdbusCal *interface,
+data_cal_handle_close_cb (EDBusCalendar *interface,
                           GDBusMethodInvocation *invocation,
                           EDataCal *cal)
 {
@@ -978,30 +1177,12 @@ data_cal_handle_close_cb (EGdbusCal *interface,
 	/* unref here makes sure the cal is freed in a separate thread */
 	g_object_unref (cal);
 
-	e_gdbus_cal_complete_close (interface, invocation, NULL);
-
 	/* This operation is never queued. */
 	e_operation_pool_push (ops_pool, op);
 
 	return TRUE;
 }
 
-/* free returned pointer with g_strfreev() */
-static gchar **
-gslist_to_strv (const GSList *lst)
-{
-	gchar **seq;
-	const GSList *l;
-	gint i;
-
-	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);
-	}
-
-	return seq;
-}
-
 /**
  * e_data_cal_respond_open:
  * @cal: A calendar client interface.
@@ -1016,11 +1197,13 @@ e_data_cal_respond_open (EDataCal *cal,
                          guint32 opid,
                          GError *error)
 {
+	OperationData *data;
 	GError *copy = NULL;
 
 	g_return_if_fail (E_IS_DATA_CAL (cal));
 
-	op_complete (cal, opid);
+	data = op_claim (cal, opid);
+	g_return_if_fail (data != NULL);
 
 	/* Translators: This is prefix to a detailed error message */
 	g_prefix_error (&error, "%s", _("Cannot open calendar: "));
@@ -1032,10 +1215,17 @@ e_data_cal_respond_open (EDataCal *cal,
 		copy = g_error_copy (error);
 	e_cal_backend_notify_opened (cal->priv->backend, copy);
 
-	e_gdbus_cal_emit_open_done (cal->priv->dbus_interface, opid, error);
+	if (error == NULL) {
+		e_dbus_calendar_complete_open (
+			cal->priv->dbus_interface,
+			data->invocation);
+	} else {
+		data_cal_convert_to_client_error (error);
+		g_dbus_method_invocation_take_error (
+			data->invocation, error);
+	}
 
-	if (error != NULL)
-		g_error_free (error);
+	op_unref (data);
 
 	/* Dispatch any pending operations. */
 
@@ -1069,17 +1259,27 @@ e_data_cal_respond_refresh (EDataCal *cal,
                             guint32 opid,
                             GError *error)
 {
+	OperationData *data;
+
 	g_return_if_fail (E_IS_DATA_CAL (cal));
 
-	op_complete (cal, opid);
+	data = op_claim (cal, opid);
+	g_return_if_fail (data != NULL);
 
 	/* Translators: This is prefix to a detailed error message */
 	g_prefix_error (&error, "%s", _("Cannot refresh calendar: "));
 
-	e_gdbus_cal_emit_refresh_done (cal->priv->dbus_interface, opid, error);
+	if (error == NULL) {
+		e_dbus_calendar_complete_refresh (
+			cal->priv->dbus_interface,
+			data->invocation);
+	} else {
+		data_cal_convert_to_client_error (error);
+		g_dbus_method_invocation_take_error (
+			data->invocation, error);
+	}
 
-	if (error)
-		g_error_free (error);
+	op_unref (data);
 }
 
 /**
@@ -1098,20 +1298,27 @@ e_data_cal_respond_get_backend_property (EDataCal *cal,
                                          GError *error,
                                          const gchar *prop_value)
 {
-	gchar *gdbus_prop_value = NULL;
+	OperationData *data;
 
 	g_return_if_fail (E_IS_DATA_CAL (cal));
 
-	op_complete (cal, opid);
+	data = op_claim (cal, opid);
+	g_return_if_fail (data != NULL);
 
 	/* 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->dbus_interface, opid, error, e_util_ensure_gdbus_string (prop_value, &gdbus_prop_value));
-
-	g_free (gdbus_prop_value);
-	if (error)
+	if (error == NULL) {
+		e_data_cal_report_backend_property_changed (
+			cal, data->d.prop_name, prop_value);
+	} else {
+		/* This should never happen, since all backend property
+		 * requests now originate from our constructed() method. */
+		g_warning ("%s: %s", G_STRFUNC, error->message);
 		g_error_free (error);
+	}
+
+	op_unref (data);
 }
 
 /**
@@ -1149,20 +1356,34 @@ e_data_cal_respond_get_object (EDataCal *cal,
                                GError *error,
                                const gchar *object)
 {
-	gchar *gdbus_object = NULL;
+	OperationData *data;
 
 	g_return_if_fail (E_IS_DATA_CAL (cal));
 
-	op_complete (cal, opid);
+	data = op_claim (cal, opid);
+	g_return_if_fail (data != NULL);
 
 	/* 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->dbus_interface, opid, error, e_util_ensure_gdbus_string (object, &gdbus_object));
+	if (error == NULL) {
+		gchar *utf8_object;
 
-	g_free (gdbus_object);
-	if (error)
-		g_error_free (error);
+		utf8_object = e_util_utf8_make_valid (object);
+
+		e_dbus_calendar_complete_get_object (
+			cal->priv->dbus_interface,
+			data->invocation,
+			utf8_object);
+
+		g_free (utf8_object);
+	} else {
+		data_cal_convert_to_client_error (error);
+		g_dbus_method_invocation_take_error (
+			data->invocation, error);
+	}
+
+	op_unref (data);
 }
 
 /**
@@ -1181,22 +1402,33 @@ e_data_cal_respond_get_object_list (EDataCal *cal,
                                     GError *error,
                                     const GSList *objects)
 {
-	gchar **strv_objects;
+	OperationData *data;
 
 	g_return_if_fail (E_IS_DATA_CAL (cal));
 
-	op_complete (cal, opid);
+	data = op_claim (cal, opid);
+	g_return_if_fail (data != NULL);
 
 	/* 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);
+	if (error == NULL) {
+		gchar **strv;
+		guint length;
+		gint ii = 0;
 
-	e_gdbus_cal_emit_get_object_list_done (cal->priv->dbus_interface, opid, error, (const gchar * const *) strv_objects);
+		length = g_slist_length ((GSList *) objects);
+		strv = g_new0 (gchar *, length + 1);
 
-	g_strfreev (strv_objects);
-	if (error)
-		g_error_free (error);
+		while (objects != NULL) {
+			strv[ii++] = e_util_utf8_make_valid (objects->data);
+			objects = g_slist_next (objects);
+		}
+
+		g_strfreev (strv);
+	}
+
+	op_unref (data);
 }
 
 /**
@@ -1214,17 +1446,27 @@ e_data_cal_respond_get_free_busy (EDataCal *cal,
                                   guint32 opid,
                                   GError *error)
 {
+	OperationData *data;
+
 	g_return_if_fail (E_IS_DATA_CAL (cal));
 
-	op_complete (cal, opid);
+	data = op_claim (cal, opid);
+	g_return_if_fail (data != NULL);
 
 	/* 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->dbus_interface, opid, error);
+	if (error == NULL) {
+		e_dbus_calendar_complete_get_free_busy (
+			cal->priv->dbus_interface,
+			data->invocation);
+	} else {
+		data_cal_convert_to_client_error (error);
+		g_dbus_method_invocation_take_error (
+			data->invocation, error);
+	}
 
-	if (error)
-		g_error_free (error);
+	op_unref (data);
 }
 
 /**
@@ -1243,34 +1485,57 @@ e_data_cal_respond_create_objects (EDataCal *cal,
                                    guint32 opid,
                                    GError *error,
                                    const GSList *uids,
-                                   /* const */ GSList *new_components)
+                                   GSList *new_components)
 {
-	gchar **array = NULL;
-	const GSList *l;
-	gint i = 0;
+	OperationData *data;
 
 	g_return_if_fail (E_IS_DATA_CAL (cal));
 
-	op_complete (cal, opid);
-
-	array = g_new0 (gchar *, g_slist_length ((GSList *) uids) + 1);
-	for (l = uids; l != NULL; l = l->next) {
-		array[i++] = e_util_utf8_make_valid (l->data);
-	}
+	data = op_claim (cal, opid);
+	g_return_if_fail (data != NULL);
 
 	/* Translators: This is prefix to a detailed error message */
 	g_prefix_error (&error, "%s", _("Cannot create calendar object: "));
 
-	e_gdbus_cal_emit_create_objects_done (cal->priv->dbus_interface, opid, error, (const gchar * const *) array);
+	if (error == NULL) {
+		ECalBackend *backend;
+		gchar **strv;
+		guint length;
+		gint ii = 0;
 
-	g_strfreev (array);
-	if (error)
-		g_error_free (error);
-	else {
-		for (l = new_components; l; l = l->next) {
-			e_cal_backend_notify_component_created (cal->priv->backend, l->data);
+		backend = e_data_cal_get_backend (cal);
+
+		length = g_slist_length ((GSList *) uids);
+		strv = g_new0 (gchar *, length + 1);
+
+		while (uids != NULL) {
+			strv[ii++] = e_util_utf8_make_valid (uids->data);
+			uids = g_slist_next ((GSList *) uids);
+		}
+
+		e_dbus_calendar_complete_create_objects (
+			cal->priv->dbus_interface,
+			data->invocation,
+			(const gchar * const *) strv);
+
+		g_strfreev (strv);
+
+		while (new_components != NULL) {
+			ECalComponent *component;
+
+			component = E_CAL_COMPONENT (new_components->data);
+			e_cal_backend_notify_component_created (
+				backend, component);
+
+			new_components = g_slist_next (new_components);
 		}
+	} else {
+		data_cal_convert_to_client_error (error);
+		g_dbus_method_invocation_take_error (
+			data->invocation, error);
 	}
+
+	op_unref (data);
 }
 
 /**
@@ -1288,28 +1553,48 @@ void
 e_data_cal_respond_modify_objects (EDataCal *cal,
                                    guint32 opid,
                                    GError *error,
-                                   /* const */ GSList *old_components,
-                                   /* const */ GSList *new_components)
+                                   GSList *old_components,
+                                   GSList *new_components)
 {
+	OperationData *data;
+
 	g_return_if_fail (E_IS_DATA_CAL (cal));
 
-	op_complete (cal, opid);
+	data = op_claim (cal, opid);
+	g_return_if_fail (data != NULL);
 
 	/* Translators: This is prefix to a detailed error message */
 	g_prefix_error (&error, "%s", _("Cannot modify calendar object: "));
 
-	e_gdbus_cal_emit_modify_objects_done (cal->priv->dbus_interface, opid, error);
+	if (error == NULL) {
+		ECalBackend *backend;
 
-	if (error)
-		g_error_free (error);
-	else {
-		const GSList *lold = old_components, *lnew = new_components;
-		while (lold && lnew) {
-			e_cal_backend_notify_component_modified (cal->priv->backend, lold->data, lnew->data);
-			lold = lold->next;
-			lnew = lnew->next;
+		backend = e_data_cal_get_backend (cal);
+
+		e_dbus_calendar_complete_modify_objects (
+			cal->priv->dbus_interface,
+			data->invocation);
+
+		while (old_components != NULL && new_components != NULL) {
+			ECalComponent *old_component;
+			ECalComponent *new_component;
+
+			old_component = E_CAL_COMPONENT (old_components->data);
+			new_component = E_CAL_COMPONENT (new_components->data);
+
+			e_cal_backend_notify_component_modified (
+				backend, old_component, new_component);
+
+			old_components = g_slist_next (old_components);
+			new_components = g_slist_next (new_components);
 		}
+	} else {
+		data_cal_convert_to_client_error (error);
+		g_dbus_method_invocation_take_error (
+			data->invocation, error);
 	}
+
+	op_unref (data);
 }
 
 /**
@@ -1330,32 +1615,54 @@ e_data_cal_respond_remove_objects (EDataCal *cal,
                                   guint32 opid,
                                   GError *error,
                                   const GSList *ids,
-                                  /* const */ GSList *old_components,
-                                  /* const */ GSList *new_components)
+                                  GSList *old_components,
+                                  GSList *new_components)
 {
+	OperationData *data;
+
 	g_return_if_fail (E_IS_DATA_CAL (cal));
 
-	op_complete (cal, opid);
+	data = op_claim (cal, opid);
+	g_return_if_fail (data != NULL);
 
 	/* Translators: This is prefix to a detailed error message */
 	g_prefix_error (&error, "%s", _("Cannot remove calendar object: "));
 
-	e_gdbus_cal_emit_remove_objects_done (cal->priv->dbus_interface, opid, error);
+	if (error == NULL) {
+		ECalBackend *backend;
 
-	if (error)
-		g_error_free (error);
-	else {
-		const GSList *lid = ids, *lold = old_components, *lnew = new_components;
-		while (lid && lold) {
-			e_cal_backend_notify_component_removed (cal->priv->backend, lid->data, lold->data, lnew ? lnew->data : NULL);
+		backend = e_data_cal_get_backend (cal);
+
+		e_dbus_calendar_complete_remove_objects (
+			cal->priv->dbus_interface,
+			data->invocation);
 
-			lid = lid->next;
-			lold = lold->next;
+		while (ids != NULL && old_components != NULL) {
+			ECalComponentId *id;
+			ECalComponent *old_component;
+			ECalComponent *new_component = NULL;
 
-			if (lnew)
-				lnew = lnew->next;
+			id = ids->data;
+			old_component = E_CAL_COMPONENT (old_components->data);
+			new_component = (new_components != NULL) ?
+				E_CAL_COMPONENT (new_components->data) : NULL;
+
+			e_cal_backend_notify_component_removed (
+				backend, id, old_component, new_component);
+
+			ids = g_slist_next ((GSList *) ids);
+			old_components = g_slist_next (old_components);
+
+			if (new_components != NULL)
+				new_components = g_slist_next (new_components);
 		}
+	} else {
+		data_cal_convert_to_client_error (error);
+		g_dbus_method_invocation_take_error (
+			data->invocation, error);
 	}
+
+	op_unref (data);
 }
 
 /**
@@ -1372,17 +1679,27 @@ e_data_cal_respond_receive_objects (EDataCal *cal,
                                     guint32 opid,
                                     GError *error)
 {
+	OperationData *data;
+
 	g_return_if_fail (E_IS_DATA_CAL (cal));
 
-	op_complete (cal, opid);
+	data = op_claim (cal, opid);
+	g_return_if_fail (data != NULL);
 
 	/* 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->dbus_interface, opid, error);
+	if (error == NULL) {
+		e_dbus_calendar_complete_receive_objects (
+			cal->priv->dbus_interface,
+			data->invocation);
+	} else {
+		data_cal_convert_to_client_error (error);
+		g_dbus_method_invocation_take_error (
+			data->invocation, error);
+	}
 
-	if (error)
-		g_error_free (error);
+	op_unref (data);
 }
 
 /**
@@ -1403,22 +1720,48 @@ e_data_cal_respond_send_objects (EDataCal *cal,
                                  const GSList *users,
                                  const gchar *calobj)
 {
-	gchar **strv_users_calobj;
+	OperationData *data;
 
 	g_return_if_fail (E_IS_DATA_CAL (cal));
 
-	op_complete (cal, opid);
+	data = op_claim (cal, opid);
+	g_return_if_fail (data != NULL);
 
 	/* Translators: This is prefix to a detailed error message */
 	g_prefix_error (&error, "%s", _("Cannot send calendar objects: "));
 
-	strv_users_calobj = e_gdbus_cal_encode_send_objects (calobj, users);
+	if (error == NULL) {
+		gchar *utf8_calobj;
+		gchar **strv;
+		guint length;
+		gint ii = 0;
 
-	e_gdbus_cal_emit_send_objects_done (cal->priv->dbus_interface, opid, error, (const gchar * const *) strv_users_calobj);
+		length = g_slist_length ((GSList *) users);
+		strv = g_new0 (gchar *, length + 1);
 
-	g_strfreev (strv_users_calobj);
-	if (error)
-		g_error_free (error);
+		while (users != NULL) {
+			strv[ii++] = e_util_utf8_make_valid (users->data);
+			users = g_slist_next ((GSList *) users);
+		}
+
+		utf8_calobj = e_util_utf8_make_valid (calobj);
+
+		e_dbus_calendar_complete_send_objects (
+			cal->priv->dbus_interface,
+			data->invocation,
+			(const gchar *const *) strv,
+			utf8_calobj);
+
+		g_free (utf8_calobj);
+
+		g_strfreev (strv);
+	} else {
+		data_cal_convert_to_client_error (error);
+		g_dbus_method_invocation_take_error (
+			data->invocation, error);
+	}
+
+	op_unref (data);
 }
 
 /**
@@ -1437,22 +1780,40 @@ e_data_cal_respond_get_attachment_uris (EDataCal *cal,
                                         GError *error,
                                         const GSList *attachment_uris)
 {
-	gchar **strv_attachment_uris;
+	OperationData *data;
 
 	g_return_if_fail (E_IS_DATA_CAL (cal));
 
-	op_complete (cal, opid);
+	data = op_claim (cal, opid);
+	g_return_if_fail (data != NULL);
 
 	/* Translators: This is prefix to a detailed error message */
 	g_prefix_error (&error, "%s", _("Could not retrieve attachment uris: "));
 
-	strv_attachment_uris = gslist_to_strv (attachment_uris);
+	if (error != NULL) {
+		gchar **strv;
+		guint length;
+		gint ii = 0;
 
-	e_gdbus_cal_emit_get_attachment_uris_done (cal->priv->dbus_interface, opid, error, (const gchar * const *) strv_attachment_uris);
+		length = g_slist_length ((GSList *) attachment_uris);
+		strv = g_new0 (gchar *, length + 1);
 
-	g_strfreev (strv_attachment_uris);
-	if (error)
-		g_error_free (error);
+		while (attachment_uris != NULL) {
+			strv[ii++] = e_util_utf8_make_valid (attachment_uris->data);
+			attachment_uris = g_slist_next ((GSList *) attachment_uris);
+		}
+
+		e_dbus_calendar_complete_get_attachment_uris (
+			cal->priv->dbus_interface,
+			data->invocation,
+			(const gchar * const *) strv);
+
+		g_strfreev (strv);
+	} else {
+		data_cal_convert_to_client_error (error);
+		g_dbus_method_invocation_take_error (
+			data->invocation, error);
+	}
 }
 
 /**
@@ -1469,17 +1830,27 @@ e_data_cal_respond_discard_alarm (EDataCal *cal,
                                   guint32 opid,
                                   GError *error)
 {
+	OperationData *data;
+
 	g_return_if_fail (E_IS_DATA_CAL (cal));
 
-	op_complete (cal, opid);
+	data = op_claim (cal, opid);
+	g_return_if_fail (data != NULL);
 
 	/* Translators: This is prefix to a detailed error message */
 	g_prefix_error (&error, "%s", _("Could not discard reminder: "));
 
-	e_gdbus_cal_emit_discard_alarm_done (cal->priv->dbus_interface, opid, error);
+	if (error == NULL) {
+		e_dbus_calendar_complete_discard_alarm (
+			cal->priv->dbus_interface,
+			data->invocation);
+	} else {
+		data_cal_convert_to_client_error (error);
+		g_dbus_method_invocation_take_error (
+			data->invocation, error);
+	}
 
-	if (error)
-		g_error_free (error);
+	op_unref (data);
 }
 
 /**
@@ -1498,20 +1869,34 @@ e_data_cal_respond_get_view (EDataCal *cal,
                              GError *error,
                              const gchar *view_path)
 {
-	gchar *gdbus_view_path = NULL;
+	OperationData *data;
 
 	g_return_if_fail (E_IS_DATA_CAL (cal));
 
-	op_complete (cal, opid);
+	data = op_claim (cal, opid);
+	g_return_if_fail (data != NULL);
 
 	/* 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->dbus_interface, opid, error, e_util_ensure_gdbus_string (view_path, &gdbus_view_path));
+	if (error == NULL) {
+		gchar *utf8_view_path;
 
-	g_free (gdbus_view_path);
-	if (error)
-		g_error_free (error);
+		utf8_view_path = e_util_utf8_make_valid (view_path);
+
+		e_dbus_calendar_complete_get_view (
+			cal->priv->dbus_interface,
+			data->invocation,
+			utf8_view_path);
+
+		g_free (utf8_view_path);
+	} else {
+		data_cal_convert_to_client_error (error);
+		g_dbus_method_invocation_take_error (
+			data->invocation, error);
+	}
+
+	op_unref (data);
 }
 
 /**
@@ -1530,20 +1915,34 @@ e_data_cal_respond_get_timezone (EDataCal *cal,
                                  GError *error,
                                  const gchar *tzobject)
 {
-	gchar *gdbus_tzobject = NULL;
+	OperationData *data;
 
 	g_return_if_fail (E_IS_DATA_CAL (cal));
 
-	op_complete (cal, opid);
+	data = op_claim (cal, opid);
+	g_return_if_fail (data != NULL);
 
 	/* 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->dbus_interface, opid, error, e_util_ensure_gdbus_string (tzobject, &gdbus_tzobject));
+	if (error == NULL) {
+		gchar *utf8_tz_object;
 
-	g_free (gdbus_tzobject);
-	if (error)
-		g_error_free (error);
+		utf8_tz_object = e_util_utf8_make_valid (tzobject);
+
+		e_dbus_calendar_complete_get_timezone (
+			cal->priv->dbus_interface,
+			data->invocation,
+			utf8_tz_object);
+
+		g_free (utf8_tz_object);
+	} else {
+		data_cal_convert_to_client_error (error);
+		g_dbus_method_invocation_take_error (
+			data->invocation, error);
+	}
+
+	op_unref (data);
 }
 
 /**
@@ -1560,17 +1959,27 @@ e_data_cal_respond_add_timezone (EDataCal *cal,
                                  guint32 opid,
                                  GError *error)
 {
+	OperationData *data;
+
 	g_return_if_fail (E_IS_DATA_CAL (cal));
 
-	op_complete (cal, opid);
+	data = op_claim (cal, opid);
+	g_return_if_fail (data != NULL);
 
 	/* 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->dbus_interface, opid, error);
+	if (error == NULL) {
+		e_dbus_calendar_complete_add_timezone (
+			cal->priv->dbus_interface,
+			data->invocation);
+	} else {
+		data_cal_convert_to_client_error (error);
+		g_dbus_method_invocation_take_error (
+			data->invocation, error);
+	}
 
-	if (error)
-		g_error_free (error);
+	op_unref (data);
 }
 
 /**
@@ -1587,7 +1996,7 @@ e_data_cal_report_error (EDataCal *cal,
 	g_return_if_fail (E_IS_DATA_CAL (cal));
 	g_return_if_fail (message != NULL);
 
-	e_gdbus_cal_emit_backend_error (cal->priv->dbus_interface, message);
+	e_dbus_calendar_emit_error (cal->priv->dbus_interface, message);
 }
 
 /**
@@ -1596,6 +2005,8 @@ e_data_cal_report_error (EDataCal *cal,
  * FIXME: Document me.
  *
  * Since: 3.2
+ *
+ * Deprecated: 3.8: Use e_cal_backend_set_writable() instead.
  **/
 void
 e_data_cal_report_readonly (EDataCal *cal,
@@ -1603,7 +2014,7 @@ e_data_cal_report_readonly (EDataCal *cal,
 {
 	g_return_if_fail (E_IS_DATA_CAL (cal));
 
-	e_gdbus_cal_emit_readonly (cal->priv->dbus_interface, readonly);
+	e_cal_backend_set_writable (cal->priv->backend, !readonly);
 }
 
 /**
@@ -1612,6 +2023,8 @@ e_data_cal_report_readonly (EDataCal *cal,
  * FIXME: Document me.
  *
  * Since: 3.2
+ *
+ * Deprecated: 3.8: Use e_backend_set_online() instead.
  **/
 void
 e_data_cal_report_online (EDataCal *cal,
@@ -1619,7 +2032,7 @@ e_data_cal_report_online (EDataCal *cal,
 {
 	g_return_if_fail (E_IS_DATA_CAL (cal));
 
-	e_gdbus_cal_emit_online (cal->priv->dbus_interface, is_online);
+	e_backend_set_online (E_BACKEND (cal->priv->backend), is_online);
 }
 
 /**
@@ -1652,15 +2065,25 @@ void
 e_data_cal_report_free_busy_data (EDataCal *cal,
                                   const GSList *freebusy)
 {
-	gchar **strv_freebusy;
+	gchar **strv;
+	guint length;
+	gint ii = 0;
 
 	g_return_if_fail (E_IS_DATA_CAL (cal));
 
-	strv_freebusy = gslist_to_strv (freebusy);
+	length = g_slist_length ((GSList *) freebusy);
+	strv = g_new0 (gchar *, length + 1);
+
+	while (freebusy != NULL) {
+		strv[ii++] = e_util_utf8_make_valid (freebusy->data);
+		freebusy = g_slist_next ((GSList *) freebusy);
+	}
 
-	e_gdbus_cal_emit_free_busy_data (cal->priv->dbus_interface, (const gchar * const *) strv_freebusy);
+	e_dbus_calendar_emit_free_busy_data (
+		cal->priv->dbus_interface,
+		(const gchar * const *) strv);
 
-	g_strfreev (strv_freebusy);
+	g_strfreev (strv);
 }
 
 /**
@@ -1675,19 +2098,37 @@ e_data_cal_report_backend_property_changed (EDataCal *cal,
                                             const gchar *prop_name,
                                             const gchar *prop_value)
 {
+	EDBusCalendar *dbus_interface;
 	gchar **strv;
 
 	g_return_if_fail (E_IS_DATA_CAL (cal));
 	g_return_if_fail (prop_name != NULL);
-	g_return_if_fail (*prop_name != '\0');
-	g_return_if_fail (prop_value != NULL);
 
-	strv = e_gdbus_templates_encode_two_strings (prop_name, prop_value);
-	g_return_if_fail (strv != NULL);
+	if (prop_value == NULL)
+		prop_value = "";
 
-	e_gdbus_cal_emit_backend_property_changed (cal->priv->dbus_interface, (const gchar * const *) strv);
+	dbus_interface = cal->priv->dbus_interface;
 
-	g_strfreev (strv);
+	if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_CAPABILITIES)) {
+		strv = g_strsplit (prop_value, ",", -1);
+		e_dbus_calendar_set_capabilities (
+			dbus_interface, (const gchar * const *) strv);
+		g_strfreev (strv);
+	}
+
+	if (g_str_equal (prop_name, CLIENT_BACKEND_PROPERTY_REVISION))
+		e_dbus_calendar_set_revision (dbus_interface, prop_value);
+
+	if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS))
+		e_dbus_calendar_set_cal_email_address (dbus_interface, prop_value);
+
+	if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS))
+		e_dbus_calendar_set_alarm_email_address (dbus_interface, prop_value);
+
+	if (g_str_equal (prop_name, CAL_BACKEND_PROPERTY_DEFAULT_OBJECT))
+		e_dbus_calendar_set_default_object (dbus_interface, prop_value);
+
+	/* Disregard anything else. */
 }
 
 static void
@@ -1832,6 +2273,70 @@ data_cal_finalize (GObject *object)
 	G_OBJECT_CLASS (e_data_cal_parent_class)->finalize (object);
 }
 
+static void
+data_cal_constructed (GObject *object)
+{
+	EDataCal *cal = E_DATA_CAL (object);
+	OperationData *op;
+
+	/* Chain up to parent's constructed() method. */
+	G_OBJECT_CLASS (e_data_cal_parent_class)->constructed (object);
+
+	g_object_bind_property (
+		cal->priv->backend, "cache-dir",
+		cal->priv->dbus_interface, "cache-dir",
+		G_BINDING_SYNC_CREATE);
+
+	g_object_bind_property (
+		cal->priv->backend, "online",
+		cal->priv->dbus_interface, "online",
+		G_BINDING_SYNC_CREATE);
+
+	g_object_bind_property (
+		cal->priv->backend, "writable",
+		cal->priv->dbus_interface, "writable",
+		G_BINDING_SYNC_CREATE);
+
+	/* XXX Initialize the rest of the properties by faking client
+	 *     requests.  At present it's the only way to fish values
+	 *     from ECalBackend's antiquated API. */
+
+	op = op_new (OP_GET_BACKEND_PROPERTY, cal, NULL);
+	op->d.prop_name = CLIENT_BACKEND_PROPERTY_CAPABILITIES;
+	e_cal_backend_get_backend_property (
+		cal->priv->backend, cal, op->id,
+		op->cancellable, op->d.prop_name);
+	op_unref (op);
+
+	op = op_new (OP_GET_BACKEND_PROPERTY, cal, NULL);
+	op->d.prop_name = CLIENT_BACKEND_PROPERTY_REVISION;
+	e_cal_backend_get_backend_property (
+		cal->priv->backend, cal, op->id,
+		op->cancellable, op->d.prop_name);
+	op_unref (op);
+
+	op = op_new (OP_GET_BACKEND_PROPERTY, cal, NULL);
+	op->d.prop_name = CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS;
+	e_cal_backend_get_backend_property (
+		cal->priv->backend, cal, op->id,
+		op->cancellable, op->d.prop_name);
+	op_unref (op);
+
+	op = op_new (OP_GET_BACKEND_PROPERTY, cal, NULL);
+	op->d.prop_name = CAL_BACKEND_PROPERTY_ALARM_EMAIL_ADDRESS;
+	e_cal_backend_get_backend_property (
+		cal->priv->backend, cal, op->id,
+		op->cancellable, op->d.prop_name);
+	op_unref (op);
+
+	op = op_new (OP_GET_BACKEND_PROPERTY, cal, NULL);
+	op->d.prop_name = CAL_BACKEND_PROPERTY_DEFAULT_OBJECT;
+	e_cal_backend_get_backend_property (
+		cal->priv->backend, cal, op->id,
+		op->cancellable, op->d.prop_name);
+	op_unref (op);
+}
+
 static gboolean
 data_cal_initable_init (GInitable *initable,
                         GCancellable *cancellable,
@@ -1841,8 +2346,8 @@ data_cal_initable_init (GInitable *initable,
 
 	cal = E_DATA_CAL (initable);
 
-	return e_gdbus_cal_register_object (
-		cal->priv->dbus_interface,
+	return g_dbus_interface_skeleton_export (
+		G_DBUS_INTERFACE_SKELETON (cal->priv->dbus_interface),
 		cal->priv->connection,
 		cal->priv->object_path,
 		error);
@@ -1860,6 +2365,7 @@ e_data_cal_class_init (EDataCalClass *class)
 	object_class->get_property = data_cal_get_property;
 	object_class->dispose = data_cal_dispose;
 	object_class->finalize = data_cal_finalize;
+	object_class->constructed = data_cal_constructed;
 
 	g_object_class_install_property (
 		object_class,
@@ -1912,11 +2418,13 @@ e_data_cal_initable_init (GInitableIface *interface)
 static void
 e_data_cal_init (EDataCal *ecal)
 {
-	EGdbusCal *dbus_interface;
+	EDBusCalendar *dbus_interface;
 
 	ecal->priv = E_DATA_CAL_GET_PRIVATE (ecal);
 
-	ecal->priv->dbus_interface = e_gdbus_cal_stub_new ();
+	dbus_interface = e_dbus_calendar_skeleton_new ();
+	ecal->priv->dbus_interface = dbus_interface;
+
 	ecal->priv->pending_ops = g_hash_table_new_full (
 		(GHashFunc) g_direct_hash,
 		(GEqualFunc) g_direct_equal,
@@ -1926,7 +2434,6 @@ e_data_cal_init (EDataCal *ecal)
 
 	g_mutex_init (&ecal->priv->open_lock);
 
-	dbus_interface = ecal->priv->dbus_interface;
 	g_signal_connect (
 		dbus_interface, "handle-open",
 		G_CALLBACK (data_cal_handle_open_cb), ecal);
@@ -1934,9 +2441,6 @@ e_data_cal_init (EDataCal *ecal)
 		dbus_interface, "handle-refresh",
 		G_CALLBACK (data_cal_handle_refresh_cb), ecal);
 	g_signal_connect (
-		dbus_interface, "handle-get-backend-property",
-		G_CALLBACK (data_cal_handle_get_backend_property_cb), ecal);
-	g_signal_connect (
 		dbus_interface, "handle-get-object",
 		G_CALLBACK (data_cal_handle_get_object_cb), ecal);
 	g_signal_connect (
diff --git a/calendar/libedata-cal/e-data-cal.h b/calendar/libedata-cal/e-data-cal.h
index 7e46372..b7e63e5 100644
--- a/calendar/libedata-cal/e-data-cal.h
+++ b/calendar/libedata-cal/e-data-cal.h
@@ -251,10 +251,6 @@ void		e_data_cal_respond_add_timezone	(EDataCal *cal,
 						 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_free_busy_data
 						(EDataCal *cal,
 						 const GSList *freebusy);
@@ -270,6 +266,10 @@ void		e_data_cal_respond_set_backend_property
 						 GError *error);
 void		e_data_cal_report_opened	(EDataCal *cal,
 						 const GError *error);
+void		e_data_cal_report_readonly	(EDataCal *cal,
+						 gboolean is_readonly);
+void		e_data_cal_report_online	(EDataCal *cal,
+						 gboolean is_online);
 #endif /* EDS_DISABLE_DEPRECATED */
 
 G_END_DECLS
diff --git a/calendar/libegdbus/Makefile.am b/calendar/libegdbus/Makefile.am
index e0d3bf1..ffeeaf5 100644
--- a/calendar/libegdbus/Makefile.am
+++ b/calendar/libegdbus/Makefile.am
@@ -11,8 +11,6 @@ libegdbus_cal_la_CPPFLAGS =			\
 	$(NULL)
 
 libegdbus_cal_la_SOURCES =			\
-	e-gdbus-cal.h				\
-	e-gdbus-cal.c				\
 	e-gdbus-cal-view.h			\
 	e-gdbus-cal-view.c
 
diff --git a/docs/reference/calendar/libedata-cal/libedata-cal-sections.txt b/docs/reference/calendar/libedata-cal/libedata-cal-sections.txt
index 00361e1..02c4a32 100644
--- a/docs/reference/calendar/libedata-cal/libedata-cal-sections.txt
+++ b/docs/reference/calendar/libedata-cal/libedata-cal-sections.txt
@@ -47,8 +47,6 @@ e_cal_backend_notify_component_created
 e_cal_backend_notify_component_modified
 e_cal_backend_notify_component_removed
 e_cal_backend_notify_error
-e_cal_backend_notify_readonly
-e_cal_backend_notify_online
 e_cal_backend_notify_property_changed
 e_cal_backend_empty_cache
 e_cal_backend_set_is_removed
@@ -59,6 +57,8 @@ e_cal_backend_is_opening
 e_cal_backend_set_backend_property
 e_cal_backend_foreach_view
 e_cal_backend_notify_opened
+e_cal_backend_notify_readonly
+e_cal_backend_notify_online
 e_cal_backend_respond_opened
 <SUBSECTION Standard>
 E_CAL_BACKEND
@@ -263,13 +263,13 @@ e_data_cal_respond_get_view
 e_data_cal_respond_get_timezone
 e_data_cal_respond_add_timezone
 e_data_cal_report_error
-e_data_cal_report_readonly
-e_data_cal_report_online
 e_data_cal_report_free_busy_data
 e_data_cal_report_backend_property_changed
 <SUBSECTION Deprecated>
 e_data_cal_respond_set_backend_property
 e_data_cal_report_opened
+e_data_cal_report_readonly
+e_data_cal_report_online
 <SUBSECTION Standard>
 E_DATA_CAL
 E_IS_DATA_CAL



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